Kits
A kit is reviewed engine code that every game can use. It registers its vocabulary in a kit.json: the components an entity can have, the actions rules take, the events they hear, the functions expressions call, the passes that build worlds, the builders that make models and sounds from recipes, and the verbs and bots that play a game in its checks. A game never brings code of its own; when it needs something no kit offers, the Director files a KitRequest. Generated from each kit.json. A field marked * is required.
Actors kit.actors
Draws every entity whose Archetype names a model: the model is built once per recipe, placed between ticks so it moves smoothly, turned the way the body faces, posed from what the simulation says it is doing, and lit from what happens to it. Poses come first from the Archetype's poses component (rules: the first Expr that holds names the pose), then from defaults every rigged model reads the same way: dead, a blow's windup and strike, a dodge, a hurt, walking and running by gait, crouched, alert while its senses are sure of someone, idle. A model's emissive slots (a lens, embers) brighten through a blow's tell, flare when its working part is hit, pulse faster as its suspicion rises and go dark when it dies. A built station that lights up (light.changed from a station) gets a warm, unsteady light at its fire. The camera follows the player's body, and machines and threats near the player are kept clear of props by the stipple. Add it to every game with models.
Components what an Archetype's entities can do
poses- How the entity's model is posed and lit. Optional: without it the defaults apply.Fields:
rules,defaults,strideM,glowRest,variants
Sound: synthesized and imported kit.audio
Every sound a game makes, synthesized from recipes or decoded from the person's own files, and baked at load into 16-bit buffers that play on desktop and on the web (no live effects). Write Sound documents with one of four builders: synth.sfx for retro effects (sfxr's parameters; paste JSON from sfxr.me), synth.layered for machines, impacts, footsteps, gathers and clicks, synth.bed for seamless ambient loops such as surf and wind by day and a haunting drone by night, and sound.file for a sound the person imported (an Asset): prefer theirs where they gave one. Give each Sound a mix category (bed, machine, event, step, ui; a Score's stems play in music) and a levelDb relative to it; the bank measures every bake and sets its gain, so editing a recipe never changes the mix. Map events to sounds in an Archetype's cues (on: event id, cue: Sound id; on: alive loops while the entity lives; {field} placeholders such as snd.step_{ground} are filled from the event): they play at an entity the event names, or, when the event names the archetype in an arch field and no entity of it (platformer.collected, grid.moved), at the listener. Sounds of the game more than of one entity (a jump, a level won, a turn, a line of a story: platformer.jumped, grid.won, dialogue.line) go in the Style's audio.cues {on, cue}, heard at the listener; or play one with kit.core's playCue. Every cue a game can emit must name a Sound. The Style's audio.beds.scenes {when, bed} put a scene's bed in place of the day and night beds while its when holds (var.scene == 'lamp', platformer_level() == 'plevel.caves'), crossfading over fadeSec; a game with no clock hears its day bed.
Builders what Model, Sound and Sprite recipes name
sound.file- Plays a sound the person imported (an Asset: OGG Vorbis, WAV or MP3), decoded at load and baked as every Sound is: high-passed for its category, a one-shot's silence trimmed and its end faded, and gained to the mix sheet's level for its category plus the Sound's levelDb, so it sits in the mix beside the synthesized sounds however loud the file was. It loops when the Sound loops: the file should join its end to its start. A stereo file stays stereo. It plays no notes, so no Score stem is voiced by it.Fields:
asset*,vary synth.sfx- sfxr's retro effect, rendered exactly as sfxr.me renders it: one wave, an envelope, a pitch slide, vibrato, an arpeggio step, a duty sweep, repeat, a phaser and filters. Values are 0 to 1 (slides and offsets -1 to 1). A jsfxr JSON export (p_env_attack, p_base_freq, wave_type...) is accepted as it is. Good for pickups, blips, UI clicks, lasers and hits; variants mutate every value slightly.Fields:
waveType,envAttack,envSustain,envPunch,envDecay,baseFreq,freqLimit,freqRamp,freqDramp,vibStrength,vibSpeed,arpMod,arpSpeed,duty,dutyRamp,repeatSpeed,phaOffset,phaRamp,lpfFreq,lpfRamp,lpfResonance,hpfFreq,hpfRamp,soundVol,sampleRate,vary,seed synth.layered- A small flat graph for anything sfxr can't say: voices (tone, noise, impulses, struck modes, pluck, fm), each with its own envelope, filters and start time, summed through master filters, saturation, an echo and a room. Machines' hums and calls, a ring against a hit, footsteps per ground, gathering, UI clicks. With loop the recipe becomes a seamless loop (pitches snap to whole cycles).Fields:
seconds,rate,voices*,filters,drive,echo,reverb,vary,seed synth.bed- A seamless ambient loop from layers: surf, wind, hiss, drone, pad and ticks, each periodic by construction, so the loop never clicks. Stereo by default, the two sides drawing different noise. Make a night variant as a second Sound: less surf and wind, a drone and a pad under them. A Style's audio.beds names the day and night beds, and the audio view crossfades them by the hour.Fields:
seconds,rate,stereo,layers*,filters,echo,reverb,seed
State machine brains kit.brain_fsm
Gives an ai body a mind as a StateMachine document: states like patrol, notice, hunt, attack, search and return, with transitions on events (perception.noticed, perception.lost, melee.downed), on Expr guards (in_strike_range(self), beyond_tether(self)) and after a time. Each state's onEnter sets what the body does until the next state: brain_patrol walks its round, brain_hunt chases what it noticed around cliffs, brain_attack closes in and bites when the body is in reach and in front, brain_search goes to where it last sensed the body and looks round, brain_return walks home, brain_hold stands. A tether stops a chase too far from home (or from its round), and forgetSec is how long a search lasts.
Needs kit.move, kit.perception, kit.melee.
Components what an Archetype's entities can do
brain- An ai body run by a StateMachine document. The machine decides the behaviour (by the brain_* actions in its states' onEnter); these fields tune how each behaviour walks.Fields:
machine*,patrolPlaces,patrolLoopM,patrolPoints,patrolWaitMs,patrolGait,chaseGait,homePlace,tetherM,tether,forgetSec,strikeRangeM,strikeArcDeg,searchTurnDegPerSec
Actions what a rule does
brain_patrol- Walk the patrol round (patrolPlaces, or the loop round home) until the next state.
brain_hunt- Chase the body it is watching most closely: to the body while it senses it, else to where it last sensed it. Routed round cliffs and water.
brain_attack- Close in on the body it watches, keep facing it, and strike whenever it is in reach and in front.
brain_search- Go to where it last sensed the body, then turn slowly to look round.
brain_return- Walk home.
brain_hold- Stand still.Fields:
face
Events what rules hear
brain.changed- A brain's state machine changed state (a body snapping to alert, giving up). Tours await the runner's own latch, sm:<entity>:<state>.Fields:
entity,from,to brain.chase- A brain began chasing a body: its behaviour turned to hunt or attack (brain_hunt, brain_attack) with a body to go after. Latch chase:<entity>.Fields:
entity,target,distM,latch brain.chase_over- A chase ended: the brain's behaviour turned to anything but hunt or attack (it lost the body, gave up, went home), or the chaser was killed. caught is false when the body got away without ever being in strike range: an escape. Latch chase_over:<entity>.Fields:
entity,target,secs,closestM,caught,keptAwaySec,latch
Functions what expressions call
brain_state(e)→ string- The brain's current state id.
target_distance(e)→ number- Metres from the body to where it believes the body it watches is (a large number when it watches none).
in_strike_range(e)→ bool- True when the watched body is within strikeRangeM.
home_distance(e)→ number- Metres from the body to its home.
beyond_tether(e)→ bool- True when the body is further than tetherM from home, or with tether round from its patrol round.
forget_sec(e)→ number- The body's forgetSec: how long a search lasts.
World clock kit.clock
One world clock: game minutes that pass at a fixed rate per real second, with day and night. Use it whenever time of day matters: darkness for senses, work and crafting that cost minutes, hours skipped when the player is downed or sleeps. Walking never buys time; only work, crafting and explicit skips jump it. Expressions read game.hour (0 to 24, fractional), game.minute, game.day and nightfall().
Actions what a rule does
skip_time- Jump the world clock forward, as sleep, long work or being knocked out does. Nothing else moves while the minutes pass.Fields:
minutes* set_hour- Set the hour of day on the current day. For tours and boot options that need a given light; games should prefer skip_time, which never goes back.Fields:
hour*
Events what rules hear
clock.hour_changed- The hour of day turned over, by time passing or by a skip. Use it for things that happen at a given hour.Fields:
hour,day
Functions what expressions call
hour()→ number- Hour of day, 0 to 24 with fractions (13.5 is half past one). Same as game.hour.
minute()→ number- Minute of the hour, 0 to 59.
day()→ number- Day number since the game began (0 is the first day).
nightfall()→ number- How dark it is: 0 in full day, 1 in full night, easing through dusk and dawn. Senses read it to see less at night.
Core kit.core
The always-on kit every game has: stats and game variables from Stats documents, tuning knobs from Tuning documents, entities spawned from Archetype documents, the player spawned from the GameManifest, rule sets (on an event, where a condition holds, do actions; once, cooldowns and bounded each), state machines other kits run per entity, dialogue (a Dialogue document's lines shown one at a time, with choices the player picks), Timelines (steps in order over time: a cutscene, a boss's phases), scenes (the GameManifest's places, joined by doors, each kept as it was left), and the basic actions: spawn, despawn, set_var, add_var, set_stat, add_stat, emit, give, take, play_cue, show_message, start_dialogue, start_timeline, stop_timeline, set_state, face, travel and end_game. Use its rules for game logic that reacts to events: scoring, win and lose conditions, messages, spawning waves. Use a Dialogue for anything said: a conversation, or a whole story told in lines and choices, with its flags kept as variables. Use a Timeline for anything that waits: a cutscene, a boss that changes when hurt, a gate that opens and then lets a wave in. Effects and abilities are here too, for every mover in every game: an Effect document is a status a body is under for a while (slowed, poisoned, shielded, hasted, stunned, invulnerable), put on with apply_effect and read by every kit that moves or fights; an Ability document is something a body does on demand with a cooldown and a cost, carried in the abilities component and used by the player's input action, by itself (auto) or by use_ability from a state machine or rule.
Components what an Archetype's entities can do
abilities- The body has abilities: Ability documents, each with its cooldown, cost and what it does. The player uses one with its action; any other body uses one by itself (the Ability's auto) or when its state machine or a rule asks (use_ability). Give it to any mover: a hero's dash and swipe, a turret's volley, a boss's slam.Fields:
abilities* door- A way into another scene (the GameManifest's scenes): a cave mouth, a cellar hatch, a house's door. A usable (kit.harvest) with a door is gone through with the use key or a click: the player arrives at the start of the next tick, and the scene left stays as it was left. Put a door back on the other side.Fields:
to*,at
Actions what a rule does
spawn- Creates entities from an archetype. They get stable ids from the archetype (arch.coin makes coin.0, coin.1...) unless an id is given, and appear at an entity (self, target, player, an id) or a named place.Fields:
arch*,id,at,count despawn- Removes an entity from the game.Fields:
entity set_var- Sets a game variable.Fields:
var*,value* add_var- Adds to a numeric game variable.Fields:
var*,by set_stat- Sets an entity's stat, clamped to the stat's min and max and the entity's own max.Fields:
entity,stat*,value* add_stat- Adds to an entity's stat, clamped to the stat's min and max and the entity's own max.Fields:
entity,stat*,by* emit- Sends an event, which rules and kits can react to.Fields:
event*,fields give- Puts items into an entity's inventory (needs an inventory kit).Fields:
item*,count,to take- Takes items out of an entity's inventory (needs an inventory kit).Fields:
item*,count,from play_cue- Plays a sound cue, at an entity when one is given.Fields:
cue*,at show_message- Shows a line of text on the message line.Fields:
text*,secs start_dialogue- Starts a Dialogue on its start line, or on the line given, in place of any dialogue running. A visual novel starts its story on game.start; a game starts a conversation when the player meets someone.Fields:
dialogue*,line end_game- Ends the game with an outcome.Fields:
outcome*,reason start_timeline- Starts a Timeline from its first step, with self the entity named here (its steps' self) and target the caller's target. A Timeline already running for that self, or a once Timeline that ran, is not started again.Fields:
timeline*,entity stop_timeline- Stops a running Timeline where it is: no step after the one it is on is done (unlike a skip, which does them at once). timeline.done goes out with stopped true.Fields:
timeline*,entity set_state- Puts an entity's state machine (kit.brain_fsm's brain) into a state, as a transition into it would: the states it leaves do their onExit, the ones it enters their onEnter. A boss's next phase, a guard told to stand still for a cutscene.Fields:
entity,state* face- Turns an entity at once to face another entity or a place.Fields:
entity,toward* apply_effect- Puts an Effect on a body (a slow on what an ability hit, a shield on self, a haste on the player): it starts, or renews as its stacking says. Whoever runs the action (self) is its source.Fields:
entity,effect*,stacks remove_effect- Takes an Effect off a body (a cure, a dispel), or every Effect on it when none is named. Each one taken off sends effect.ended with why removed.Fields:
entity,effect use_ability- Asks a body to use one of its Abilities now, if it can (alive, able to act, off cooldown, its when holding, its cost paid): how a state machine's state or a rule uses an ability. A refusal sends ability.refused with why.Fields:
entity,ability*,at travel- Moves the player to another scene (the GameManifest's scenes) at the start of the next tick, as a door does: a cutscene's end, a fall through the floor. The scene left stays as it was left.Fields:
scene*,at
Events what rules hear
game.start- Play began: the first tick of a new game, or the tick the title was left.
game.end- The game ended.Fields:
outcome,reason pointer.clicked- The player clicked the world (or tapped it on a phone), in a game whose InputMap pointer has a click: target is what the click was on, x and z where on the ground. For a game of choices on the map (select a tile, place a tower, pick a card off the table), rules do the rest; walk and use also walk there.Fields:
target,x,z entity.spawned- An entity was created.Fields:
self,arch entity.despawned- An entity was removed. It is gone by the time rules see this, so self is empty.Fields:
self,arch cue.play- A sound cue should play, at an entity when one is named.Fields:
cue,self ui.message- A line for the message line.Fields:
text,secs dialogue.line- A line of a Dialogue came on screen. A line passed over (its when did not hold) is not shown and sends nothing.Fields:
dialogue,line,speaker dialogue.chose- The player picked a choice of a Dialogue.Fields:
dialogue,line,choice dialogue.ended- A Dialogue ran out of lines: past a line with end, or past its last line.Fields:
dialogue,line timeline.started- A Timeline started. Latch timeline.started:<id>.Fields:
timeline,self,latch timeline.done- A Timeline ended: past its last step, skipped by the player, or stopped by stop_timeline. Latch timeline.done:<id>.Fields:
timeline,self,skipped,stopped,latch effect.started- An Effect was put on a body that didn't have it. Views and cues show it (a stunned body's stars, a shield's hum); an Archetype's cues on effect.started play at the body. Latch effect:<effect>.Fields:
self,source,effect,stacks,latch effect.renewed- An Effect already on a body was put on again: its time started over or grew, or it gained a stack, as its stacking says. Latch renewed:<effect>.Fields:
self,source,effect,stacks,latch effect.ended- An Effect came off a body: its time ran out (why expired) or something took it off (why removed). Latch ended:<effect>.Fields:
self,source,effect,why,latch ability.used- A body used an Ability: its cost was paid, its cooldown began and its actions ran. Map it to the ability's sound on the body's cues. Latch used:<ability>.Fields:
self,ability,target,latch ability.refused- A press or a use_ability asked for an Ability that couldn't be used: why is dead, cannot_act (an effect stops the body acting), cooldown, when (its condition didn't hold) or cost (too little of the stat). A HUD or a cue can say so.Fields:
self,ability,why ability.ready- An Ability's cooldown ended: the body can use it again. Latch ready:<ability>.Fields:
self,ability,latch scene.entered- The player came into a scene by a door or travel. first is true the first time: a rule on it where event.first spawns what lives there. Latch scene:<id>.Fields:
scene,from,door,first,latch scene.left- The player left a scene: what is in it waits there as it was.Fields:
scene,to
Functions what expressions call
count(tag)→ number- How many live entities have a tag.
dist(a, b)→ number- Distance between two entities in world units (0 when either is missing).
outcome()→ string- How the game ended: win, lose or quit, as end_game said; "" while it runs. A screen shows a won game with when: outcome() == 'win'.
roll(stream)→ number- The next number in [0, 1) from a named random stream, for chances: roll('loot') < 0.25. Each stream is its own sequence, seeded by the game's seed and the name, and saved.
dialogue_line()→ string- The id of the line the running Dialogue is on, or an empty string when none runs. A playtest asserts where a story stands with it; a screen shows the story's box with when: dialogue_line() != ''.
dialogue_speaker()→ string- The speaker id of the line on screen (an earlier line while the player steps back to reread), or an empty string for narration or no line. A screen hides the name plate with when: dialogue_speaker() != ''.
dialogue_choosing()→ bool- True while the line on screen is whole and offers choices, so the player must pick one to go on. A screen shows its choice list with when: dialogue_choosing().
dialogue_back()→ number- How many lines back the player has stepped to reread (0 on the current line). A screen marks an earlier line with when: dialogue_back() > 0.
cutscene()→ bool- True while a cutscene Timeline runs and the player has no control. A HUD hides its hints with when: not cutscene().
timeline_running(timeline)→ bool- True while the Timeline runs (for any self).
has_effect(e, effect)→ bool- True while the Effect is on the body: has_effect(self, 'effect.shield').
effect_stacks(e, effect)→ number- How many stacks of the Effect the body has: 0 when it isn't on.
effect_secs(e, effect)→ number- Seconds the Effect has left on the body: 0 when it isn't on, -1 while it lasts until taken off. A HUD bar's value.
can_act(e)→ bool- False while an Effect on the body stops it acting (a stun, a silence).
can_move(e)→ bool- False while an Effect on the body holds it still (a stun, a root).
ability_ready(e, ability)→ bool- True when the body's Ability is off cooldown (its when and cost may still refuse it). A HUD greys a button with it.
cooldown_secs(e, ability)→ number- Seconds until the body's Ability is off cooldown: 0 when ready.
scene()→ string- The scene the player is in (an id from the GameManifest's scenes), or an empty string in a game played in one place. A Style's bed plays per place with when: scene() == 'den'.
visited(scene)→ bool- True once the player has been in the scene.
Tour verbs what a Playtest's steps say
seed N- Use seed N for the next boot.
boot [title|game]- Start a new game, on the title or straight into play.
press ACTION- Press an input action for one tick.
hold ACTION- Hold an input action down until released.
release ACTION- Let go of a held action.
move X Z- Hold a world-space move intent (length at most 1); move 0 0 stops.
point at WHAT | point off- Hold the pointer (the mouse) on WHAT, followed as it moves: an entity id, prop:<kind> (the nearest standing prop of that kind, then that one) or place:<name>. A game whose InputMap pointer aims turns the player to it; off lets go.
aim DEG- Hold the pointer DEG degrees round the player as facings go (0 is +X, 90 is -Z), 6 m out: a game that aims with the pointer turns the player there, and its fire action shoots there.
click [WHAT]- Click once on WHAT (as point at takes it), or where the pointer is held, and keep the pointer there. A game whose InputMap pointer click is walk or use walks the player there (await arrived), and use then uses it; every click sends pointer.clicked. Fails when WHAT is not there.
wait SECS- Let the game run for SECS game seconds.
await WHAT SECS- Run until WHAT holds; fail if it doesn't within SECS game seconds. WHAT is control, tick>=N, event:ID or a latch a kit reports (noticed:player).
until WHAT SECS- Run until WHAT holds or SECS pass; never fails.
assert same-state | assert WHAT- Fail unless the state matches the one saved in the slot just loaded, or WHAT holds now.
shot NAME [with A,B]- Capture a frame named NAME; with subjects, fail unless they are in frame.
save SLOT- Save the game to a slot.
load SLOT- Load the game saved in a slot.
quit [title]- quit title goes back to the title; quit ends the tour.
hour H- Set the clock to hour H (a clock kit's, or the variable hour); logged.
repeat N { A; B }- Run the commands in braces N times.
echo TEXT- Print a line in the tour log.
read LINE- Advance the running Dialogue, a press a tick, until LINE is on screen. Fails when a choice stands in the way (it names the choices on offer), when the dialogue ends first, or when none runs.
choose CHOICE- Pick the choice whose link id is CHOICE, as soon as the line offering it is whole (pressing advance to show its words until then). Fails when the line on screen does not offer that choice now.
read_all- Read the running Dialogue to its end, a press a tick, taking the first choice on offer whenever one stands: how the seek bot gets through a conversation, so write the choice that gets on with things first. Fails when none starts within 2 s, or when it runs on past 256 lines (a loop of choices).
Bots what plays a Playtest
monkey- Plays every game dumbly, to reach states no tour does: presses the game's own actions (its InputMap's ids, and the choices a kit's screen sends, like make:<recipe>), each as likely as the next, holding each for 4 to 30 ticks, and walks in a direction that changes every 30 to 120 ticks; when the game's clicks do something (its InputMap's pointer click), half its walks are a click instead, on a thing near the player or the ground there. Seeded from the game's seed (bots/monkey/n), so a run replays. Never done: it plays until the run's ticks pass or the game ends. With runs and the engine's invariants it is the fuzz.
seek- Plays toward a Playtest's goals, in order, by the obvious route and with a person's reaction time (8 to 15 ticks before each step) and fumbles (a wrong way for a few ticks, about 5% of the time): reach:<place>, near:<archetype id>, take:<prop kind>, have:<item id>, make:<recipe id>, use:<item id> (come by one if none is carried, then use it as the carry app does: eat it, drink it), talk:<archetype id> (walk up to the nearest of them, use it, and read its Dialogue to the end, taking the first choice on offer; talk alone picks the nearest usable that has a Dialogue), fight, win. A goal may come more than once (talk to the giver, fetch, talk to the giver again). Built from kits' tour verbs (goto, use, talk, read_all, make, fight) and the ways kits know to come by an item. Done when every goal is met, or stuck when one fails three plans over; reports each goal met, unmet or failed, and why.
seek_click- The seek bot played by a person with only a mouse or a finger, for a point-and-click game (its InputMap's pointer click use, or walk for goals that only walk): each walk is a click on the ground (click_to), and each walk up to something with its use one click on it (click_use): a person to talk to, a prop to take. The Screens a person clicks send the rest as they are (a talk's lines and choices, make, use_item). A goal only a key can reach (fight, a use with nothing clicked) fails, saying so: a click-only game whose Playtest it passes can be played without a keyboard.
Crafting kit.crafting
Making things from Recipe documents: by hand anywhere, or at a station (an archetype such as a campfire or a bench that must stand within reach). A recipe consumes its inputs, needs a carried tool of a verb and hardness if it names one, passes its world minutes, and either gives its outputs or builds an archetype on the ground in front of the maker (a campfire). A built station can be a warm light (light.changed) and, tagged respawn, the place a downed player wakes. The make screen and tours send the make action as an input press make:<recipe id>, so making replays like any other input.
Needs kit.inventory, kit.move.
Components what an Archetype's entities can do
crafter- The body can make recipes (the player).Fields:
makeAction,stationReachM,buildAheadM station- A built thing that is a place to make things and may be a light: a campfire, a bench. Tag its archetype respawn to make it where a downed player wakes.Fields:
warm,lightRadiusM
Actions what a rule does
make_recipe- Make a recipe now, as the make screen does: checks the station, inputs, tool and room, then consumes, passes the minutes and gives or builds.Fields:
entity,recipe*
Events what rules hear
crafting.made- A recipe was made. Latch made:<recipe>.Fields:
entity,recipe,latch crafting.built- A recipe placed an archetype in the world (a campfire). Latch built:<arch>.Fields:
entity,recipe,built,arch,latch crafting.refused- A recipe could not be made: why is unknown, no_station, missing, no_tool, no_room or full.Fields:
entity,recipe,why
Functions what expressions call
can_make(e, recipe)→ bool- True when the body could make the recipe right now.
make_why(e, recipe)→ string- Why the body can't make the recipe now (no_station, missing, no_tool, no_room, full, unknown), or an empty string when it can. The make screen shows it.
Tour verbs what a Playtest's steps say
make <recipe id>- Press make:<recipe> for the player, as the make screen would.
Grid world kit.grid
A turn-based world of square cells for puzzle games (Sokoban-likes). Each cell has three layers (floor, object, overlay) and holds at most one object per layer; an object is an archetype with a grid_object component, and its tags are what rules and win conditions can name. The avatar is an object too (grid_object avatar true). One input press is one turn: up, down, left and right mark the avatar to move, wait passes a turn, undo steps back one turn, restart goes back to the level's start, next goes on from a won level, and level:<id> jumps to a level. An object moves when the cell it moves into is free on its layer; what happens when it bumps into something is kit.grid_rules' job. Levels are Level documents, played in order. Ticks between turns only animate.
Components what an Archetype's entities can do
grid_object- The archetype is a kind of object on the grid. Legends place it by archetype id; rules and win conditions name it by id or by its tags.Fields:
layer,color,avatar
Events what rules hear
grid.level- A level began (or began again, after restart or a load of another level). Latch level:<id>.Fields:
level,index,latch grid.turn- A turn changed the grid. Latch turn:<n>; grid.moved follows for every kind of object that moved.Fields:
level,turn,input,latch grid.moved- Objects of one kind moved in the turn just taken: once a turn for each kind that moved, the avatar's included, after grid.turn. An Archetype's cues on it play when its kind moves (a crate's scrape when it is pushed). Latch moved:<arch>.Fields:
level,arch,latch grid.blocked- A press changed nothing (the avatar walked into a wall): no turn was taken.Fields:
level,input grid.won- The turn won the level. Latch won and won:<level>.Fields:
level,turn,moves,latch grid.undo- The last turn was taken back.Fields:
level,turn grid.complete- The last level was won and the player went on: every level is solved. The game ends with a win. Latch complete.Fields:
latch
Functions what expressions call
grid_turn()→ number- Turns taken in the current level.
grid_won()→ bool- True once the current level is won.
grid_level()→ string- The current Level's id.
grid_count(what)→ number- How many objects of an archetype id, or with a tag, are on the grid now.
grid_solved(level)→ bool- True when the Level has been won in this game.
Tour verbs what a Playtest's steps say
moves <u d l r w...>- Press the moves in order, one turn per press, like udlrw or rrdl. Fails at a press the game refuses (a won or finished level).
witness [level id]- Press the level's witness (the shortest solution bake stored); the current level when none is named. Fails when the level has no witness.
level <level id>- Press level:<id>, as a level select screen would, and start that level.
Grid rules kit.grid_rules
PuzzleScript-style rewrite rules and win conditions for kit.grid, written as GridRules documents: pushing, pulling, sliding, falling, keys and doors, things that change when they land on something. A rule matches a row of cells along a direction (the avatar moving forward into a crate) and puts what the cells hold afterwards (the crate moving forward too). Rules run in list order, each until it changes nothing, before movement; late rules run after it; a rule that would run forever is stopped at the GridRules passLimit and the stop reported. Win conditions (all crates on targets, no gems left, some key on a door) decide when a level is won. The core runs the same rules in its solver, so every level is proven solvable at bake.
Needs kit.grid.
Events what rules hear
grid.rule_limit- A rule was still changing things after passLimit passes in one turn and was stopped there. Latch rule_limit:<rule>.Fields:
rules,rule,latch
Harvest kit.harvest
The use key works the nearest thing in front of the body: a world prop the Biome gives a take rule (a fallen branch, a rock pile, a boulder), a pile on the ground (dropped loot), or a usable entity (a person to talk to, a sign to read, a lever). A prop is worked with the held tool, bare hands or another carried tool whose verb matches the take's verb and whose hardness is enough; each take costs a moment of work and some world minutes, works the prop down one stage and yields its items. Using a usable starts its Dialogue, if it names one, and sends harvest.used for rules to answer. While a Dialogue runs the key is the conversation's: it works nothing, and the body that talks stands still. What the highlight shows and what the key does come from one function (harvest_target), so the mark never promises what the key won't do.
Needs kit.inventory, kit.move.
Components what an Archetype's entities can do
harvester- The body can work props and take piles with the use action.Fields:
useAction,reachM,arcDeg,workMs,handVerb,handHardness usable- Something the use key works when a body stands at it and faces it: a person to talk to, a sign to read, a lever, a door. Using it starts its Dialogue if it names one (the conversation's lines can read the game's variables, so one person says what fits the quest so far) and sends harvest.used, which rules answer (open a gate, hand over an item). One with kit.core's door takes the player through it to another scene. It is used at once: no work, no world minutes. A usable that walks (driver ai) turns to face whoever used it. The reach is the user's harvester reach plus the usable's own body radius.Fields:
verb,dialogue
Actions what a rule does
use_in_front- Work the thing in front of a body now, as its use key would.Fields:
entity
Events what rules hear
harvest.started- A body began a take.Fields:
entity,target,kind harvest.taken- A take finished: a prop was worked down a stage (gone when its last stage was taken), or a pile's items were taken. Latch taken:<prop kind> for a prop, taken:<item> for each item from a pile.Fields:
entity,target,kind,item,count,gone,latch harvest.used- A body used a usable (talked to a person, read a sign, pulled a lever). Its Dialogue, if it names one, starts in the same tick. Latch used:<arch>.Fields:
entity,target,arch,verb,latch harvest.refused- The use key had nothing it could do: why is too_hard, no_tool, full or nothing.Fields:
entity,target,why
Functions what expressions call
use_state(e)→ string- What the use key would do now: workable, other_tool (a carried tool would, and use takes it out), too_hard, no_tool, full, usable (a usable is in front: use_verb says what), or an empty string with nothing in reach or while a Dialogue runs. The highlight reads this.
use_target(e)→ string- The id of the prop, pile or usable the use key would work, or an empty string.
use_verb(e)→ string- The verb of the usable the use key would use now (talk, read), or an empty string when what is in front is not a usable. A hint shows use_verb(self) when use_state(self) == 'usable'.
working(e)→ bool- True while the body is busy with a take.
Tour verbs what a Playtest's steps say
use- Press the player's use key once and wait until the take it started is done (or it is refused). It works a usable too.
talk [ARCH]- Face the usable in reach (the nearest of archetype ARCH when given: someone the player has walked up to), press use, and wait a tick: its Dialogue is on screen then. Fails when there is no such usable in reach. read, choose and read_all go on from there.
click_use prop:<kind> | click_use <arch id>- Click something the use key works, once, as a person does in a point-and-click game (its InputMap's pointer click use), then wait while the player walks there, turns to it and works it: the nearest standing prop of a kind, or the nearest usable of an archetype (a person, a sign). Fails when the game's clicks don't use things, nothing matches, or the walk stops out of reach.
Inventory kit.inventory
What a body carries: counts of Item documents, a bulk limit (each item's bulk times its count), stacks of each item's stack size, and one held item that is both the working tool and what is in hand. Also piles on the ground (the pickup component) that use takes. kit.core's give and take actions and every play kit move items through this kit's interface, so the limit is kept in one place. A carried Item with a use (eat, drink, light) is used by a press use:<item id> (the carry app's confirm on its row, the use_item tour verb): it spends a charge, one is taken away once its charges are spent, and inventory.used goes out for a rule to say what it does. A press hold:<item id> puts a carried item in hand (the carry app's confirm on an item with no use).
Components what an Archetype's entities can do
inventory- The body carries items. Anything added past bulkLimit is refused (the rest stays where it was). Give the player one; machines rarely need it.Fields:
bulkLimit,slots,startItems,startHeld pickup- A pile on the ground that use takes: dropped loot, a stash. It disappears once emptied. A killed machine's drop is one of these.Fields:
items
Actions what a rule does
hold_item- Put a carried item in hand (it becomes the working tool), or an empty item for bare hands.Fields:
entity,item
Events what rules hear
inventory.changed- Items came or went. Its latch is got:<item> when items came.Fields:
entity,item,delta,latch inventory.used- A body used a carried item that has a use (ate the berries, drank the potion): a charge was spent, and one was taken away when its charges were. Rules answer it with what using it does: where: event.item == 'item.berries', do: add_stat health. Latch used:<item>.Fields:
entity,item,verb,gone,left,latch inventory.full- Items were refused because the body can't carry more.Fields:
entity,item,refused
Functions what expressions call
item_count(e, item)→ number- How many of an item a body carries.
held(e)→ string- The Item id in the body's hand, or an empty string for bare hands.
carried_bulk(e)→ number- Total bulk the body carries.
Tour verbs what a Playtest's steps say
use_item ITEM- Use one of ITEM as the carry app's confirm does on its row (a use:ITEM press), and wait a tick: inventory.used has gone out by then. Fails when the player carries none, or the Item has no use.
Carried light kit.light_carried
A lamp a body carries and switches on and off. A lit lamp lets the carrier see and be seen: senses (kit.perception) treat a lit body as standing in daylight in the open, so it undoes both the dark and any cover. Optional oil burns down in world minutes. The look track draws the lamp's warm pool from light.changed. Use it for a light that is a trade-off, not a free torch.
Needs kit.inventory.
Components what an Archetype's entities can do
lamp- The body carries a lamp it can light. With item set, the lamp works only while that item is carried.Fields:
item,toggleAction,startLit,oilMinutes,radiusM,warm
Actions what a rule does
set_lamp- Light or put out a body's lamp.Fields:
entity,lit* toggle_lamp- Switch a body's lamp.Fields:
entity
Events what rules hear
light.changed- A light came on or went out: a carried lamp, or a station's fire. Presentation moves its light pool from this. Its latch is lit:<entity> or dark:<entity>.Fields:
entity,lit,radiusM,warm,source,latch
Functions what expressions call
lamp_lit(e)→ bool- True while the body's lamp is lit.
lamp_oil(e)→ number- World minutes of oil left in the body's lamp (0 when it takes none).
Tour verbs what a Playtest's steps say
toggle lamp- Press the player's lamp toggle for one tick.
Melee kit.melee
Close combat where tactics beat trading hits. A blow has windup (the tell: melee.tell fires as it starts, so presentation can brighten a lens or raise a limb), active, recovery and cooldown windows in milliseconds; it hits bodies within reach and arc in front. A dodge is a short dash with invulnerable frames. A body can wear plate over an arc (a blow there rings and does nothing) and have a working part over another arc that takes damage and stalls it, losing any tell in progress. A machine that bites and misses is carried on past and turns slowly while spent, so its back is open for a moment. At zero health a body is killed (and drops its LootTable as a pile) or downed (hours pass and it wakes at the last respawn point, such as a campfire, or a named place). Effects (kit.core) count here: damageDealtMul and damageTakenMul scale every hit, an invulnerable effect turns hits away, and a body an effect stops acting throws no blows and makes no dodges. The blast action is an area hit for abilities.
Needs kit.move.
Components what an Archetype's entities can do
melee- The body throws blows. For a body driven by input, attackAction throws one (aimed where the input aims); for an ai body its brain asks. Times are milliseconds and are rounded to whole ticks.Fields:
attackAction,windupMs,windupJitterMs,activeMs,recoveryMs,cooldownMs,reachM,arcDeg,widthM,damage,lungeMps,overrunMps,windupMoveMul,committedTurnDegPerSec,spentTurnDegPerSec,knockMps,knockMs,hitsTags,bufferMs,ringRecoilMps,ringRecoilMs dodge- The body can dodge: a short dash along its input (or backwards) with invulnerable frames in the middle. Dodging the tell is how a fight is won.Fields:
dodgeAction,durationMs,speedMps,endShare,iframeFromMs,iframeToMs,cooldownMs combatant- The body can be struck: its health stat, an arc of plate that rings, an arc where its working part is, invulnerable frames after a hurt, and what happens at zero health. A blow lands where the striker stands, seen from the body: sides are the body's own front, back, left and right.Fields:
healthStat,hurtIframesMs,plateSide,plateArcDeg,partSide,partArcDeg,stallMs,stallEveryMs,onDefeat,loot,dropArch,downedHours,respawnPlace,respawnTag,wakeHealthShare
Actions what a rule does
damage- Take health from a combatant outside a blow (a hazard, a trap). It counts as a hit from nowhere: no plate, no stall.Fields:
entity,amount* strike- Ask a body to throw its blow now, if it can.Fields:
entity blast- An area hit round a body, at once (an ability's ground slam, a nova, a bomb going off): every other combatant within radiusM of its edge meets it as it meets a shot from the body's centre (a dodge's invulnerable frames, hurt frames and plate turn it; a working part stalls), is knocked straight away from it, and when hurt takes the effect. Its hits, kills and downs are melee.hit, melee.killed and melee.downed.Fields:
entity,radiusM,damage,hitsTags,knockMps,knockMs,effect
Events what rules hear
melee.tell- A blow's windup began: the tell. Presentation shows it on the body (a lens brightening, a limb raised) and plays its windup sound. Latch tell:<attacker>.Fields:
attacker,windupMs,latch melee.swing- A blow became active (the whoosh).Fields:
attacker melee.hit- A blow hurt a body. part is true when it struck the working part. Latch hit:<target>.Fields:
attacker,target,damage,side,part,latch melee.ring- A blow rang off plate and did nothing. Latch ring:<target>.Fields:
attacker,target,side,latch melee.evaded- A blow met a body in its dodge's invulnerable frames. Latch evaded:<target>.Fields:
attacker,target,latch melee.whiff- A blow's active window ended without meeting anybody.Fields:
attacker melee.dodged- A body dodged. Latch dodge:<entity>.Fields:
entity,latch melee.stalled- A blow in the working part stalled the body; a tell in progress was lost.Fields:
entity,by melee.killed- A body was killed. pile is the dropped loot's entity, if any. Latch killed:<target>.Fields:
attacker,target,pile,latch melee.downed- A body was downed: hours pass. Latch downed:<entity>.Fields:
entity,by,latch melee.woke- A downed body woke at its respawn point. Latch woke:<entity>.Fields:
entity,at,latch melee.blast- A blast went off round a body (the blast action): a ring of radiusM past its edge, for a shockwave to show. Its hits follow as melee.hit. Latch blast:<attacker>.Fields:
attacker,radiusM,latch
Functions what expressions call
in_windup(e)→ bool- True while the body winds up a blow (its tell is showing).
melee_phase(e)→ string- The body's blow window: windup, active, recovery, cooldown, or an empty string when free.
can_strike(e)→ bool- True when the body could throw a blow now.
side_of(a, b)→ string- Which side of body a faces toward b: front, back, left or right.
stalled(e)→ bool- True while the body is stalled by a blow in its working part.
Tour verbs what a Playtest's steps say
fight tactics | fight trade- Let a bot play the player's side of the nearest fight until it is won (the foe is killed) or lost (the player is downed): tactics reads the tell, dodges it and strikes the working part; trade stands in front and swings (the control that should lose). The bots fight_tactics and fight_trade.
Bots what plays a Playtest
fight_tactics- Plays the player through the nearest fight the way it is meant to be won: waits in front for the tell, dodges out of the blow as the windup ends, goes round to the working part while the foe is spent or stalled and strikes it. Done when the fight is won or lost; reports outcome won or lost.
fight_trade- Plays the player through the nearest fight by standing in front and swinging whenever it can, never dodging: the control that should lose against plate and a tell. Done when the fight is won or lost; reports outcome won or lost.
Mesh builders kit.mesh
Tier 1 mesh builders: a Model document names one of these builders, its params, palette slots and a budget, and the engine builds the mesh at load (no imported art). Compose archetypes (tree.tiered, rock.faceted, driftwood.log, wreck.hull, machine.sentry, figure.person, campfire.ring) rather than primitives; mesh.parts is the escape hatch for a novel prop and needs every part grounded and touching. Models face +X, stand on y = 0, and are sized in world units (a tile is 1). Palette slots take sRGB hex or @slot from the Style. Rigged builders (machine.sentry, figure.person) come with joints and named poses the views play by name (a sprite's clips, kit.actors' pose rules); a Model may add poses or replace them with its own poses and moves, and mesh.parts is rigged by giving it joints, so an animal or a bird the Director draws can run, strut or flap.
Builders what Model, Sound and Sprite recipes name
tree.tiered- A conifer as 3 to 5 drooping, offset tiers of jagged needles on a tapering trunk: never a cone. Crowns sway in the wind, each tier on its own phase, and are the first thing the camera stipples away over the player. One surface (foliage). Palette slots: bark, needle, needle_dark (the undersides).Fields:
tiers,heightM,spreadM,trunkM,droop,leanDeg,jag rock.faceted- A boulder as a faceted, leaning hull, optionally split in two with a gap, with scree at its foot: never a sphere or a cube. One surface (made). Palette slots: stone, stone_dark (scree and the split faces).Fields:
radiusM,heightM,leanDeg,split,facets,stones driftwood.log- A bleached, bent log lying on the ground along its length, with a splayed root end and broken branch stubs. One surface (made). Palette slots: wood, wood_pale (broken ends), wood_dark (the underside).Fields:
lengthM,radiusM,bends,branches,roots wreck.hull- The broken hull of a dead machine lying half sunk: a panelled shell snapped in two, torn plates, exposed ribs and a dead lens. FOUND metal that takes the land's rust. Palette slots: plate, plate_dark (ribs and the torn inside), lens_dead.Fields:
lengthM,widthM,heightM,sunk,tiltDeg,torn machine.sentry- A quadruped sentry machine: a panelled FOUND body with a plate across its front, a working part (a vent) on its back, a wedge head with one lens as the only saturated thing on it, and four jointed legs. A dark mass by day. Rigged: poses stand, walk, alert, windup, strike, hurt, dead (the Model may add or replace poses, or take plan.quadruped's presets, a trot or a walk; joints body, head and each leg's thigh and shin: fl, fr, bl, br). At most 3 surfaces (found, emissive). Palette slots: plate, joint, vent, lens.Fields:
heightM,lengthRatio,lens,plateFront,ventGlow,plan,roles,presets,poses,moves figure.person- A person: chunky, about 4.6 heads tall, with a big head and big hands, a coat whose hem stands out from the legs, and a warm rim that holds the silhouette in any light. One skinned surface (figure). Rigged: poses idle, walk, run, crouch, swing, dodge, hurt, down, and no jump or fall, which a Model takes from plan.biped's presets or writes with its own poses and moves. Joints: hips (the root), spine, head, and on each side (_l, _r) arm, fore, hand, thigh, shin, foot; a limb hangs down from its joint, so a positive swing takes it forward. Palette slots: skin, hair, coat, shirt, trousers, boots.Fields:
heightM,build,coat,hood,plan,roles,presets,poses,moves campfire.ring- A campfire: a ring of stones round charred ground, logs leaned in a tent, and an emissive ember slot with low flames. Exposes the anchor fire for its light (warm, unsteady). Palette slots: stone, log, char, ember, flame.Fields:
radiusM,stones,logs,burning mesh.parts- A model as a list of primitives (box, prism, strut, hull) placed by hand: for a prop, an animal or a bird no archetype builder covers. Every part must stand on the ground or touch another part. Palette slots are the ones the parts name. Give it joints (a body, a head, a joint at the top of each leg, a tail) and each moving part the joint it rides, and it is rigged: name its body plan (plan.quadruped, plan.biped, plan.bird) and take the plan's presets (a gallop, a hop, a strut, a jump, a hurt), changing any joint with moves of its own, or write poses made of moves for a body no plan fits (a flag that waves).Fields:
parts*,joints,plan,roles,presets,poses,moves
Ground movement kit.move
Walking bodies on a tile world: walk, run and crouch speeds, a step of at most one level, cliffs, deep water and blocking props that stop a body, shallows that slow it, and round bodies that never overlap. The player's body follows the input's world-space intent; a machine's body walks toward a goal its brain sets, routed around cliffs. Give every archetype that moves a move component; everything else (senses, blows, work) reads its gait and position from here.
Components what an Archetype's entities can do
move- A body that walks. driver input follows the player's input frames (move is world-space intent, run and crouch are held actions); driver ai walks toward goals a brain sets and faces what it is told to face. Speeds are metres per second on flat dry ground; the ground's speedMul and shallow water scale them, and so does any Effect on the body (speedMul; canMove false holds it where it stands, though it can still be pushed).Fields:
driver,walkSpeedMps,runSpeedMps,crouchSpeedMps,wadeSpeedMul,radiusM,solid,turnDegPerSec,canSwim,runAction,crouchAction,arriveM,rerouteMs,walkStepHz,runStepHz,crouchStepHz
Actions what a rule does
walk_to- Send an ai body walking toward a named place, routed around cliffs and water.Fields:
entity,place*,gait stop_walking- Stop an ai body where it stands.Fields:
entity dash- Throw a body along the ground at a speed for a moment, in place of its own walking: an ability's dash, a charge, a leap back. Walls and cliffs stop it as they stop a walk; an effect that slows or holds the body doesn't.Fields:
entity,speedMps,ms,dir
Events what rules hear
move.step- A body put a foot down: one per stride at its gait's step rate while it moves. Map it to footsteps per ground with a cue like snd.step_{ground}.Fields:
entity,ground,gait move.arrived- The player's walk to a click ended (the InputMap's pointer click walk or use): there, or as near as the world's route goes. Tours wait for it as the latch arrived.Fields:
entity,reached,latch move.dashed- A body began a dash (the dash action). Latch dashed:<entity>.Fields:
entity,latch
Functions what expressions call
gait(e)→ string- How a body is moving: stand, walk, run or crouch.
crouched(e)→ bool- True while the body is crouched, moving or still.
wading(e)→ bool- True while the body stands in shallow water.
Tour verbs what a Playtest's steps say
goto prop:<kind> | goto place:<name> | goto near <arch id> <metres>- Walk the player along the world's route to the nearest prop of a kind, a named place, or within some metres of the nearest entity of an archetype. Fails when there is no such thing or no route.
click_to place:<name> | click_to near <arch id>- Click the ground once, as a person does in a game whose clicks walk (its InputMap's pointer click walk or use), then wait while the player walks there: a named place, or the ground a metre short of the nearest entity of an archetype (beside a person without using them). Fails when the game's clicks don't walk or nothing matches.
Scored music kit.music
A game's music, written as a Score document (music/<slug>.score.json) and rendered at load into seamless whole-bar loops that play on desktop and the web. Give the Score a key, a mode, a tempo and a meter, and sections of whole bars, each with chords as Roman numerals in the key (i VI III VII; upper case major, lower case minor, :2 for two bars). Each stem is voiced by a Sound made with synth.layered or synth.sfx (a pad, a pluck, a bass, a kick, a hat: the Sound's timbre, played at each note's pitch) and plays chords, an arp over them, a drone, a euclid rhythm (drums with pitch none, a bass on the root), a motif of scale degrees changed bar by bar (same, follow, invert, retrograde, up, down), or explicit notes {bar, beat, note, length} with note names like A3 or scale degrees. Layers turn stems up and down from the game: a level from 0 to 1, read from self (the player), game, var and tune, eased over easeBars bars (var.score / 5 for drive; 1 if game.hour >= 20 or game.hour < 5 else 0 for night; watched(self) for tension when kit.perception runs). The first section whose when holds plays, switching on a bar line; put the default section last, without when. Stems are measured and set to the mix sheet's music level plus their levelDb. Put a held stem (a drone or a pad) first: it leads, playing alone while the rest bake. The game's Style chooses the Score it plays (audio.score), so a restyle can swap the music; without one, the first Score by id plays. Music only reads the game, so a Score may call only pure functions, and adding or changing one, or turning kit.music on, never changes play.
Needs kit.audio.
Perception kit.perception
How a watcher (a machine, a creature, a guard) comes to know a body is there: a sight cone with range, hearing that scales with how loud the body moves, darkness from the clock, cover from the world, a clear line of sight, and a suspicion ramp from 0 to 1 per second. Suspicion rises fastest for a body close by and slowest at the edge of the sense that finds it, so a body far off, low in cover, in the dark, only heard or glimpsed takes longer; it drains when nothing comes of it, and at 1 the watcher is sure. Night and cover shorten sight but never hearing. A lit carried lamp undoes both the dark and the cover. Behind its cone a watcher sees only close up. Brains react to perception.noticed and perception.lost.
Needs kit.move.
Components what an Archetype's entities can do
perception- A watcher's senses. Ranges are for a standing body in daylight in the open; what the body does (crouch, cover, the dark, its lamp, how loud it moves) scales them. Once sure of a body the watcher keeps track of it all round, until it has not sensed it for loseMs.Fields:
sightM,coneDeg,behindShare,hearingM,nightSightShare,coverSightCut,eyeHeightM,beatMs,nearRisePerSec,edgeRisePerSec,fadePerSec,nightHearBoost,suspiciousAt,loseMs,watchTags noticeable- A body watchers can notice. How loud each gait, or working a prop, is scales the watcher's hearing (and the ground's noise scales footsteps again); crouching also cuts how far it is seen.Fields:
crouchSightShare,loudStand,loudWalk,loudRun,loudCrouch,loudWork,centerHeightM,crouchHeightM
Actions what a rule does
forget_all- Make a watcher forget every body at once: suspicion to 0, nothing noticed.Fields:
entity
Events what rules hear
perception.noticed- A watcher became sure of a body (its suspicion reached 1). Its latch is noticed:<target>.Fields:
watcher,target,how,latch perception.suspicious- A watcher's suspicion of a body rose past suspiciousAt: it is not sure yet and turns to look. Presentation may flicker its lens.Fields:
watcher,target,how perception.lost- A watcher that was sure of a body has sensed nothing of it for loseMs. Its latch is lost:<target>.Fields:
watcher,target,latch
Functions what expressions call
suspicion(e)→ number- How sure the watcher is of the body it watches most closely, 0 to 1.
is_aware(e)→ bool- True while the watcher is sure of some body.
focus_distance(e)→ number- Metres from the watcher to where it last sensed the body it watches most closely (a large number when there is none).
sensed_seconds(e)→ number- Seconds since the watcher last sensed that body.
watched(e)→ number- How sure the surest watcher is of this body, 0 to 1: the most suspicion any watcher holds of it. watched(self) in a Score's layer is the player's tension.
2D platformer kit.platformer
Side-view platforming on a tile grid, for 2D platformers. Bodies are boxes that run with acceleration and friction, jump with coyote time, jump buffering and variable height (letting go of jump early cuts the rise), fall under gravity to a terminal speed, stand on solid ground and one-way platforms (down drops through), climb ladders, and never pass through solid tiles. Everything moves in whole sub-tile steps on a fixed tick, so a run replays exactly and the core's reachability search plays the same moves. Levels are PlatformLevel documents made of Room documents, played in order; spikes and falls hurt and send the player back to the last checkpoint; things with a platformer_touch component are collected, set the checkpoint, end the level or hurt. The player's input actions are left, right, jump, down, climb and pause. Give the player archetype a platformer_body with driver input; enemies a platformer_body with driver patrol and a platformer_touch with role hurt.
Needs kit.sprite.
Components what an Archetype's entities can do
platformer_body- A body that moves on a platformer's tiles: a box standing on its feet, sizes and speeds in tiles and seconds. driver input follows the player's actions (left, right, jump, down, climb); driver patrol walks one way and turns at walls (and at ledges with turnAtLedges); driver still only falls. A full jump rises about jumpSpeedTilesPerS squared over twice gravityTilesPerS2 tiles; gamewright reach prints the exact apex and gap for the numbers given. Numbers may be written as tune.<knob> expressions over constants and knobs; the core evaluates them to prove every level completable, so they may read nothing else.Fields:
driver,widthTiles,heightTiles,runSpeedTilesPerS,runAccelTilesPerS2,runDecelTilesPerS2,airAccelTilesPerS2,jumpSpeedTilesPerS,gravityTilesPerS2,fallSpeedMaxTilesPerS,jumpCutRatio,coyoteMs,jumpBufferMs,climbSpeedTilesPerS,canClimb,turnAtLedges,invulnerableMs,respawnMs platformer_touch- What happens when the player's box touches this thing's box. collect: it is taken (it disappears for the rest of the game and adds value to platformer_collected()). checkpoint: the player comes back here after being hurt. exit: the level is done and the next begins (after the last, the game is won). hurt: the player takes damage and goes back to the last checkpoint (an enemy, a saw); a beatable one is stomped instead when the player comes down on it from above.Fields:
role,widthTiles,heightTiles,damage,value,beatable,hits,stompBounce
Actions what a rule does
platformer_strike- A blow ahead of a platformer body (an Ability's swipe): each beatable thing within reach takes damage hits.Fields:
entity,reachTiles,heightTiles,damage
Events what rules hear
platformer.level- A level began (or began again). Latch level:<id>.Fields:
level,index,latch platformer.jumped- The player jumped (from the ground, in coyote time, or off a ladder). Latch jumped.Fields:
latch platformer.landed- The player landed on ground, a platform or a ladder top after being in the air. Latch landed.Fields:
latch platformer.checkpoint- The player touched a checkpoint it was not already at. Latch checkpoint:<id>.Fields:
thing,latch platformer.collected- The player took a collectible. Latch collected:<id>.Fields:
thing,arch,value,total,latch platformer.hurt- The player was hurt by spikes, a fall or a hurt touch, and goes back to the last checkpoint. Latch hurt.Fields:
cause,damage,tx,ty,latch platformer.died- A hurt took the player's last health: the player's health is restored at the last checkpoint and the deaths count grows (a rule may end the game instead). Latch died.Fields:
deaths,cause,latch platformer.exit- The player touched the level's exit. Latch exit and exit:<level>.Fields:
level,ticks,latch platformer.struck- A beatable thing was hit and has hits left. Latch struck:<thing>.Fields:
thing,arch,how,left,latch platformer.beaten- A beatable thing was beaten and is gone: score it, open the way, win on the boss. Latch beaten:<thing>.Fields:
thing,arch,how,left,latch platformer.complete- The last level's exit was touched: the game ends with a win. Latch complete.Fields:
latch
Functions what expressions call
platformer_level()→ string- The current PlatformLevel's id.
platformer_hits_left(e)→ number- Hits a beatable thing has left: a boss's bar.
platformer_collected()→ number- The value of everything collected in this game.
platformer_deaths()→ number- How many times the player has died in this game.
platformer_done(level)→ bool- True once the PlatformLevel's exit has been touched in this game.
platformer_grounded(e)→ bool- True while a body stands on ground, a platform or a ladder top.
World passes steps of a WorldGen
rooms.chain- Lays a PlatformLevel out Spelunky-style, in the level's generate field (not a WorldGen): it walks a path through the room grid first (a start room in the top row, left and right along a row, down to the next, until it leaves the bottom row in the exit room), places a room template on each path cell whose openSides give the path its exits and whose roles fit (start, path, exit), then fills every other cell with a filler room. Every template it may use is checked on its own, and the finished level is proven completable by the reachability search; a level that is not is laid again from the next attempt's seed (attempt.<n>, by name), and bake records the attempt that won.Fields:
templates,minPathRooms,dropChance,attempts,fill
Tour verbs what a Playtest's steps say
inputs <runs...>- Play input runs tick by tick, like 12R 20RJ 5-: a tick count, then the keys held (L left, R right, J jump, D down, U climb, - nothing). A key held in one run and the next stays held; one newly held is pressed.
route [level id]- Replay the level's witness (the path bake proved it completable with) from the level's first tick, starting the level over when it is not at its first tick; the current level when none is named. Fails when the level has no witness or the exit is not touched when it ends.
enter <level id>- Press level:<id>, as a level select screen would, and start that level from its start.
Bots what plays a Playtest
playthrough- Plays every level in order the way a person would, so a Playtest measures how often people are hurt and where, how long each level takes, how often they try again and which levels they give up: it follows each level's witness move by move with a person's reaction time, lines each jump up never quite on the spot, presses and lets go a little early or late, fumbles now and then, waits for a moving hazard to pass, finds its own way back when it falls off the route, goes back to the checkpoint when hurt and tries again, and gives a level up after its patience runs out (then goes on to the next, as a level select would). A Playtest's skill sets its hands: novice, casual (the default), skilled, or perfect (none of it: it plays the witness tick for tick). Seeded from the game's seed (bots/playthrough/<level>/...), so a run replays.
Ranged kit.ranged
Shots that fly: a shooter fires projectiles (each an entity of a projectile Archetype, drawn by its model) that fly straight and level from where it stands, are stopped by cliffs, blocking props and the world's edge, run out at their range, and hit the first combatant they touch through kit.melee, so a shot meets dodges, hurt frames, plate and working parts as a blow does and its hits, kills and downs are melee.hit, melee.killed and melee.downed. A body driven by input shoots where the aim stick points as soon as it is pushed (the twin-stick way), or with its fire action held; an ai body shoots when a state machine asks (the shoot action), after a tell, at where its target stood when the tell began. Use it for anything that shoots, throws or spits: a twin-stick hero, a turret, a spitting beast, a slingshot.
Components what an Archetype's entities can do
shooter- The body shoots. Driven by input it shoots where the aim stick points once it is pushed past half (aimFires), or where it faces while fireAction is held; an ai body shoots when a state machine's shoot action asks. Each shot is a new entity of the projectile Archetype, which says how it flies (its projectile component) and how it looks. Times are milliseconds, rounded to whole ticks.Fields:
projectile*,fireAction,aimFires,cooldownMs,windupMs,windupMoveMul,count,spreadDeg,damage,hitsTags,muzzleM,effect projectile- A shot, on the Archetype a shooter fires: it flies straight and level at heightM over the ground it left, at speedMps, until it has flown rangeM, meets a cliff two levels up, a blocking prop or the world's edge, or touches a combatant its shooter's shots hit. A body in a dodge's invulnerable frames lets it pass; anything else stops it (pierce lets it go on through that many hits). Give it a model (a small glowing part) and nothing else that moves.Fields:
speedMps,rangeM,radiusM,heightM,pierce,knockMps,knockMs
Actions what a rule does
shoot- Ask a shooter to shoot as soon as it can (its cooldown and tell allowing), at an entity, or where it faces. The ask holds until the shot is fired, so a state machine's onEnter shoots once: a spitter's machine aims (brain_hold with face), shoots, and goes back to hunting after a time.Fields:
entity,at fire- Fire a volley now from any body, shooter or not: an ability's fireball, a burst of darts, a spit. It has no tell or cooldown of its own (the ability's cooldown paces it); its shots fly and hit as a shooter's do (ranged.fired, ranged.spent, melee.hit with the body as attacker), and a shot that hurts puts the effect on what it hit.Fields:
entity,projectile*,at,damage,count,spreadDeg,hitsTags,muzzleM,effect
Events what rules hear
ranged.tell- A shooter began its tell: the shot leaves windupMs later, at where it aims now. Presentation brightens a lens or raises a limb. Latch tell:<shooter>.Fields:
shooter,windupMs,latch ranged.fired- A shooter fired a volley. Map it to the shot's sound on the shooter's cues. Latch fired:<shooter>.Fields:
shooter,shot,count,latch ranged.spent- A shot ended and is gone: how is hit (it hurt what it touched: melee.hit says more), ring (plate turned it), guarded (the body was in its hurt frames), wall or range. Sent while the shot is still there, so its own cues can play a splash; rules see it after the shot is removed. Latch spent:<shooter>.Fields:
shot,shooter,target,how,latch
Functions what expressions call
can_shoot(e)→ bool- True when the shooter could fire now: alive, off its cooldown, not in a tell, not stalled.
in_tell(e)→ bool- True while the shooter's tell shows (a shot is about to leave).
Tour verbs what a Playtest's steps say
skirmish [SECS [until LATCH]]- Let the skirmish bot play the player's side of a ranged fight: it keeps away from the foes, aims at the nearest with a person's reaction time, shoots, and dodges a blow or a shot it sees coming. Done after SECS game seconds (a tour's kit verb gives up after 60), once LATCH is set when until names one (skirmish 40 until tell:spitter.0: play until a spitter's tell, to shoot it), or when the game ends or the player is down.
Bots what plays a Playtest
skirmish- Plays a game of shooting as a fair person would: keeps 4 to 8 metres from the foes and away from walls, strafing round them; aims at the nearest foe its shots can hit, leading it a little, with 8 to 15 ticks of reaction and a few degrees of aim error drawn from its own seeded stream; shoots while one is in range; dodges a blow's tell or a shot coming at it when the player can dodge. Never done: it plays until the run's ticks pass, the game ends, or the player is down. Reports shots fired, foes killed and hits taken.
Sprites kit.sprite
Pixel-art sprites for 2D games, baked from the same Model recipes 3D games draw: a Sprite document names sprite.baked, a Model and the clips to render, and the player renders each frame of each clip from a fixed orthographic camera (a side view by default), lit by one fixed light, snapped to the model's palette and outlined, into one atlas at load, cached by the recipe's hash. A clip samples one of the Model's poses, so a sprite moves as its Model can: give a mesh.parts animal joints, poses and moves (kit.mesh) for a run cycle, a jump and a strut. Or draw the person's own art: a Sprite that names sprite.sheet cuts an image they imported (an Asset) into frames of one size and plays runs of them as clips, so a sheet from an artist or an asset store works as it is. Archetypes show a sprite with the sprite component; the 2D views of other kits (kit.platformer) draw it, choosing clips by name (idle, walk, run, jump, fall, climb, hurt) from what a body is doing.
Needs kit.mesh.
Components what an Archetype's entities can do
sprite- How a 2D view draws the archetype: the Sprite recipe baked into its frames, or, with none, a flat box of a colour.Fields:
sheet,color
Builders what Model, Sound and Sprite recipes name
sprite.sheet- Draws the person's own art: an image they imported (an Asset: PNG, JPEG or WebP) cut into frames of one size, left to right and top to bottom, each clip a run of frames along one row. Every frame shares one size and one pivot, where the feet are (the middle of the bottom edge unless pivotXPx and pivotYPx say otherwise), so a view stands the sprite on a body's feet and turns it the way the body faces; give flip when the art faces left. The pixels are drawn as they are, never snapped to the Style's palette. With no clips, the first frame is a still clip, idle. A frame size of 0 is the whole image: one picture.Fields:
asset*,frameWidthPx,frameHeightPx,clips,pivotXPx,pivotYPx,pixelsPerTile,flip sprite.baked- Renders a Model recipe into pixel-art frames: the model is posed for each frame of each animation, turned by yawDeg and seen from the side (pitchDeg looks down on it) through an orthographic camera at pixelsPerTile pixels per world unit, lit by one fixed light, rendered at supersample times the size and brought down by the most common colour, snapped to shades of its palette, and outlined. Every frame shares one size and one pivot: the model's feet (its origin) sit at the pivot, so a view stands the sprite on a body's feet. A model faces +X, so at yawDeg 0 the sprite faces right. Pure: the same recipe gives the same pixels on every machine and in the web build, pinned by golden hashes.Fields:
model*,anims,pixelsPerTile,yawDeg,pitchDeg,lightYawDeg,lightPitchDeg,ambient,shades,supersample,outline,paddingPx
Slate UI kit.ui
Every screen as a Screen document: a flat list of widgets (frame, label, bar, cells, list, icon, hint, button, sprite) with a parent, an anchor, an offset and a size in whole pitches, and a value from an Expr binding (self is the player; game, var, tune), a feed another kit provides (carry, make, held, hint, message, game, dialogue) or the chosen row of a list. A visual novel's whole look is one Screen: fill frames paint a backdrop's sky and ground from the Style's palette, sprite widgets stand baked Sprites (figures and props from Model recipes) on it, bound to variables like var.left so the story moves them, and the dialogue feed gives the line on screen, its speaker, the words said so far (a label's revealKey) and the choices on offer (a list's chosenKey). The HUD (the manifest's flow.hud) is drawn over the world; the apps (flow.apps, or Screens with frame slate) sit one at a time on a device drawn in the style's ui tokens: a stolen machine display in a patched bezel, phosphor text on dark glass, one warning colour, a pixel face cut in code, never filtered. Key hints read the live input map. Menus move by abstract actions (up, down, left, right, confirm, back, next, prev) named in the style's ui.tokens.nav, so a tour or test drives them like a player. It also draws the menu every game has (the GameManifest's menu: pause, continue, options) on ui.pause and ui.options, its own Screens unless the game has one of that id, from the menu feed (title, rows, pick, note).
Builders what Model, Sound and Sprite recipes name
ui.theme- The Godot Theme for a style's UI, built at load from its ui.tokens: the pixel face at the pitch, flat unfiltered boxes with borders and margins in whole pitches, and the slate palette as named colours. Set the tokens in the Style document's ui.tokens; everything unset keeps the engine's slate.Fields:
pitch,glass,glassRow,glassLit,glassSpare,phosphor,warn,warnDim,bezel,bezelLight,bezelDark,patch,tape,screw,rim,veil,slateSize
Juice kit.vfx
What a game shows when something happens: particles, a flash, a squash and a shake, answering events as kit.audio's cues answer them with sounds. Write them in the game's Style as vfx.effects, one per event, each with any of four parts. particles: a burst where it happened (count, speed, spread in degrees round straight up, lifeSec, size, gravity: positive falls like sparks and chips, negative rises like dust and motes; drag; shape square or spark, a streak along its path), coloured from palette slots (colors: [@spark, @ember]); with trailSec they leave one by one from where the entity is then, a trail behind a shot. flash: the entity lights up in one colour and fades (seconds at most 0.3). shake: the view shakes (strength a share of its height: 0.005 a nudge, 0.015 a hit, 0.04 a blast; falloff fade, sharp or none); shakes at once don't add up. tween: the entity changes shape on its feet and springs back (squash for a landing, stretch for a jump, pop for a pickup or a win, hop for a step, grow for a spawn). at says where: the event's field naming the entity or place (target on melee.hit, shot on ranged.fired, thing on platformer.collected), or player; left out, the first entity the event names, else the player (a platformer's jump, a grid's win). Units are metres in 3D, tiles in a platformer, cells on a grid. Keep it tasteful: small, short and in the game's colours; save the big shake for the big moment. Accessibility is built in: at most three flashes start in any second, only an entity ever flashes (never the screen), and the person's Options offer Screen shake (on, reduced, off) and Flashes (on, off) in any game whose Style has them. Every effect is a look: it reads the game and never changes it, and its particles are seeded by name from the event, so a replay and a shot at a named tick show the same thing.
World tiles kit.world_tiles
A generated world on a tile grid that the eye sees as contour terraces, never as a grid. Rules read whole levels per tile (a body steps one level, two or more is a cliff), grounds from a Biome, water sheets (wading under 0.5 units, deep at 0.5 and over) and a table of props with stable ids (region.r0/prop.pine.17) that are worked down in stages. Generation is a WorldGen document: a list of the passes below, each drawing from its own named stream, so adding a pass never moves another. Use it for any top-down or ortho game played on terrain: coasts, moors, islands, valleys. It provides the world queries (height, ground, water, stepping, sight, cover, props, named places) and routing around cliffs that movement, perception and harvest kits use.
Events what rules hear
world.prop_worked- A prop was worked down one stage (a take by harvest). gone is true when it has no stages left.Fields:
prop,kind,stage,stages,gone
World passes steps of a WorldGen
noise.height- Rolling hills: a continuous height field of fractal value noise, centred on baseLevels. Later passes shape it (shape.coast) and cut it into levels (terrace.levels).Fields:
scaleTiles,octaves,persistence,amplitudeLevels,baseLevels shape.coast- Puts the sea along one side. A wandering shoreline, a sea floor shelving down, a flat beach band, then land rising inland with the hills fading in. Needs noise.height before it.Fields:
seaSide,shoreAtFrac,wobbleTiles,wobbleScaleTiles,beachTiles,beachLevel,seaDepthLevels,shelfTiles,inlandRiseLevels,riseTiles,hillsRampTiles terrace.levels- Cuts the height field into whole levels, the terraces the rules and the eye share. Optionally raises a cliff band a body can't climb, with ramps through it.Fields:
minLevel,maxLevel,cliffAtTiles,cliffLevels,cliffWobbleTiles,cliffWobbleScaleTiles,cliffGaps,cliffGapTiles,rampTilesPerLevel,tidy water.sheets- Lays the water as flat sheets: the sea (every tile at or below the Biome's water.level joined to the map edge) and optionally one tarn carved into high flat land.Fields:
wadeM,tarnRadiusTiles,tarnDeepLevels,tarnMinLevel,tarnEdgeTiles ground.assign- Gives every tile a Biome ground by rules on level, slope, distance from the sea, water, moisture and a disc of the map (atFrac, withinTiles). Also sets each tile's ground cover. Run it after the land and water are shaped.Fields:
rules*,moistScaleTiles scatter.props- Stands Biome props on the land, one rule per kind, each rule kept to its grounds, levels, slopes, distance from the sea, patches and a disc of the map (atFrac, withinTiles). Ids are stable: prop.<kind>.<n> counts only that rule's own candidates, so adding a rule, a kind or a pass never renumbers the rest.Fields:
rules* place.sites- Names places (spawn, tarn, wreck, cliff_top) so tours, spawns and quests stage by name, never by coordinate.Fields:
sites* path.guarantee- Makes every named place walkable from a start place. Where no walk exists it opens the cheapest way: a ramp through a cliff, a ford through deep water, a gap in blocking props. Stores each route as a witness.Fields:
from,to,canSwim verify.reach- Proves the world is solvable: every named place is reachable from the start, and every stored witness still walks. Failures are reported with the place's name. Run it last.Fields:
from,canSwim