Skip to content

Today I learned / Web development

Web development notes

Vue, Nuxt, TypeScript and the browser platform: fixes, configuration details and patterns found while building real web products.

How do I build an ECS where mechanics can be swapped while the game runs?

Keep all state in components as plain data and all code in modules that own no state. A snapshot is then just the stores, and swapping a mechanic is just swapping the systems that read them.

ts
world.add(e, 'Napping', {}) // state: plain data, saved in every snapshot

export default defineModule({
  id: 'siesta', version: '1.1.0',
  components: { Napping: { version: 2, migrate: { 1: old => ({ ...old, since: 0 }) } } },
  install(ctx) { /* one-time world changes */ },
  setup(ctx) { ctx.extend(ACTIONS_REGISTRY, 'siesta_nap', nap) }, // runs on every attach: never writes the world
  systems: [{ id: 'wake', every: 10, run(ctx) { /* query, then mutate */ } }],
})

In Glimtide every mechanic, even hunger, is a module installed into the live world between two ticks. The rules that make it work: no state in closures (an upgrade drops it), randomness only from the world's seeded RNG and time only from ticks, or a trial run on a snapshot can't be compared. More in the Glimtide write-up and the ECS FAQ.

How to make a narrated explainer video for a side project from one prompt

My tool pages explained everything in text, and I wasn't going to record and edit a video for each of them by hand.

I used Animator, a Python CLI that turns one prompt into a hand-drawn whiteboard video with narration:

bash
pip install -r requirements.txt   # plus FFmpeg on PATH and GEMINI_API_KEY in .env
python -m animator --prompt "How tabs-broadcast lets browser tabs talk to each other" --scenes 4 -o tabs_broadcast.mp4

Gemini writes the storyboard, draws each scene, voices it and finds every icon in the frame. A local CPU engine then draws each icon while its sentence is being spoken. A 4–5 scene video takes about a minute.

That's how I got the videos on tabs-broadcast, XPLOIT Game UI, Steam AI Disclosure and Contract Red-Flag Scanner: one command each, uploaded to YouTube as is.

If a caption shows up before it's spoken, rerun with --save-storyboard and fix the beat in scene_XX.regions.json. The art style and the script tone are plain-text prompts in animator/prompts/, so you can change them without touching code.

Asking Claude to "add feature X" gets you X.

The loop I use on ravy.pro:

  1. Keep a CLAUDE.md in the repo: the architecture, plus the rules that are easy to break (where data lives, what must stay prerendered, which analytics events exist).
  2. Ask for ideas against a goal, not for a feature:
text
Read CLAUDE.md and the site. My goal: companies hiring a CTO should find me.
Propose 10 features ranked by impact vs. effort.
For each: what it is, why it helps, which files it touches.
  1. Pick one and let it build the whole thing: code, tests, lint, a production build, then screenshots to check the layout.

This feed is item 10 on that list. The ⌘K search and the press kits for my games came from the same list.

What made it work: every rule goes into CLAUDE.md the day it bites. Claude reads that file at the start of every session, so the same mistake rarely comes back.

Docs: How Claude remembers your project

Newsletter

Occasional notes on engineering, game tech, and new tools — no spam, unsubscribe anytime.

Ravy

Engineering manager, founder, and software developer building web platforms, game systems, real-time services, and automation tools. 15 years of shipped work — currently at Gaijin.net.

Get in Touch

Building an MVP, shipping a game feature, or automating a team workflow? Open source or paid — let's talk.

Contact Me
© 2020-2026 XPLOIT FZE. All trademarks, names and logos belong to their respective copyright holders.