status — phase 01 is installed and has run live sessions. phases 02 and 03 were built on my own initiative, tested on a bench rig, and have not been installed.
a departmental teaching project — several teams of students and faculty building an escape room from scratch, to open to the public.
the room and its props had been designed and built over several semesters. the final puzzle called for physical computing, which sat outside what the course covered, so my supervisor asked whether I would take that piece on. I joined to build it, and it went into the room.
the two phases after it came out of watching that one run: what it would take to operate reliably during a session, and what it could become if the rest of the room could hear it.
what it does
the three phases together. only the first is in the room.
- reads real objects — five
RFIDreaders in a wooden table pick up where five props are placed. no keypad, no buttons - turns a placement into a cue — an object lands, and a sound fires in
QLaband a fixture moves inQLC+, on the moment it happened - puts the room in one browser tab — device status, placement indicators, the game clock, and a manual override for every effect
- runs three props at once — the table, a radio and a locker, on one Raspberry Pi and one
Node-REDinstance - shows the operator what it is doing — a missed tag is something the game master can see and fire by hand, rather than guess at from the other side of a wall
that is the bench build of phases 02 and 03, which is where most of this ended up. what is in the room is the table from phase 01.
that is what it is. below are the three phases in the order they were built, and what broke in each.
01 — the puzzle
physical objects. real placement. no buttons.
status — built, installed, and running as the room's final puzzle. has run live sessions.

the room needed a puzzle that responded to real objects rather than a keypad. five
RFID-RC522 readers embedded in a wooden table detect the placement of five designated
props — a trophy, sheet music, an amulet, a journal and a ring box. correct placement
lights the corresponding candle; an incorrect one triggers a rapid flash across all five.

that behavior started as a prototype. I built it, showed the team, and it is what went into the room.
built from scratch: reader integration, microcontroller firmware, and the low-voltage control circuit switching the 12V bulbs.


the part that took the longest was getting five readers to run at once — five RC522s on
one board, each holding its own state, none of them interfering with the others. that took
more research and testing than everything else in this phase together, and it had to hold
up under a table for a full session with nobody able to reach it.
it works, and it is the part of this project that has actually met players.
the version before this one
there was a larger prototype first, built out of parts: an MP3 module firing music on a trigger, a long LED sequence through a multiplexer, and an electromagnet lock on a relay that released when the puzzle was solved.
it was more than the room needed at that stage, so the scope came back to the five readers and the candles. most of the rest returns in phase 02 — the audio, the sequence, the timing — written as software rather than built out of parts.
the breadboard on the game master's desk
after the first test session a member of the faculty raised a problem. watching the security camera, they could see a candle come on but not tell which prop it belonged to — the five candles are identical and the camera is at the far end of a room.
so: five LEDs on a breadboard, one per candle, each with the name of its prop written beside it, and about fifty feet of ethernet cable out to the GM's desk. it was the quickest thing I built in this phase. the labels are the whole of it — the LEDs only repeat what the candles were already doing, and the writing supplies what the candles could never say.

it still cannot show a reader that missed a tag, which looks exactly like a player who has not put anything down yet. and the room takes no notice either way: the candles light, and the lighting and sound carry on as though nothing has happened.
that desk is where phases 02 and 03 come from — one screen instead of a bundle of wire,
with something behind it that every prop can report to. going looking for that is what took
me to Node-RED, which both phases below are built on.
02 — the scene, and the system to run it
one prop. one operator. figure out what breaks before show day.
status — built and tested on a bench rig. not yet installed.
this phase adds the two things the installed version doesn't have, and the first one is not an operations feature at all.
the candles are LEDs here — the real ones are installed in the table in the room, so the bench rig stands in for them on the same relays.
making the room respond
every placement a player makes now becomes a cue. an object lands on the table, and a
sound fires in QLab and a DMX fixture moves in QLC+, timed to the moment it happened.
all five placed correctly triggers a two-stage sequence: a two-second blackout, then a
lighting chase with atmospheric audio.
none of that exists in phase 01, where the puzzle only lights its own candles. the point of adding it is not automation — it is that the puzzle stops being a device sitting on a table and becomes part of the scene the players are standing inside.
making it operable
a player places a ritual object. the Arduino reads the RFID tag and sends a JSON state packet to a Raspberry Pi 5 over USB serial. Node-RED dispatches from there — the audio and lighting cues above, and the GM dashboard updated in the same breath.
the GM watches from a browser: what is connected, where the five placements stand, the game clock, and controls for the game as a whole — start, pause, reset the puzzle, force a win.

