Wall & zones
The wall is a runtime setting
Section titled “The wall is a runtime setting”Walls are built from panels and installations differ in size, so neither side may hard-code the wall. The engine owns the physical installation and reports it once at startup, before any mode is loaded:
/wall/config iiiiiiff columns rows panelColumns panelRows areaFirstColumn areaColumns widthMeters heightMeters/wall/blanks i* every grid position with no holdBoth are rate: state, sent in one bundle, and re-sent on /sys/sync. Every
hold index anywhere in the protocol means “an index into the most recent
/wall/config” — holdCount is columns × rows.
The numbers in schema/protocol.yaml describe a reference installation.
They drive this site, the mock sender and the monitor’s defaults. They are not
constants, and the generated code does not present them as constants:
- SuperCollider:
~oscWallstarts as the reference wall, and the generated/wall/configresponder overwrites it before your handler runs. - Engine: the helpers take the live geometry as arguments
(
Osc.HoldIndex(column, row, columns)); the reference values sit in a separateOsc.ReferenceWallclass for tests.
Hold numbering
Section titled “Hold numbering”Unchanged from 0.1: zero-based, bottom-left origin, row-major, across the whole wall — decorative columns included. The index of a hold therefore never changes when the interactive area is reconfigured, and a saved route survives a change of play area.
The interactive area
Section titled “The interactive area”The use cases distinguish the central, mappable area from decorative columns either side — Draw & Climb prints only the central part, and the side columns show a gradient. The protocol makes that a wall property rather than a Draw & Climb detail, because every mode needs to know where gameplay can happen:
- Modes place gameplay holds only inside the area.
- Zones split the area, not the whole wall.
- The decorative columns still report touches through
/wall/hold/touch; it is up to the mode whether they mean anything.
A wall with no decorative columns simply sends areaFirstColumn 0 and
areaColumns = columns.
Chase the Shape and Mirror split the area into 1–4 equal vertical strips, one child per strip. Zone 0 is leftmost.
zone z of n covers columns areaFirstColumn + floor(z × areaColumns / n) .. areaFirstColumn + floor((z + 1) × areaColumns / n) − 1The split is computed, never sent. The zone count is a mode init param
(zoneCount), and both sides derive the strips from it with generated helpers
— ~zoneColumns / ~holdZone in SuperCollider, Osc.ZoneColumns /
Osc.ZoneOfColumn in the engine — so they cannot disagree about which zone a
hold belongs to.
Zone indices in messages are declared ref: zone, so the monitor checks them
against the zoneCount of the last /mode/load it saw.
/wall/config.
Physical size
Section titled “Physical size”widthMeters and heightMeters let SuperCollider place a sound between the
speakers by real distance rather than hold count — on a 12-metre wall a hold
two columns from the edge is a very different place from the same hold on a
3-metre one.
Speakers
Section titled “Speakers”Speakers are SuperCollider’s hardware, not the engine’s, so their layout lives
in SuperCollider’s own configuration; the reference layout is on the map above.
The engine only trims levels during installation with /audio/speaker/volume.
Nothing in play addresses a speaker — SuperCollider pans sounds to holds, and
works out which speakers that means.