-
Notifications
You must be signed in to change notification settings - Fork 0
event stream
The layer between a game and the tokenizer. Game-agnostic by design — any game that can emit structured events can feed the pipeline.
For the philosophical foundation — why events are the unit of meaning, collision-defined semantics, and the Wittgensteinian framing — see Theory.
A game produces raw state each tick. The event stream layer decides what happened — it converts state transitions into discrete, named events.
The transformer never sees the game. It sees events. Game-agnosticism lives here.
Any game must expose:
reset() → initial state
step(action) → next state, list[Event], done flag
legal_actions(state) → list[Action]
An Event is a structured record:
Event {
type: str # e.g. "move", "collect", "die", "spawn"
entity: str # e.g. "player", "enemy.0", "coin.3"
payload: dict # type-specific data, e.g. {pos: (3,4), dir: "R"}
tick: int # global timestep
}
Events are the atoms. The tokenizer decides how to encode them.
Two extremes:
Maximalist: Every state change is an event. Player moved? Event. Enemy moved? Event. Score changed? Event. Timer decremented? Event.
- Pro: Nothing is lost. The event log is a perfect reconstruction of gameplay.
- Con: Noisy. Most ticks produce many events, most of which are boring (enemy pathfinding steps, timers ticking).
Minimalist: Only "meaningful" transitions. Collisions, deaths, collections, phase changes.
- Pro: Clean signal. Every event matters.
- Con: Who decides what's meaningful? This bakes in assumptions about what the model should learn.
Proposed approach: Emit everything, but tag events with a salience level:
TICK = 0 # always happens, marks time
MOVEMENT = 1 # entity changed position
COLLISION = 2 # two entities occupy the same cell
RULE_EFFECT = 3 # game rule triggered (score change, death, buff)
PHASE = 4 # game phase transition (buff activated, level complete)
The tokenizer can then filter by salience threshold — a hyperparameter. High threshold = only collisions and rule effects. Low threshold = full replay.
How do we refer to entities across events?
- By type: "enemy" — sufficient if there's only one, breaks with multiples
- By index: "enemy.0", "enemy.1" — stable but arbitrary
- By position: "enemy@3,4" — unambiguous but changes every tick
- By role: first assigned identity persists — "the enemy that spawned top-left"
For now: type + index, assigned at spawn time. Simple, stable, game-agnostic.
Events within a single tick are simultaneous. Do we:
- Flatten: Emit them in a fixed order (movements, then collisions, then effects). Implies false sequentiality.
-
Bundle: Group them with a tick delimiter.
[TICK] [event] [event] [event] [TICK]. Preserves simultaneity. -
Causal chain: Order by causation.
move → collision → death. Implies causal structure.
Option 3 is the most informative but requires the game to know its own causal graph. Option 2 is safe and general. Start with bundled, then explore causal ordering as a refinement.
- Should the event stream carry negative events? ("player did NOT collide with wall this tick") Absence of tokens encodes this in the premise, but explicit negatives might help the model learn constraints faster.
- How do we handle continuous state in games that have it? (e.g., velocity in Pong) Discretize? Bucket? Ignore until collision?
- Should events include counterfactuals? ("player could have gone left but didn't") This is relevant for archetype detection — what you don't do defines your style.
This layer is essentially an event sourcing write model. The connection is nearly 1:1:
| Event Sourcing | Game Grammar |
|---|---|
| Event log | Token sequence |
| Projection function | Transformer's learned prediction |
| Snapshots | Periodic state snapshots in the sequence |
| Event schema | Vocabulary design |
The event log is the source of truth; any state can be reconstructed by replaying events. The token sequence is an event log. The transformer learns the projection function. Snapshots are snapshots. The vocabulary is the event schema.
See Theory for more on the philosophical foundations.
The salience levels relate to information-theoretic surprise — high-salience events carry more bits. A future refinement could compute salience dynamically from the model's own prediction confidence.