# Guassia Script v1

Guassia Script adds creator-written rules to Gaussian worlds. Open **Game tools → Game scripting** in the world editor. Start with an example, edit the JSON, select **Check program**, then **Apply program** and play. Applying changes the current draft; use the main Save control to persist it on your device. A downloaded website ZIP preserves the program and the trusted player implementation. Importing the ZIP restores editable program data and never executes code supplied inside that ZIP.

New worlds contain no rules. Goals, stories, NPCs and scripts remain optional. The same trusted player interpreter can be packaged with a desktop game. This is a restricted, deterministic JSON language, not arbitrary JavaScript, Python, C++ or a claim of unrestricted professional scripting. It provides no browser, filesystem, account, payment, DOM, host-function or network capability. Script data cannot change the interpreter or expand its quotas. Native plugins and arbitrary native code are not enabled.

## First interaction

1. Place an object and find its ID under **Available IDs**.
2. In **Objects, notes & doors**, select that object, choose **Script interaction** and apply it. This makes it an E/tap target without attaching an automatic note, door or ending.
3. Load **Interactive color switch**. The example uses the first object in the world; change `target` to your chosen object's ID if needed.
4. Check, apply and play. Interact to switch the instance tint. Restart restores the original tint and all script variables.

Object IDs, room IDs, sound IDs, achievement IDs and trigger IDs are validated when applying, importing and starting the player. If a referenced item is removed, validation stops the save instead of silently redirecting the rule. Update or remove the reference first. A script changes instance overrides, preserving shared source Gaussian arrays.

```json
{
  "version": 1,
  "variables": { "toggled": 0 },
  "handlers": [
    {
      "id": "switch-color",
      "on": "interact",
      "target": "object-1",
      "do": [
        {
          "op": "if",
          "test": { "compare": "eq", "left": { "var": "toggled" }, "right": 0 },
          "then": [
            { "op": "tint", "target": "object-1", "color": "#de668d" },
            { "op": "set", "name": "toggled", "value": 1 }
          ],
          "else": [
            { "op": "tint", "target": "object-1", "color": "#ffffff" },
            { "op": "set", "name": "toggled", "value": 0 }
          ]
        }
      ]
    }
  ]
}
```

Replace `object-1` with an existing object ID. Programs use English keywords regardless of interface language. Creator-written notes, identifiers and source are not translated automatically.

## Events and handler options

| `on` | Optional `target` | When it runs |
| --- | --- | --- |
| `start` | None | First active world frame after start or restart |
| `update` | None | At its configured interval during active play |
| `interact` | Object ID | After a successful E/tap interaction; failed/distant interactions do not dispatch |
| `collect` | Object ID | After a collectible is actually collected |
| `room-enter` | Room ID | First active frame in a room, including initial spawn |
| `achievement` | Achievement ID | Once when an existing achievement becomes earned |
| `trigger` | Trigger ID | After an authored proximity trigger fires |
| `signal` | Signal name | When another script instruction emits that signal |

Every handler has a unique `id`, `on` and `do` array. Optional `enabled` defaults to `true`; `once` defaults to `false`. `interval` limits how often a handler may run, in seconds. Update handlers default to 0.1 seconds and require at least 0.05 seconds; other handlers default to zero. A `when` condition defaults to `true`. A skipped condition does not consume the handler's once flag or interval. Signals are queued, not recursive function calls.

There is no built-in arbitrary keyboard or mouse callback, networking, custom function call, recursion, unbounded loop, dynamic variable declaration or native plugin interface in v1. Use E/tap targets and authored proximity triggers for input.

## Values and conditions

Variables are fixed declared numeric entries, initialized from `variables`. Numbers must be finite, with absolute value at most 1,000,000,000. `{ "var": "counter" }` reads a variable. `{ "event": "time" }` reads elapsed active-play seconds; `delta` is the current frame delta capped at 0.1 seconds. `value` reads the current signal value, otherwise zero. `player-x`, `player-y` and `player-z` read the last active frame's world-space player position.

Arithmetic expressions have `op` and `args`: `add`, `subtract`, `multiply`, `divide`, `min` and `max` take two arguments; `abs`, `sin` and `cos` take one; `clamp` takes value, minimum and maximum. Trigonometric angles are radians. Divide-by-zero and nonfinite/out-of-range results pause the script.

