How-To: Write GessaScript
Add behavior to a world by authoring GessaScript. The normal authoring path is the Script Semantic Patch (typed, intent-level operations applied to the script) not hand-writing Script IR and not hand-editing generated source. You declare what should change; the backend compiler owns the rest.
This page describes the canonical authoring flow for v1. Source and visual authoring both round-trip through Script IR; generated TypeScript is runtime/debug output, not normal creator truth.
Media placeholder: add a capture showing the same script in Visual and GessaScript source, then a Play trace mapped back to the authored node/source span.
What is canonical: the IR, not its projections
Script IR is the canonical behavior contract. It is the single source of truth for what a script does. The two surfaces creators usually look at (GessaScript source and the visual node graph) are both constrained authoring surfaces over the IR. Generated TypeScript is an execution and debug projection. Editing source or visual means editing the IR underneath; neither surface is allowed to drift into a separate truth.
The IR's root is versioned (an irVersion literal), so a script declares which IR contract it conforms to. You never hand-write that IR. Instead you express intent through the semantic patch layer, and the compiler projects it into canonical IR, owning node ids, ports, and layout. See Explanation: Script IR and GessaScript.
The semantic patch is the normal path
Semantic patches are creator-facing edit operations derived from packages/script-semantic-patch. The backend compiler projects them into canonical Script IR, and the normal Project Graph script-update path persists the result. The catalog is Tier-2 generated; the current count and inventory of operations live in the generated file:
docs/spec/generated/script-semantic-patch.md: the operation catalog, packs, and effect tags.docs/spec/generated/script-node-catalog.md: the canonical Script IR node declarations (event, core, and host nodes).docs/spec/generated/script-sdk.md: the generated Script SDK surface (ScriptContextand thectx.*host namespaces).- Reference: Script Nodes: the thin pointer page.
You apply a patch through the canonical action project.script.patch.apply, surfaced to agents as the MCP tool project_apply_script_semantic_patch. Each operation carries typed effect tags (readState, writeState, durable, spawnEntity, despawnEntity, emitEvent, requiresAuthority) so the authority layer knows exactly what a behavior touches.
Representative operations (read the generated catalog for the full set and each operation's schema): findEntitiesByTag, forEachEntityInResult, incrementNumericState, declareWinCondition, emitCustomEvent, spawnEntityFromTemplate, despawnEntity, attachComponentWithValidatedDefaults, wireHudStateBinding, and the higher-level addShooterCollectorLoop, which expands a common gameplay loop from semantic intent alone. Handler operations (addActionHandler, addTriggerHandler, addTimerHandler, addTickHandler, createCustomEventHandler) attach the entry points behavior runs from.
The compiler owns ids, ports, and layout
This is the point of the semantic patch. You declare intent (add a tick handler, spawn an entity from a template, declare a win condition); the compiler decides node ids, wires execution and data ports, and lays out the graph. That is why the source and visual graph stay in lockstep, they both re-project from the IR the compiler produced. If you hand-wired nodes, the two surfaces would drift and the IR would no longer be a single authority. Let the compiler do it.
The authoring recipe
Related
- Explanation: Script IR and GessaScript: why the IR is canonical and source/visual are projections.
- Reference: Script Nodes: the generated node catalog and SDK surface.
- How-To: Use MCP Tools: discovery-first authoring from an agent.
- How-To: Publish and Play: validating a behavior change in a Play session.
Status: this page documents the canonical GessaScript authoring flow for v1. The exact operations, node declarations, and SDK methods live in generated references; use runtime proof for runtime claims.