the workshop
for the ones who would build a room of their own — how the machinery is kept, and the covenants a new room signs before it joins the album.
how it is made
next.js 14 app router, typescript, tailwind kept light, zustand for the one shared store. every room is a thin page in src/app with its real body in src/components. the seas and skies are fragment shaders on webgl canvases; the surface forms are 2d canvas; the deep objects — the tourbillon, the drop — are three.js; the prose that bends around sigils is measured line by line with pretext. all of it procedural: no stock, no sound packs, no downloaded assets anywhere.
every sound comes from one web audio graph (src/lib/audio.ts) whose lfo clocks are shared with the visuals, so what you see breathes with what you hear. haptics ride the same intensity axis. and everything generated — sigil, music, flower, constellation — is a deterministic function of a small state vector: your night sounds like yours, always.
the laws a room signs
determinism from small vectors, with no model calls in the loop that renders state. procedural over assets. every meaningful change lands in at least two senses in the same frame. no controls to learn and no instructions, ever — everything discoverable by a curious hand in sixty seconds, glimmers instead of labels, nothing punished. lowercase copy holding two of the three registers: devotional, operational, oceanic.
each room honors prefers-reduced-motion, keeps its keyboard dialect, and holds at 390px. the full law is in INSPIRATION.md and AGENTS.md in the repository; the checklist in INSPIRATION.md §7 is the bar a room clears before it ships.
the shared buses
new work joins the organs that exist rather than growing private ones. src/lib/audio.ts — the one audio graph, ambient beds, one-shots, per-concern voices. src/lib/haptics.ts — the haptic bus and the ios core haptics bridge, speaking sea-words: tap, ripple, chop, roll, storm. src/lib/turbulence.ts — the shared intensity axis. src/lib/world.ts — the persistent world, where a shell planted on one shore can migrate overnight. src/lib/vessel.ts — tilt, shake, knock, flip, breath, with the candle owning permission. src/lib/gesture/ — the semantic gesture engine; rooms bind meanings, never raw pointers, and every threshold lives in gesture/core.ts alone. src/lib/scale.ts — the scale manifold: bands, detents, travel, spectral registers.
the scale manifold
the album mounts one logarithmic axis from 10⁻²² meters to the spacetime manifold: the quanta, quarks, nucleons, atoms, molecules, cells, a drop, flowers, the coast, the atlas, the earth, the stars, beyond, the manifold. within a band, pinch zooms freely and rubber-bands at the walls; crossing a wall takes sustained intent — hold the pinch through the resistance and a haptic detent marks the door. the focused object of one band becomes the container of the next, so it stays one world. scale also chooses the sound: sub-bass and minute-long lfos at the cosmic end, mids at human scale, granular shimmer among the atoms — zooming is a glissando on the site's one instrument.
composing a new room
the first decision is ordinal: find the level where the room lives on the quark→manifold axis, prefer deepening an existing band over adding a room, and branch only where containment genuinely forks. then copy src/components/RoomTemplate.tsx — a compilable scaffold already wired to every bus: gestures, vessel, audio, haptics, persistence with the quiet clear control, glimmer, keyboard, reduced motion.
register the room where the tests expect it: src/app/<room>/ (thin page + layout), src/lib/routes.ts, src/lib/site-icon-config.ts, scripts/test-routes.mjs, SCALE_BANDS when it takes a band — and its entry in this guide, with a fresh screenshot. extract the room's laws into a pure lib module and pin them with falsifiable tests only: determinism, conservation, monotonicity, round trips. docs/new-room.md in the repository is the full method.
keeping this guide true
this page is maintained under the documentation law in AGENTS.md: any change that adds, removes, or alters a room, a gesture, a bus, or an api updates src/data/guide.ts in the same pr, and re-shoots the affected screenshots with npm run shoot:guide. the test suite fails when the registry and this guide drift apart — the site cannot quietly outgrow its own account of itself.
the http api
the room’s few server offices, all stateless: each takes the current state in the request body and stores nothing. all prefer ANTHROPIC_API_KEY, fall back to GEMINI_API_KEY, and answer 503 with a hint when neither is set. the voice rules are hard-coded into every system prompt.
POST /api/ask-the-room
takes · a question (≤400 chars), plus the current concern state, region, and carried object
returns · one short paragraph, answered in the room's own voice
notes · Claude Haiku 4.5 first, Gemini 2.5 Flash as fallback; 503 if neither key is set
POST /api/imagine-entry
takes · a title (≤80 chars) and a few concern tags
returns · a new archive entry: { fn, note, body[] }
notes · same model ladder as ask-the-room; 502 if the model returns the wrong shape
POST /api/generate-music
takes · a prompt (≤500 chars) and whether to thread a sea-wash coda
returns · a short mp3 clip, base64-encoded
notes · Gemini's Lyria only — no Anthropic fallback; 503 without GEMINI_API_KEY
POST /api/generate-speech
takes · text (≤1200 chars) and an optional voice name
returns · a wav clip, spoken warm and unhurried, close to the microphone
notes · Gemini TTS only; retries once on failure
POST /api/parse-music-input
takes · loose music text and/or a photo of sheet music
returns · a normalized score plus any parsing warnings
notes · falls back to a fully local parser for text with no key; a photo needs GEMINI_API_KEY
POST /api/atlas/generate
takes · a prompt, the current atlas tile, viewport, and generation phase (preview or final)
returns · a generated tile image plus its hotspots and seeds, or a demo tile with the same shape
notes · image models (OpenAI or OpenRouter), rate-limited per visitor; runs in demo mode with no keys set, so the atlas stays playable either way