diff --git a/docs/superpowers/specs/2026-06-25-simulator-dev-mode-design.md b/docs/superpowers/specs/2026-06-25-simulator-dev-mode-design.md new file mode 100644 index 0000000..3bafe46 --- /dev/null +++ b/docs/superpowers/specs/2026-06-25-simulator-dev-mode-design.md @@ -0,0 +1,64 @@ +# Simulator Dev Mode — design + +> 2026-06-25 · session 0017 · planning-and-executing +> Anchor: leaf task (simulator dev-tooling — R2b, no upstream design needed) + +## Problem + +While previewing the experience, the operator can't choose *which* clip in an +altitude's rotating pool is shown — the server picks a random pool member on each +landing (content-pipeline §11.1). For by-eye review they want to step through every +clip in a pool on demand, and to see the engine/clip data behind what's on screen. +The RenderPlan JSON readout is also always visible, cluttering what should read as +an audience-facing preview. + +## Goal + +A single **Dev Mode** toggle at the bottom of the control panel. Off by default +(persisted in `localStorage`). When on, a panel appears directly below it with all +dev controls and data; when off, the normal view is just the experience + the three +control fieldsets. + +## Scope + +Frontend only — `simulator/static/{index.html,app.js,style.css}`. No API changes: +every datum Dev Mode shows is already available client-side (`/api/clips`, +`/api/ring`, the `/api/alteration` response, and the in-memory preload cache). The +separate `/author.html` remains the place to *edit* labels; Dev Mode is +inspect-and-select only. + +## Dev panel contents (top → bottom) + +1. **Pool picker** — a ` + + -
- RenderPlan readout -
-
+ diff --git a/simulator/static/style.css b/simulator/static/style.css index 4e41e39..69cfe18 100644 --- a/simulator/static/style.css +++ b/simulator/static/style.css @@ -66,3 +66,34 @@ input[type=range], select { width: 100%; } .dial-hub { fill: #2c3c5c; stroke: #9cf; stroke-width: 0.6; } .scale-name { display: block; text-align: center; font-size: 12px; color: #cde; } .hint { margin: 0.3rem 0 0; font-size: 11px; color: #789; } + +/* --- Dev Mode --- a single switch; all dev controls/data live in #dev-panel below it. */ +.dev-switch { display: flex; align-items: center; gap: 0.5rem; cursor: pointer; + padding: 0.5rem 0.2rem 0.2rem; border-top: 1px solid #222; user-select: none; } +.dev-switch input { position: absolute; opacity: 0; width: 0; height: 0; } +.dev-switch-track { position: relative; width: 34px; height: 18px; border-radius: 9px; + background: #2a2a2a; border: 1px solid #444; transition: background 0.15s; } +.dev-switch-thumb { position: absolute; top: 1px; left: 1px; width: 14px; height: 14px; + border-radius: 50%; background: #888; transition: transform 0.15s, background 0.15s; } +.dev-switch input:checked + .dev-switch-track { background: #1d3a2a; border-color: #2e6; } +.dev-switch input:checked + .dev-switch-track .dev-switch-thumb { transform: translateX(16px); background: #4e9; } +.dev-switch input:focus-visible + .dev-switch-track { outline: 2px solid #9af; outline-offset: 1px; } +.dev-switch-label { color: #9af; font-weight: 600; letter-spacing: 0.3px; } +.dev-panel { display: flex; flex-direction: column; gap: 0.8rem; } +.dev-panel legend { color: #4e9; } +.dev-btn { margin-top: 0.5rem; width: 100%; padding: 0.4rem; cursor: pointer; + background: #182028; color: #cde; border: 1px solid #2c3c5c; border-radius: 4px; } +.dev-btn:hover { background: #20303f; } +.dev-dl { margin: 0; display: grid; grid-template-columns: auto 1fr; gap: 0.15rem 0.6rem; font-size: 12px; } +.dev-dl dt { color: #789; } +.dev-dl dd { margin: 0; color: #dde; word-break: break-word; } +.dev-dl dd.mem { color: #4e9; } +.dev-dl dd.net { color: #fc6; } +.dev-anno { font-size: 11px; max-height: 220px; overflow: auto; + font-family: ui-monospace, monospace; } +.dev-anno .anno-row { padding: 0.2rem 0; border-bottom: 1px solid #1d1d1d; } +.dev-anno .anno-key { color: #aee6ff; } +.dev-anno .anno-key.affect { color: #e3cfff; } +.dev-anno .anno-key.measure { color: #ffd79a; } +.dev-anno .anno-meta { color: #678; } +.dev-anno .anno-empty { color: #567; font-style: italic; }