Skip to content

Lifecycle

Two programs on two machines, started by different people in an unpredictable order, one of which will occasionally be restarted mid-session while the other keeps running. The lifecycle messages exist so that none of that requires a human to intervene.

engine SuperCollider
│ │
├── /sys/hello "wall-game 2026.3" "0.2.0" ───────▶ │ (repeats every 2s
│ │ until answered)
│ ◀── /sys/ready "0.2.0" "3.13.0" ─────────────────┤
│ │
├── /sys/assets "/Users/wall/ClimbingWall/assets" ▶│ where files live
├── [ /wall/config 20 12 5 6 2 16 5.0 3.0 ▶│ one bundle:
│ /wall/blanks ] ▶│ the geometry
├── /audio/master/volume 0.8, /audio/bus/volume … ─▶│ the mix
│ │
├── /sample/load "savanna/giraffe" "stories/…" ───▶ │ everything the
│ ◀── /sample/loaded "savanna/giraffe" 1 2.4 "" ────┤ mode will name
│ │
├── /mode/load "memory" "savanna" 4 ──────────────▶ │
│ ◀── /mode/loaded "memory" 1 "" ───────────────────┤
├── /mode/start ──────────────────────────────────▶ │

The order matters in one direction only: geometry and samples before the mode. A mode never waits for either once it has started, so a mode loaded before /wall/config pans every sound against the reference wall, and a sample named before it has loaded is silence.

The engine repeats /sys/hello every couple of seconds until a /sys/ready comes back, and SuperCollider sends /sys/ready unprompted once on boot. Those two behaviours together mean either program can start first and the pair converges on the same state without anyone touching anything.

/sys/hello carries the protocol version the engine was built against. /sys/ready carries SuperCollider’s. Each side compares and logs loudly on a mismatch.

Neither side refuses to run. A minor-version difference is usually harmless, and an installation that will not make a sound is worse than one that makes a slightly outdated sound. But the log line is the difference between five minutes and an afternoon when something does go wrong, and it costs ten minutes to build.

/sys/ping/sys/pong, once a second, carrying a sequence number.

Two missed pongs means SuperCollider is gone or its language thread is wedged. Surface that in the engine’s operator UI rather than failing silently — the failure mode without it is a wall that looks completely normal and makes no sound.

The pong carries scsynth’s CPU load as a bonus. Above about 0.8 expect dropouts, which is worth knowing before an audience finds out.

SuperCollider will be restarted mid-session, repeatedly, during development and occasionally during the installation’s life. It must come back without restarting the game.

SuperCollider restarts
├── /sys/ready ───────────────────▶ engine
├── /sys/sync ────────────────────▶ engine
│ │
│ ◀── /sys/assets … ─────────────────┤ every message
│ ◀── [/wall/config … /wall/blanks] ──┤ marked
│ ◀── /audio/master/volume 0.8 ───────┤ rate: state,
│ ◀── /sample/load … (each one) ──────┤ in startup
│ ◀── /mode/load "synth" … ───────────┤ order
│ ◀── /mode/synth/notes 0 2 4 ────────┤
│ ◀── /mode/synth/freeze 1 ───────────┤
│ ◀── /mode/start ────────────────────┤

/sys/sync is SuperCollider asking the engine to re-send everything. The engine answers by re-sending every message marked rate: state, in the same order as startup, with no bookkeeping about what the receiver might already know — that is exactly why those messages are required to be idempotent.

The engine may also push that same set unprompted at any time; no separate message is needed for it.

/sys/panic frees every running node immediately. No fade, no release, no unloading ceremony. After a panic the engine must /mode/load again from scratch.

Wire it to a physical button during installation. You will want it — during testing, when a feedback loop starts building, and on the opening night when something does something nobody predicted.

/mode/stop is the graceful version and uses the mode’s own release envelope. Panic is for when graceful is not what you need.