Build a room for Alice
Every stage in this game is a few lines of text: a walled room, some rocks, the buttons they belong on, a lever, a gate, a door. The level maker is a page in this repository that draws it with the game's own art, proves it can be solved, and lets you play it from the keyboard the way the badge would. Make one. Send it in. It ships with the next deploy.
The maker runs from a clone of the repository on your own machine, where the keyboard is allowed to play. This page is only the invitation; the published site plays from the badge alone.
You are on a local checkout: the studio is below (behind Studio in the bar, on a phone). WASD or the arrows move, Z X C V are A B X Y, Q E the shoulders, Enter is START and Backspace SELECT. A badge on USB works too. New here? The line at the top walks you through your first room; ? lists every key.
How it goes
- Fork, then clone. A fork of your own is where your room lands first: its GitHub Pages site plays it the moment it
is merged. Node 20 or newer is all the clone needs, no packages, no build;
npm run makerserves the checkout and opens the studio. An assistant opens it in its own browser pane, beside its chat, so you watch the room and answer on the page; by hand, in your browser. - Draw, check, play. Paint with the pencil, line, rectangle and fill tools, or type the map. Check runs the real solver and says how many moves the room takes, and whether the gate earns its keep. Run & debug plays it with a simulated badge, every press logged. Surprise me draws a solvable room from a seed when you want a start. With an assistant on the bridge, a welcome banner offers three ways to a first room: Follow the White Rabbit (step by step, you hold the brush), Drink Me (four questions and it paints with you) and Eat Me (the one-bite starter); the assistant follows a written guide, so even a small model can walk you through.
- Send it in. Export writes a stage module,
stages/community/<id>.js. Add it to the index, open a pull request; the checks prove it is solvable before anyone has to play it. Or press Open a pull request with your AI in the studio: it hands your assistant the room and the steps. An assistant can do all of this with you: the studio has a bridge it drives.
What a stage is
// Stage: "A Small Garden"
//
// # wall . floor A Alice O rock
// b button L lever G gate D door
export const A_SMALL_GARDEN = {
name: 'A Small Garden',
theme: 'garden',
rows: [
'#########',
'#A..#..b#',
'#.O.G...#',
'#...#...#',
'#.L.#..D#',
'#########',
],
};
Push every rock onto a button and walk Alice to the door. A gate stays shut until she steps on the lever. A rock pushed into a corner is lost, so the order of the shoves is the puzzle. Nothing is scripted: the page proves a room with the same search the site is deployed with, and a room that cannot be solved is refused.
A timed room adds a clock and a cast: tickMs: 320 and a list of
hazards, each walking a loop one cell per tick. The Red Queen also looks ahead, so a straight line of
open floor between her and Alice ends the run. Then a plan is a schedule, and standing still is a move.
Three dressings: garden, hall, court. Rooms are between 4×4 and 24×24,
walled all round.
By hand
git clone https://github.com/bsidestlv/bsidestlv-2026-badge.git
cd bsidestlv-2026-badge
npm run maker # serves http://localhost:8080 and opens maker.html
npm run stage -- stages/community/my-room.js # what CI will say about it
The whole guide, with the format, the rules the checker applies and how a room gets onto the site: software/docs/LEVEL_MAKER.md.
The room ● playing
A level for one of the five games on glitch.html. The fields are the level; the range's own map is drawn beside them with what the rules make of the numbers. Check runs what CI runs on the shipped levels (the budgets, a replay, a hand, the attacker), Try it on the range opens it on the range page as a tab, and the export writes the module with its index line.
Click or drag to paint with the brush; right-click paints floor. Alice and the door are single, so painting one moves it. With a hazard selected, clicks lay its route instead, point by point, straight lines only; the loop closes itself. Shaded cells are where a rock is lost for good.
The tune is fixed per level (its id seeds it), so a take recorded once keeps working. The window shrinks a level at a time until only a replayed take is fast enough; the host samples the badge every 16 ms, so a press needs 34 ms to be seen.
label: a label, one tick ! line the target check ... goto x a taken branch * line crashes the guard if hit delay(n) holds n ticks ret end
Exactly one ! line, every goto to a label that exists, and every goto taken in the honest run. The good ending calls
alice_jump, the honest one alice_bounce; the check's neighbours must be harmless, and at least one line must crash.
A tick of 80 ms or more is a hand level: a hand lands within about ±40 ms.
The door compares one symbol a tick and stops at the first mismatch, so its answer time is the leak. Jitter makes one reading ambiguous (the badge's repeat takes the median); a secret order hides which symbol was wrong, not how many were right.
Every nudge must land inside the window measured from the last (or from START, for the first). Two presses of a hand are each ±40 ms off, so a hand needs 80 ms of window; the badge plays a take sped up until the gaps fit, and the first gap is the fire's offset.
The frame is name[size] [canary] lr[2], one symbol a slot. The listing must show name[size] (or
name[?] when hidden) and a line open_wall: @ … with the address, as a firmware image would.
The stages page shows the lesson under the room and ticks it off as the player does what it says.
Events: move push lever button blocked undo reset for any room, start wait tick caught restart
for a timed one, win for the door.
Start from…
Start from… the shipped levels
Surprise me
My shelf
Run & debug ● armed
✚moveBundoYwait a tickSTARTreset
The badge, simulated. Lit while a button is down, from the keyboard, a click, a real badge on USB, or an assistant over the bridge. The log is every edge and what the room made of it.
Send it in
The module goes in stages/community/ as untitled.js, plus one line in
stages/community/index.json. npm run stage -- stages/community/untitled.js
says what CI will say; then open a pull request. Or share a link: it carries the whole room in its address, and opens it
where it plays - on this checkout, or on the published site for anyone.
The assistant not connected
With npm run maker serving this page, an assistant on this machine can see the room, paint it,
prove it, play it and answer you here. Hand it the prompt under the hero (it says how to connect: the MCP tools in
.mcp.json, or curl on /__maker/); everything it does shows on the board and in this log.
Painting the Roses
Guided builds, one step at a time: pick one below. Each leads to a finished room, and each step watches what you do and ticks itself off; the line at the top of the page says what comes next wherever you are. Progress is kept per build, so switch whenever you like. Skip what you like, it costs nothing.