The openturn reducer is the function the engine builds from your game definition. For every dispatched event it picks the matching transition branch, runs the resolver, and commits the result. There is no side-effect pipeline and no preparer/guard/commit split. Just pure branches, chosen strictly.Documentation Index
Fetch the complete documentation index at: https://openturn.io/docs/llms.txt
Use this file to discover all available pages before exploring further.
Labelled resolvers
A singlefrom/event pair can declare many branches with different outcomes. Give each a label so inspector and the validation report can tell them apart:
Shared branch work
If two branches do the same work to decide whether they match, extract it into a helper and call it from both. The resolver stays pure; the helper stays in your module.Queued internal events
Some flows want to run follow-up logic without asking a player. Example: after a move ends a round, automatically kick off the next round’s setup. Returnenqueue: [{ kind, payload }] from your resolver:
kind: "internal", so inspector still show the full chain.
Internal events are deterministic and pure. You cannot call fetch, trigger animations, or read the wall clock inside them. If you need the current time, read it from context.now, which is the match’s recorded time (fixed during replay).
When not to queue
If a follow-up is mechanical and has no meaningful intermediate state, just compute it inline and return the finalG. Queue only when:
- The intermediate state is inspectable (a player should see it before the chain resolves).
- The flow is naturally recursive or multi-step (draw card → reveal → resolve effect).
- A hosted client needs to observe each step for animation.
What to read next
- Turns, phases, and control explains how
activePlayersand turn increments interact. - How-to: debug with inspector shows the inspector UI that renders every resolver branch and internal event.