Conditions may be `true`, `false`, `{ "collected": "key-id" }`, `{ "achievement": "achievement-id" }`, `{ "room": "room-id" }`, `{ "not": condition }`, `{ "all": [conditions] }`, `{ "any": [conditions] }`, or numeric comparisons:

```json
{ "compare": "gte", "left": { "var": "counter" }, "right": 3 }
```

Comparators are `eq`, `ne`, `lt`, `lte`, `gt` and `gte`. Empty `all` is true; empty `any` is false.

## Instructions

| `op` | Fields | Effect |
| --- | --- | --- |
| `set`, `add` | `name`, `value` | Assign or increment a declared variable |
| `if` | `test`, `then`, optional `else` | Run one conditional instruction list |
| `repeat` | literal integer `count`, `do` | Repeat a bounded list 1–32 times |
| `move` | `target`, `vector` | Add a room-local XYZ offset to the current instance position |
| `position`, `rotation`, `scale` | `target`, `vector` | Set three instance components; rotation uses radians and scale must stay positive |
| `tint` | `target`, `color` | Set `#rrggbb` tint |
| `opacity`, `dissolve` | `target`, `value` | Set a numeric expression between 0 and 1 |
| `visible`, `solid` | `target`, boolean `value` | Set visibility or collision participation |
| `door` | `target`, boolean `open` | Open/close an existing authored door; its transform and collision move together |
| `award` | `id` | Earn an existing achievement, even before its collectible requirements are met |
| `journal` | `id`, `title`, `text` | Add and show one journal entry; stable IDs prevent duplicate entries |
| `teleport` | `room` | Request the room's normal safe spawn, respecting achievement gates |
| `sound` | `sound`, `room`, optional `position`, optional `volume` | Play one imported cue; room-local position defaults to `[0,1.65,0]`, volume to 1 |
| `ending` | `title`, `text` | Show an ending without requiring a native objective |
| `signal` | `name`, optional `value` | Queue another script event; numeric value defaults to zero |

Transform and sound-position components must remain within ±1,000. Direct `move` and `position` edits are not a collision-aware character controller. They do not change an object's room membership, and an active NPC may also update its transform. Use native NPC authoring controls for patrol or pursuit; avoid simultaneous competing ownership of the same transform.

Room gates are enforced for scripted teleport. If an intentional rule should grant entry, explicitly `award` the gate's existing achievement first. Awards and ending state reset on restart. Script changes are local gameplay state, not account achievements, ownership, payment entitlements or server-authoritative security rules.

## Example: a smooth visual pulse

Use an update handler with `interval: 0.05` and this instruction. It reads absolute game time, so its phase does not depend on rendering every frame:

```json
{
  "op": "opacity",
  "target": "object-1",
  "value": {
    "op": "add",
    "args": [0.7, { "op": "multiply", "args": [0.3, { "op": "sin", "args": [{ "op": "multiply", "args": [{ "event": "time" }, 2] }] }] }]
  }
}
```

## Limits, diagnostics and restart

Programs are limited to 64 KiB, 32 handlers, 64 numeric variables, 512 syntax nodes and eight nesting levels. Repeat counts are literal integers up to 32. Per active frame the interpreter allows 2,048 interpreted steps, 128 world commands and 64 events, with at most 64 queued events. Arithmetic and conditions count toward the instruction budget. Interactions share the current frame's quota. These are work limits, not measured frame-time guarantees on every device.

Enable the player's optional diagnostics for handler count, interpreted steps, commands and a paused error. A malformed program is rejected before replacement. A runtime fault or quota overrun pauses only script execution and reports an error. Earlier valid commands from that frame remain applied until restart; execution is not transactional. Restart clears script variables, once/interval state, pending signals, scripted achievements and all ordinary world overrides. It runs the initial program again on the next active frame. Fix the program in the editor before repeating an error.

Runtime rules contain no dynamic code evaluation and are unchanged by imported assets. This reduces the capabilities exposed to third-party worlds; it is not a claim that the full engine or browser is exploit-proof. Public multiplayer rules, commerce, server-side scripts, persistent saves, a debugger with breakpoints, and native extension APIs remain separate engineering work.
