Browser-based audience interaction system for the Satosphère — the SAT's 18 m immersive dome.
Audience members scan a QR code, open a web page on their phone, tap Commencer / Start, and their device becomes a sensor/controller for the piece: accelerometer, gyroscope, orientation, touch, taps and shakes stream to the show system as OSC under a Puara-compatible namespace, consumed by ossia score and onward by SpatGRIS/MBAP or any OSC-capable tool.
This repository is reusable infrastructure, not a one-off piece: residency
artists configure interaction modes, zones, rates and OSC destinations in one
YAML file (config/puara.yaml) without touching
framework internals.
[phone browsers] --wss--> [soundworks server (Node.js)] <--ws--> [controller dashboard (browser)]
|
v (SharedState observation)
[puara-bridge (soundworks Node client)]
|
v UDP OSC
[ossia score] --> [SpatGRIS / MBAP / piece logic]
Three client roles, one server:
| role | runtime | purpose |
|---|---|---|
player |
browser (phone) | sensors + touch UI → shared state; bilingual FR/EN, wake lock, zone from QR ?zone=… |
controller |
browser | operator dashboard: live counts, per-client meters, sensor rate / interaction mode / scene controls, panic, per-zone QR codes (printable) |
puara-bridge |
node (headless) | observes all player states, computes crowd aggregates at a fixed tick, emits OSC |
The networking, state and client lifecycle layer is soundworks, an open-source (BSD-3-Clause) creative-coding framework for distributed WebAudio/web applications, developed by the {Sound Music Movement} Interaction team (ISMM) at IRCAM (STMS-LAB, Paris). soundworks was designed exactly for this class of piece — collaborative mobile web performances where dozens to hundreds of phones join a shared, synchronized environment.
What soundworks provides here:
- Distributed shared state (
StateManager): each phone owns aplayerstate; the server, dashboard and bridge observe collections of them. A dashboard change to the server-ownedglobalstate (e.g.sensorRate) propagates to every phone in well under a second — no hand-rolled protocol. - Client lifecycle & reconnection: init screens, automatic WebSocket reconnection after lock/unlock or WiFi blips, browser and Node.js clients from the same codebase (the OSC bridge is just a headless soundworks client).
- Plugins:
platform-init(iOS motion-permission flow inside the required user gesture, via@ircam/devicemotionwhich normalizes iOS/Android sensor conventions) andcheckin(unique client ids). - Tooling:
@soundworks/createscaffolding, build pipeline, and@ircam/sc-componentsweb components used by the dashboard.
References:
- Documentation & tutorials: https://soundworks.dev/
- API reference: https://soundworks.dev/api
- Source: https://github.com/collective-soundworks/soundworks
- ISMM team at IRCAM: https://ismm.ircam.fr/
- Founding paper: S. Robaszkiewicz & N. Schnell, “Soundworks – A playground for artists and developers to create collaborative mobile web performances”, Proceedings of the 1st Web Audio Conference (WAC), Paris, 2015.
The OSC vocabulary follows the conventions of the SAT's own
Puara framework for new media instruments and
installations; the full contract lives in docs/NAMESPACE.md.
npm install
npm run dev # build + watch, server on http://127.0.0.1:8000
npm run bridge # in a second terminal: OSC bridge (after `npm run build`)- Player (phones):
http://<server-ip>:8000/?zone=north - Controller dashboard:
http://<server-ip>:8000/controller - OSC out: UDP
127.0.0.1:9000by default — verify withoscdump 9000or point ossia score at it. - Emulate a crowd without phones:
http://127.0.0.1:8000/?emulate=10.
Real phones require HTTPS: browsers only expose the motion sensors and
wake lock in a secure context, and on iOS a page-level certificate exception
does not cover wss:// — so a properly trusted certificate is not optional.
docs/DEPLOYMENT.md covers the whole topic:
- dev/lab: mkcert local CA, installed once on each test phone;
- production/audience: a real hostname (e.g.
connect.sat.qc.ca) with a free Let's Encrypt certificate obtained via DNS-01 challenge — including the concrete Cloudflare + certbot recipe, renewal, and why the server never needs to be exposed to the internet; - the audience-scale WiFi checklist for the venue network team.
Everything tunable lives in config/puara.yaml:
sensorRate (ceiling, Hz), bridgeTick (aggregate/OSC tick, Hz), emitRaw
(per-device raw streams on/off), interactionMode
(sensors / touch / events-only), zones (dome sections → QR codes),
maxClients, oscDestinations. sensorRate, interactionMode and emitRaw
can also be changed live from the controller dashboard.
Environment config (port, HTTPS certs) follows the soundworks convention:
config/env-default.yaml, overridden by ENV=<name> →
config/env-<name>.yaml (gitignored except default).
src/
├── server.js # server, plugins, state classes, global state
├── clients/
│ ├── player.js # audience phone client
│ ├── controller.js # operator dashboard
│ └── puara-bridge.js # headless client → UDP OSC
└── shared/
├── schemas.js # SharedState class descriptions
├── namespace.js # OSC namespace builder (single source of truth)
├── strings.js # FR/EN UI strings
└── load-puara-config.js # config/puara.yaml loader (node side)
docs/
├── NAMESPACE.md # the OSC contract (versioned, currently 0.1.0)
└── DEPLOYMENT.md # certs, DNS, WiFi notes
Prototype (M1–M2 of the project brief): skeleton + bridge verified end-to-end on LAN. Remaining: dashboard hardening (M3), aggregate tuning with a 5-phone demo driving an ossia scenario (M4), frozen namespace + artist guide (M5). Explicit non-goals for v1: phone audio playback, puara-gestures descriptor extraction (raw + simple aggregates only — richer descriptors happen ossia-side), accounts/persistence, public-internet deployment.
BSD 3-Clause, matching the soundworks framework it is built on.
- Puara — SAT framework for new media instruments
- ossia score — intermedia sequencer consuming the OSC
- SpatGRIS — spatialization (GRIS, Université de Montréal)
- CoMo, Playground — other soundworks-based collective experiences from IRCAM