the five placements only report. every control on this screen acts on the whole game, so the answer to one reader missing one tag is to reset the puzzle — which takes the session back rather than the thing that went wrong. driving a single placement by hand is phase 03, and this screen is why it is there.
players get a separate fullscreen countdown served over WebSocket, on any screen on the network. it reports the time and nothing else here.


what broke, and what fixed it
the version history is the real content of this phase. every step below came out of my own build and test cycles — this is the record of finding the failures deliberately, before they could find a session.
- v1.0 — ran entirely on the Arduino, no network. confirmed the core mechanic worked before adding any complexity.
- v2.0 — MQTT over Wi-Fi and Node-RED.
QLabandQLC+triggered automatically for the first time. - v2.1 — dropping Wi-Fi mid-run froze the puzzle completely. added non-blocking connection logic so the Arduino keeps running when the network doesn't.
- v3.0 — Wi-Fi stayed unreliable across repeated test runs. dropped wireless from the Arduino entirely and switched to wired USB serial. stability over architectural elegance.
- v4.0 — running Node-RED on a laptop wasn't viable for a permanent installation. moved to a dedicated Raspberry Pi 5: smaller, quieter, no screen, stays in the room. all devices through a network switch.
- v4.2 — four bugs found in extended test runs: the win animation ran indefinitely after reset; the Arduino appeared offline during blocking animations; reset commands were dropped mid-animation; heartbeats re-triggered the win sequence every two seconds.
- v4.2.2 — fullscreen player countdown over WebSocket, auto-reconnecting, deployable on any screen on the network.
03 — one operator, three props
three props. one operator. nothing breaks mid-game.
status — built and tested, not yet installed.
a room has more than one puzzle. running each on its own tooling would mean the GM juggling several interfaces during a live session — the same problem phase 02 solves, reappearing at room scale.
testing that needed more than one prop, and the room's others were not mine to take apart. so I built two. the radio and the locker are my own, made to resemble the kind of puzzle the room has rather than to replace anything in it — a tuning dial and a lock are the two shapes a prop usually takes, and between them they cover a continuous input and a physical output. the ritual table is the real one.
all three on a single Raspberry Pi 5, one Node-RED instance, one MQTT broker. the GM sees all of it in one browser tab. the player sees none of it.
the whole phase is designed around one question — what does the operator need in order to trust the system completely?
the props here are their electronics rather than their finished selves. what is being tested is the system, not the carpentry.

the props

- ritual table — the puzzle from phase 01, now reporting JSON state over USB serial. each of the five placements can be force-activated on its own from the dashboard, which is the gap phase 02 left: a missed tag is now one click on that placement rather than a reset of the whole game.
- radio — a potentiometer on an
Arduino Nano ESP32mapped to a zone-based state machine: five looping stations separated by static, simulating analogue tuning. a semicircular dial gauge on the dashboard tracks knob position live. - locker — an Arduino driving a tongue-type solenoid lock, with a two-second maximum energisation hardcoded in firmware. triggered by a hidden player button or a GM hint. a microswitch reports drawer open/closed state back to the dashboard.



one page per prop, plus one for the room as a whole.
a prop's page carries what that prop needs: its state, and a remote control wherever it can go wrong. the ritual table gets a button per placement, the locker gets one that opens it, and the radio gets a dial reading.
the room page is the one the GM keeps open before a session, through it and after — which
props are talking to Node-RED and which are not, and the controls to start and reset the
game.

that offline pair is the point of the panel rather than a fault in it. the two things most likely to be missing on show day are the two applications the system does not own, and the GM finds that out from a screen rather than from a cue that never fires.
the clock the players watch
everything else in this phase is built for the operator. the countdown is the one part the players see, and in phase 02 it only reported the time.
it is color-coded to state — blue, then green, then red for the last ten minutes — and
turning red also starts an ambient track, so the final stretch arrives as sound as well as
color. running out puts the 00:00 into motion; escaping before it does replaces the clock
with ESCAPE!
decisions worth naming
- the radio enters a muted state on reset if the dial is left mid-position. the GM shouldn't have to remember to turn a physical knob back before every session.
- every prop runs over wired USB serial, with
udevaliases —/dev/ritualtable,/dev/radio,/dev/locker— that persist across reboots regardless of plug order. no surprises on show day. - the player display and the GM dashboard are separate fullscreen pages served from the same state, so what the room shows and what the operator sees cannot drift apart.
the whole thing, explained
that walkthrough is the longest thing here and the only place the system is shown end to end: the flow that dispatches everything, what the game master sees while a session runs, and the diagram of how the pieces are wired together.
with thanks to Playful Technology, whose RFID tutorials were an essential reference during phase 01.