The studio, control by control
Open http://127.0.0.1:4600 — screenbook serve redirects straight to the studio at
/screenbook/.

Top bar
| Control | What it does |
|---|---|
| ⧉ Feature ▾ | Switches the active feature (one folder under features/ = one entry). Embedded apps appear here too. |
| iPhone | Android | Web | The segmented device picker — one device is always active: the sidebar filters to it, multi-device screens re-frame to it, and segments gray out when the feature has no screens for that device. Picking a device hops to its first screen if the current one doesn't render there; navigating to another device's screen pulls the picker along. Hidden when the project declares one device (and for app features). |
| 🎭 Scenario ▾ | Applies a named data overlay from the feature's scenarios.json — empty states, mid-journey, edge cases. The screen reloads with the merged data. Embedded apps can expose their own scenarios here. |
| 🎨 Theme Lab | Docked panel: every token of the active theme, editable live against the hosted screens — color pickers, Export JSON, Save to themes/<id>.json (under serve), Revert, theme switcher when several themes exist. |
| ◐ Color mode | System / Light / Dark — System is the default and follows your OS live (flip macOS appearance and the studio flips with it). Picking Light or Dark pins it, and only a pinned mode travels in deep links. Tokens flip live, no reload; the studio chrome follows. |
| ⇄ LTR/RTL | Flips direction live (dir on the screen's <html>). |
| 🌐 lang ▾ | Sets Engine.env.lang and reloads the screen so Engine.t strings rebind. Picking an RTL language flips direction automatically. Hidden for single-language projects. |
| ▶ Flow ▾ | Plays a walkthrough from the feature's flows.json: a floating bar with ←/→, step counter and the step's note. Steps can pin scenarios. Arrow keys work; ✕ exits. |
| 📌 Review | Review Mode. Click anywhere on the screen to pin a comment — it captures screen, scenario, theme, mode, direction and the exact element. The docked panel lists, edits (unresolved ones), resolves, exports; clicking a comment pinned on another screen opens that screen in its scenario. Pins sign as git config user.name (offered by serve, confirmed once on your first pin, editable in the panel header). Synced to review/comments.json under serve; localStorage otherwise. |
| ↺ | Resets the shared Engine.state store (the cross-screen KV) and reloads the screen. |
Sidebar
View map (the feature map, below) · search (/ focuses it) · grouped screen rows
(title, description, updated date, status pill, tags) · the ● live badge shows when the
CLI server's extras are active · the Self-test link runs the render matrix in your browser.
The sidebar and the docked panels (Theme Lab, Review) are resizable — drag the thin grip on their inner edge; double-click it to reset. Widths persist.
Keyboard: ↑/↓ or j/k moves between screens · ←/→ steps an active flow · Esc closes menus (or leaves the map).
Feature map
View map in the sidebar zooms out to the whole feature: every screen as a live
mini frame, connected by its real navigation. The edges come straight from the
screens — every literal data-go="…" / Engine.go('…') target is scanned into the
manifest's links at regen time, so the picture never drifts from the code.

Scroll zooms, dragging the canvas pans, dragging a node rearranges it (saved to
features/<id>/map.json under engine serve, so agents and humans share the
layout). Click selects a node and lights up its connections; double-click opens
that screen in the studio; Esc leaves the map. The map follows the device picker —
one device's flow at a time — and ?map=1 deep-links straight into it.
A screen can also point at another feature with data-go="feature/screen"
(e.g. onboarding's last step → order/010-menu). Live screens really navigate
across, and on the map the link lands on a named feature card — click it to jump
to that feature's map.
Deep links
Everything is a URL:
#feature/screen?scenario=mid-trip&mode=dark&dir=rtl&lang=ar&theme=noir&flow=tour&step=2
Share a link and a stakeholder lands in the exact state — screen, data, theme, direction,
mid-flow. ?solo=1 renders just the framed screen (used by screenshot); ?selftest=1
runs the matrix.
Device variants, groups, transitions
Screens declaring "devices": ["ios","android"] get switcher chips above the frame —
one file, several frames, and the self-test covers each. Features declaring a "group" in
feature.json cluster under section headers in the Feature ▾ dropdown. Screen switches play
a subtle 180ms entrance — disabled automatically under prefers-reduced-motion, or
project-wide with "transitions": false in app.config.json.
Device frames
The engine draws the hardware — iPhone (island, status bar, home bar), Android (punch-hole,
gesture bar), browser chrome, or a bare card. Screens pad with var(--safe-top) /
var(--safe-bottom) and never draw hardware themselves. Full-bleed screens can force the
status-bar ink with "statusBar": "light" | "dark" in their meta. Frames scale to fit the
window. Embedded apps that draw their own chrome declare "chrome": "self" and get bezel
only.
Self-test
?selftest=1 — every screen × theme × light/dark × LTR/RTL must reach Engine.ready with
its meta present and zero console errors; embedded apps must register and survive a
visit to every screen they report. The same matrix runs headlessly via
screenbook validate — treat green as the definition of done.