Gessa Docs
Recipes

Recipe

Writing GessaScript source to rewrite or remove behavior a patch cannot express (whole-body script text)

You want to author or REWRITE a whole script as text - including removing a handler or changing an existing value, which the add-only semantic ops cannot express. One replaceScriptFromGessaScript operation replaces the entire script body; the compiler owns IR, node ids, and layout, and returns structured GS_* diagnostics (stable codes + source paths) when the source does not parse or validate.
engine v1.0.234since script-semantic-patch-ops.v1, gessascript.v1Copy for LLM

Use this for

authoring or rewriting a whole script as readable source text; SUBTRACTIVE edits (removing a handler, changing a literal in place) the add-only ops cannot express; expressing multi-handler logic in one call

Not for

small incremental additions (prefer the typed ops - addTriggerHandler, incrementNumericState, despawnEntity, etc.); raw IR or visual-node wiring (addNode/connectExec are editor/import-only and blocked for ai)

Pairs with: Collectibles pickups scoring and win condition, Event wiring one trigger emits another responder reacts, UI HUD panels widgets and world nameplates

When to use

You want to author or REWRITE a whole script as text - including removing a handler or changing an existing value, which the add-only semantic ops cannot express. One replaceScriptFromGessaScript operation replaces the entire script body; the compiler owns IR, node ids, and layout, and returns structured GS_* diagnostics (stable codes + source paths) when the source does not parse or validate. For small additive tweaks, prefer the typed ops instead.

The call

JSON
{
  "id_or_key": "coin_pickup",
  "request": {
    "ifVersion": <current version>,
    "intent": "Rewrite coin pickup as whole-body source.",
    "operations": [
      { "op": "replaceScriptFromGessaScript", "source": "<the whole script text>" }
    ]
  }
}

via project_apply_script_semantic_patch. The op is in the ai_safe pack.

The grammar (complete for v1)

Top-level, inside script <scriptKey> { ... }:

  • var <name>: <type> = <literal>;
  • custom event <key>(<params>);
  • event <eventName>(<params>) { <statements> }
  • function <name>(<params>) -> <type> { <statements> } (prefix export to expose)

Statements:

  • let <name> = <expression>;
  • set <path> = <expression>;
  • host <Namespace>.<name>(<args>);
  • component <ComponentType>.patch({ ... });
  • if <expression> { ... } else { ... }
  • for <name> from <expr> to <expr> max <number> { ... }
  • while <expression> max <number> { ... }
  • return <expression>;

Expressions:

  • JSON literals, arrays, records, vector3(x, y, z)
  • get(path.to.value) - read a variable/state path
  • event.key(), event.payload(path, type, default?)
  • record.get(record, path, type, default?)
  • array.length(v), array.get(v, index, type, default?), array.first(v, type, default?)
  • call <functionName>(...) (or bare <functionName>(...) as a statement)
  • math/comparison/boolean HELPER CALLS, not operators: add, sub, mul, div, mod, eq, ne, lt, lte, gt, gte, and, or, not. Write if gt(deltaSeconds, 0) { ... }, never if (deltaSeconds > 0).

It is NOT TypeScript: no imports, no arbitrary code, no infix arithmetic or comparison operators, no const, no template strings. Unsupported syntax returns GS_* diagnostics naming the construct and its span.

Compile-verified example

Text
script script.launch {
  var score: number = 0;
  custom event combat.hit(entityId: string);

  event onStart() {
    let greeting = "ready";
    host Debug.log(greeting);
    component TransformComponent.patch({ position: vector3(0, 1, 0) });
  }

  event onTick(deltaSeconds: number) {
    if gt(deltaSeconds, 0) {
      host Debug.log("tick");
    }
  }

  export function addScore(by: number) -> number {
    return add(by, 1);
  }
}

Handler events available: onStart, onTick(deltaSeconds), onTriggerEnter, onTimerFired, onActionResolved, onCustomEvent (custom events also arrive via their declared key; read fields with event.payload(...)).

Gotchas

  • The source replaces the WHOLE script: include every handler you want to keep.
  • Host namespaces are the Script SDK surface (Debug, World, Warehouse, Match, Events, UI, ...) - discover exact signatures via engine_get_sdk_function_signature / engine-reference/script-sdk.
  • set score = add(score, 1); mutates a declared var; let bindings are local to the handler.
  • Component patches go through component <Type>.patch({...}) with canonical component fields (see engine-reference/component-types).
Was this helpful?Report an issueContact support

On this page