Skip to content

Today I learned

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.

Share LinkedIn Post on X

Related notes

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.