Define states once.
Render it anywhere.
A state machine built for performance
States as pure, serializable data you can plug into anything that renders.
Inspired by
XState
and
Zag.
npm i @dunky-dev/state-machine Why Dunky
- 🌎
Truly agnostic
No environment assumption at all — one step beyond Zag's headless idea. Compare →
- ⚡️
Fast at scale
~8× XState's throughput, flat-ish memory, surgical re-renders. See the benchmark →
- 🧠
Behavior, not render
A pure behavioral kernel — states, events, context. Runs on the DOM, React Native, or any JS runtime.
Fast machines
Few bytes of state, events and context per machine. A tiny
footprint can spin up thousands of them
Built for high density × high frequency.
// 🟡 pacman — eats until the ghost gets him
const pacman = machine({
initial: 'eating',
context: { x: 1, y: 1, dir: 'right', mouth: 'open' },
states: {
eating: { on: {
step: { actions: act($ => ({ x: $.event.x, y: $.event.y })) },
die: { target: 'dead' },
} },
dead: { on: { revive: { target: 'eating' } } },
},
}) // 👻 ghost — chases on each tick, stops on a catch
const ghost = machine({
initial: 'roaming',
context: { x: 11, y: 10, dir: 'up' },
states: {
roaming: { on: {
tick: { actions: act($ => chase($.context, $.event)) },
stop: { target: 'stopped' },
} },
stopped: { on: { reset: { target: 'roaming' } } },
},
}) // 🍒 board — dots, cherry, score
const board = machine({
initial: 'playing',
context: { dots, cherry, score: 0 },
states: {
playing: { on: {
eat: { actions: act($ => scoreAt($.context, $.event)) },
caught: { target: 'caught' },
} },
caught: { on: { reset: { target: 'playing' } } },
},
}) // ⏱️ a clock machine self-drives via `after` — no external loop
const clock = machine({
initial: 'running',
states: { running: { after: { 200: { target: 'running' } } } },
})
// 🎲 compose the four; sync() fans each beat to all regions in order
const game = compose({ clock, pacman, ghost, board })
game.sync(() => {
const { x, y } = step(pacman.context)
pacman.send({ type: 'step', x, y })
board.send({ type: 'eat', x, y })
ghost.send({ type: 'tick', targetX: x, targetY: y })
})
game.start()
One machine.
Rendered on any JS runner.
The machine is a pure kernel with no environment assumptions. Plug it into any JS UI. If JS runs it, the machine drives it.
| machine | state | context |
|---|---|---|
| pacman | … | |
| ghost | … | |
| board | … |