ONE WRITER, ONE READER
Muralista writes it. Pregonero reads it. It sits beside the gig it belongs to and names that gig, so it cannot be used for a different room by accident.
where things land on a wall
One room, one file: the surfaces on the wall, how they are shaped, and what belongs in each. visualsVersion 2.
Muralista owns where things are. Pregonero owns what is showing when. That line is the whole architecture of this file.
Muralista writes it. Pregonero reads it. It sits beside the gig it belongs to and names that gig, so it cannot be used for a different room by accident.
| key | type | what it holds |
|---|---|---|
visualsVersion | number | Exactly 2. A version this build does not know is refused, never coerced |
gigId | string | Must match the gig's id |
cameraDeviceId, cameraQuad | string, four points | The calibration: the projector's lit rectangle, marked by hand in camera space |
modes | array | Named modes, in order |
shapes | array | The mapped regions |
songVisuals | object | defaults, songs, assets |
A shape carries id, name, corners (four normalised points, clockwise from top left), outline (three or more points, the clipping ring), layer.type, visible, and mode, which is the mode it belongs to, or absent for a shape that is always on the wall.
A mode carries id, name, and when: a condition asking whether another shape is filled or empty, or null.
Modes are an ordered list, and the first whose condition is true wins. When none matches, no mode is live and only the no-mode shapes paint. Exclusivity comes from that rule, not from the conditions happening to be opposites.
A shape belongs to one mode or to none, and no mode means always on the wall.
A condition asks about content, never existence. Shapes belong to the gig and always exist; what changes from song to song is whether they were given something. Filled means an asset is assigned for that song.
A condition names another shape, not a fact about the song. Whether a song has a video is domain knowledge Muralista does not have. Muralista declares the relationship and Pregonero evaluates it.
Two things are refused rather than repaired: a visualsVersion this build does not know, and a gigId that is not this gig's. The second exists because copying last month's gig folder to start the next one gives you a mapping of the wrong room that renders perfectly and reports nothing.
The room that goes with the gig above: its calibration, its modes and its shapes. Only the camera's hardware identifier is removed.
{
"visualsVersion": 2,
"gigId": "frrw98jj8s",
"cameraQuad": [
[
0.2556401866232465,
0.13916843220338984
],
[
0.6984046217434869,
0.1490020071364853
],
[
0.7004673409318637,
0.5224339317573595
],
[
0.254156751002004,
0.5376198706512043
]
],
"modes": [
{
"id": "m-mtosdfch1xx",
"name": "Song with lyrics",
"when": {
"shape": "s-mtosdfcd7y2",
"is": "empty"
}
},
{
"id": "m-mtosdfch25j",
"name": "Song with video and lyrics",
"when": {
"shape": "s-mtosdfcd7y2",
"is": "filled"
}
}
],
"shapes": [
{
"id": "s-mtosdfcd7y2",
"name": "Video frame",
"corners": [
[
0.4000266157314629,
0.1830745428189117
],
[
0.8439887587675351,
0.1915491190900981
],
[
0.8465955348196392,
0.7225691347011597
],
[
0.4022028431863727,
0.7294686663693131
]
],
"outline": [
[
0.4000266157314629,
0.1830745428189117
],
[
0.8439887587675351,
0.1915491190900981
],
[
0.8465955348196392,
0.7225691347011597
],
[
0.4022028431863727,
0.7294686663693131
]
],
"layer": {
"type": "song-video",
"src": null,
"opacity": 1
},
"visible": true,
"mode": "m-mtosdfch25j"
},
{
"id": "s-mtosdfcgtl9",
"name": "Video lyrics",
"corners": [
[
0.4028799787074148,
0.5079449152542372
],
[
0.8462863226452906,
0.5069204393398751
],
[
0.8453665142785571,
0.7199277988403211
],
[
0.4048839867234469,
0.728569636485281
]
],
"outline": [
[
0.4028799787074148,
0.5079449152542372
],
[
0.8462863226452906,
0.5069204393398751
],
[
0.8453665142785571,
0.7199277988403211
],
[
0.4048839867234469,
0.728569636485281
]
],
"layer": {
"type": "song-lyrics",
"src": null,
"opacity": 1,
"text": "\"Wat een lekkernij zul jij zijn,\" zucht hij,\nen ik proef al het onvermijdelijke afscheid\nvan mijn modderplasherinneringen.",
"maxSize": 0.2,
"aspect": 1,
"align": "center",
"color": "#ffffff",
"outline": true,
"outlineWidth": 0.08
},
"visible": true,
"mode": "m-mtosdfch25j"
},
{
"id": "s-mtosdfcg18x",
"name": "Song lyrics",
"corners": [
[
0.3974511523046092,
0.1813182983942908
],
[
0.8447128632264529,
0.19055948929527208
],
[
0.8484742923346693,
0.7262628233719893
],
[
0.4029465180360721,
0.7281514830508474
]
],
"outline": [
[
0.3974511523046092,
0.1813182983942908
],
[
0.8447128632264529,
0.19055948929527208
],
[
0.8484742923346693,
0.7262628233719893
],
[
0.4029465180360721,
0.7281514830508474
]
],
"layer": {
"type": "song-lyrics",
"src": null,
"opacity": 1,
"text": "\"Wat een lekkernij zul jij zijn,\" zucht hij,\nen ik proef al het onvermijdelijke afscheid\nvan mijn modderplasherinneringen.",
"maxSize": 0.2,
"aspect": 1,
"align": "center",
"color": "#ffffff",
"outline": true,
"outlineWidth": 0.08
},
"visible": true,
"mode": "m-mtosdfch1xx"
},
{
"id": "s-mtoshzrj4nk",
"name": "Shape 4",
"corners": [
[
0.03330410821643287,
0.7461585637823372
],
[
0.24344783316633267,
0.7470171721677075
],
[
0.24350263026052105,
1.0286644179304194
],
[
0.03893333542084165,
1.0291522636039252
]
],
"outline": [
[
0.03330410821643287,
0.7461585637823372
],
[
0.24344783316633267,
0.7470171721677075
],
[
0.24350263026052105,
1.0286644179304194
],
[
0.03893333542084165,
1.0291522636039252
]
],
"layer": {
"type": "image",
"src": "Logo Chango Pepper - black.png",
"opacity": 1
},
"visible": true
}
],
"songVisuals": {
"defaults": {
"song-lyrics": [
"s-mtosdfcgtl9",
"s-mtosdfcg18x"
],
"song-video": [
"s-mtosdfcd7y2"
]
},
"songs": {},
"assets": {
"tragedia-de-cerdo-asado": {
"s-mtosdfcd7y2": "tragedia-de-cerdo-asado/Tragedia de Cerdo Asado.mp4"
}
}
}
}DOWNLOAD THIS EXAMPLE →This is a snapshot of one real room file, taken on 6 September 2026, with the camera's hardware identifier removed. It is a copy kept here to illustrate the format, not a live mirror — the working file goes on changing, and this one stays as it was.
This page is CC BY 4.0. The format itself carries no licence, because a file format is not the kind of thing that can be owned. Any reference code is MIT.
CC BY 4.0 →