Event Sheets¶
Event Sheets are Sektor's primary gameplay language. They are not a simplified macro editor: a complete game is authorable with Event Sheets alone, and Studio, Play mode, automated tests, and AI all use the same versioned event document, the same operation registry, and the same runtime evaluator.
The model is the familiar one from Construct: conditions on the left pick objects, actions on the right change them. Underneath, execution is deterministic, every parameter is a typed expression, and every reference is a stable ID, so renaming an object or variable never breaks logic.
How execution works¶
- Events evaluate top to bottom every simulation tick. Conditions evaluate in order; actions execute in order.
- AND events progressively filter a selection. If a condition picks 12 enemies and the next condition passes for 3 of them, the actions run on those 3.
- OR events merge the branches that succeeded.
- Triggers (marked with an arrow) are edge driven. They fire once per occurrence, like a key press or a collision, rather than polling true every tick.
- A sub-event inherits its parent's picked objects after the parent's actions. Sibling sub-events each start from the same parent result; picks changed in one sibling never leak into the next.
- An action targeting a type with no prior condition applies to all instances of that type. After a filtering condition, it applies only to the picked ones.
Reading an event
Conditions: Enemy has component navigation_agent AND distance to Hero is below 4
Actions: set Enemy animation parameter Attacking to true, play audio sword_swing
Only the enemies that passed both conditions attack. Everyone else is untouched.
Flow control¶
| Block | Behavior |
|---|---|
Repeat n |
Runs its actions and sub-events n times with a loop index expression |
For (range) |
Inclusive numeric range with the index available as an expression |
For Each object |
One iteration per picked instance, in stable deterministic order |
While |
Re-evaluates its condition live each iteration |
Stop Loop |
Stops the innermost loop, finishes the current branch, suppresses later iterations |
Else / else-if chains |
Runs when the previous sibling failed; resets to the parent's picks |
Trigger Once While True |
Fires on the rising edge, re-arms when the whole event goes false, survives saves |
Loops carry safety budgets (10,000 direct iterations, 100,000 total) so a runaway While can never hang a shipped game.
Time and scheduling¶
Every X Secondsfires on the fixed simulation clock, not wall time.- Named timers support start, pause, resume, stop, completion triggers, and state queries.
Waitsuspends the current action chain and its sub-events without blocking anything else. Continuations resume at later fixed ticks in stable order, survive player saves, and restore exactly.- Async functions are explicit fire-and-continue calls that may contain Wait.
All of it participates in the authoritative state hash, so replays and saves reproduce timing exactly.
Functions and includes¶
Functions have typed parameters, locals, return values, a 32-frame recursion guard, and optional copy-picked execution. Calls create isolated frames; Return stops the rest of the frame.
Reusable Event Sheet includes landed recently: the Project Settings Primary Event Sheet is the single execution root, and an include evaluates another sheet at its exact position with the current picks. Shared sheets in a diamond (two sheets include the same library sheet) still run once per tick. Cycles, self-includes, and duplicates are rejected when you author them, not at runtime.
Structure a real project
Keep Primary as a thin table of contents that includes Player, Enemies, UI, and Audio sheets. Each stays small, and shared logic lives in one place.
Variables, expressions, and randomness¶
Typed variables exist at global, scene, and local scope; locals reset on entry unless marked static, and constants cannot be assigned. Every parameter field is a typed expression with autocomplete and inline errors: literals, variables, object and component properties, arithmetic, comparisons, conditionals, vectors, and built-in calls.
Deterministic random uses named streams:
{"source":"expression","kind":"random","stream":"gameplay.loot","minimum":1,"maximum":100,"integer":true}
Streams are seeded by the project seed. The same project, seed, and inputs produce the same rolls in Studio Play and in a packaged game, which is what makes replays and save files trustworthy.
Custom events¶
Sheets can send custom events into a bounded queue: deferred or immediate, with a source, an optional target, and typed event data. Receiving triggers dispatch once per occurrence with the sender and data picked. That is the clean way to decouple systems: "QuestCompleted" fires once; the UI sheet and the audio sheet each react on their own.
Worked example: a scoring pickup¶
A complete, real pattern using systems from this page plus Physics, Runtime UI, and Audio:
- Variables: global
Score(number, starts at 0). - Event 1, trigger
physics.on_trigger_enterbetweenHeroandCoin:audio.playon the pickedCoin(its Audio Source has a chime clip)- add
1toScore - destroy the picked
Coin
- Event 2, on
Scorechanged: set the HUD text widget to"Coins: " & Score. - Event 3, condition
Score ≥ 10plusTrigger Once While True:- show the "Level complete" panel and pause the game.
Because triggers pick both participants, only the coin the hero actually touched plays its sound and dies. The other forty coins in the scene are never considered.
Automate it¶
An AI collaborator authors sheets through the same registry you use, and can prove its changes are safe:
{"op":"inspect.capabilities"}
{"op":"event.else.create","sheetId":3,"afterEventId":41}
{"op":"runtime.animation.parameter.set","id":1,"name":"Moving","type":"boolean","value":true}
During Play, events.runtime.randomStreams exposes each stream's state and draw count, and runtime.stateHash fingerprints the complete simulation, so an AI can verify a change did not break determinism instead of guessing from a screenshot.