Skip to content

Wall & zones

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 hold

Both 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: ~oscWall starts as the reference wall, and the generated /wall/config responder 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 separate Osc.ReferenceWall class for tests.

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 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) − 1

The 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.

zone 0 zone 1 zone 2 zone 3 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 0 1 2 3 decorative interactive area decorative
The reference wall: 240 holds, 20 × 12, built from 4 × 2 panels of 5 × 6. Hold 0 (circled) is bottom-left; numbering runs along each row, then up, across the whole wall including decorative columns. Columns 2–17 are the interactive area. Shaded strips show a 4-zone split. Real walls report their own size with /wall/config.

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 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.