Walk a live QR code as a 3D maze. Flip land and wall modules while a real decoder reports what scanners would read. Complete ten field cases across four disciplines — the Signal Break campaign, ported from the HTML prototype into React Three Fiber.
npm install
npm run devOpen the URL Vite prints (usually http://localhost:5173).
| Script | Purpose |
|---|---|
npm run dev |
Local development server |
npm run build |
Typecheck + production bundle |
npm run preview |
Serve the production build |
- Begin Inspection → Field Ops (Tutorial / Campaign / disciplines)
- Enter a case and walk the maze (
WASD/ arrows) - Flip the tile ahead of you (
Spaceor click) - Watch Decoded in the sidebar — that is the live scanner readout
- Use Lock in score or Log result when the mission condition is met
- Land (
0) — walkable (light module) - Wall (
1) — blocked (dark module)
Progress (unlock + stars) is saved in the browser (localStorage).
| Mode | Goal |
|---|---|
| Survive | Damage the code as much as possible while it still decodes as the original — then lock in |
| Hijack | Retune modules until the scanner reads a different target message (fewest flips vs par) |
| Break (Kill Shot) | Drop the signal with as few flips as possible |
| Restore (Cold Case) | Start from a damaged code; restore the original reading |
Ten cases · 30 ★ max. Ranks unlock on the final report.
1st / 3rd person (relative to facing):
| Input | Action |
|---|---|
W / ↑ |
Move forward |
S / ↓ |
Move backward |
A / ← |
Turn left 90° |
D / → |
Turn right 90° |
Top-down (grid-absolute):
| Input | Action |
|---|---|
W / ↑ / A / ← / S / ↓ / D / → |
Step that way (facing unchanged) |
Q |
Turn left 90° |
E |
Turn right 90° |
Orbit (grid-absolute):
| Input | Action |
|---|---|
W / ↑ |
Face north + step |
S / ↓ |
Face south + step |
A / ← |
Face west + step |
D / → |
Face east + step |
Q |
Turn left 90° (no step) |
E |
Turn right 90° (no step) |
| Input | Action |
|---|---|
Space or click |
Toggle the tile ahead |
R |
Reset case |
1–4 or C |
Camera mode |
V |
Cycle environment |
T |
Cycle color palette |
L |
Toggle light / dark scene |
| ☰ menu | Camera, environment, palette |
| ← Cases | Return to Case Files |
Pointer lock (1st & 3rd person): first click captures the mouse; later clicks toggle. Orbit: right-click toggles; drag to orbit the maze.
- Signal Break campaign: cover, case map, results, final report
- Live jsQR decode of the maze grid
- Four camera modes, five environments, five palettes
- Diff / hint overlays on the aerial map
- Procedural Blockman character + per-environment tile flip FX
CampaignProvider → screens (cover / map / result / final)
→ play: MazeGameProvider + Canvas + MazeSidebar
cases.ts → caseSession.ts → encode / damage / hints
qrDecode.ts → jsQR after each toggle
scoring.ts → stars → localStorage via useCampaign
Prototype reference: signal-break.html (2D). Game rules and case list match that source.
Edit src/cases.ts — append a SignalCase (mode, ec, text, optional target / hintMode / damageRatio). Session build and scoring pick it up automatically.
Same as before: environments.ts + environment/*, or themes.ts.
| Package | Role |
|---|---|
react / react-dom |
UI + campaign |
three / @react-three/fiber / @react-three/drei |
3D |
qrcode-generator |
Encode |
jsqr |
Decode |
vite + TypeScript |
Build |
- Standalone client app — no backend
- Internal docs live in
/docs(not for public push without/pub-*) - QR primer (encoding, EC, advanced features):
docs/QR_CODES.md postcss.config.jsis empty on purpose (avoids parent PostCSS bleed)
Private project — all rights reserved unless otherwise noted.