Troubleshooting
The studio is blank / "could not load this project".
The studio expects app.config.json one level above where it's mounted. screenbook serve
wires this automatically (the studio lives at /screenbook/, your project at /). Under a
plain static server, serve the PROJECT root — never the studio folder itself.
My new screen isn't in the sidebar.
The sidebar reads the derived features/<f>/manifest.json. Under serve it regenerates on
save; under any other server run screenbook manifest. Also check the
meta block parses (validate says exactly what's wrong).
The screen shows "Loading…" forever.
The bridge never finished its handshake — almost always a thrown error in the screen's own
script before Engine.ready. Open the screen standalone
(/features/<f>/screens/<s>.html) and read the console.
"App hasn't registered" on an embedded app.
Driven app: the driver didn't reach AppBridge.register — check
features/<id>/driver.js against the app's real globals (open the app directly, poke in
the console). Cooperative app: the include path to engine/app-bridge.js is wrong, or
register() never runs. Cross-origin apps can't be driven — serve them same-origin or make
them cooperative.
validate fails with "No headless browser available".
The checks drive your installed Google Chrome via playwright-core (bundled with the
package), and on a Chrome-less machine they download a headless browser once, automatically.
If both routes failed (offline machine, blocked download), run
npx playwright-core install chromium when you're back online.
validate is red on a screen that looks fine.
The gate is zero console errors across every theme × mode × direction. The failure row
names the combo and the first error — usually a missing guard on empty data
(d.user.name with no user in some scenario) or a 404'd asset. Screens must survive every
scenario, including the empty ones.
i18n warnings ("missing ar", "has no entry").
Warnings never block. They list exactly which keys lack which language, and which
Engine.t("key") calls have no entry in i18n.json. Fill them when ready.
Review comments don't persist.
Disk sync needs screenbook serve (the ● live badge). Under other servers, pins live in
localStorage and can be exported as JSON from the panel.
Theme Lab's Save fails.
Save needs serve too (POST /__sb/theme/<id>). Use Export under static servers.
Two status bars on an embedded app.
The app draws its own chrome — set "chrome": "self" in its feature.json.
Stale content under python http.server.
Python's server sends cache headers; hard-reload, or use screenbook serve
(no-store on everything — this problem is why).
Something engine-side looks wrong.
?selftest=1 in the browser for the live matrix; the testing map
covers every layer (npm test in a checkout of the ScreenBook repo runs the engine's own
64-test suite).