GENERATED VIEW · PRIVATE ARCHIVE · DO NOT SERVE
RobCo Industries · Archive Museum

FO3_PIPBOY_DESIGN.md



RELEASE

planning/2.8.5/designs/FO3/FO3_PIPBOY_DESIGN.md

sha256 33ec1d2614aed87c · 20304 bytes · original held in the private archive

# FO3 PIP-BOY 3000 — The True Recreation (Design of Record) > **Design document only — nothing here ships.** Fifth pass, and the real one: the owner > ruled *"why not make it actually laid out like the pipboy? I want a genuine recreation. > down to the panels fitting into the UI as well."* This document is rewritten around that > brief. Canonical mockup: `planning/mockups/fo3/fo3-pipboy-true.html`. All prior passes > (`fo3-pipboy-mockup.html`, `fo3-body-{a,b,c}-*.html`, `fo3-body-final*.html`) are history — > useful only as the record of what didn't work and why. Grounded in `dev` @ `709a96c`. > Next: Opus audits this against the real code; Sonnet builds it. NV IS UNTOUCHED THROUGHOUT. --- ## 1. The two ideas everything hangs on **The orientation split.** The Pip-Boy screen is landscape (~4:3); a phone is portrait. Every compromise in passes 1–4 came from fighting that. So we stop: - **LANDSCAPE = the true Pip-Boy** — the primary FO3 view, a genuine recreation. Deciding viewport: **780×360** (the owner's phone rotated). - **PORTRAIT = the LEGACY VIEW** — the existing flat/plain layout, unchanged. No squashed compromise object exists anymore. - Rotating is diegetic — you turn your wrist to look at a Pip-Boy. Pure `@media (orientation: …)` CSS; no JS branching. **The thesis: NV puts the machinery ON THE GLASS; FO3 puts it IN THE CASING.** NV's screen is full of instruments (faders, weigh bridge, dials). The real Pip-Boy screen is **austere** — flat phosphor text, boxed outlines, dash-connected rails, `▲▼` arrows, plain-text actions with symbols. All the tactility lives in the body: the lamps, the knob, the gauge, the toggle. FO3's on-screen controls get **simpler**, not more elaborate — faster to build AND more faithful, and it is what makes the two skins different *machines* rather than different paint. --- ## 2. The two measurements (taken first, headless, 780×360) | Question | Measured answer | What it forced | |---|---|---| | Is 360px of height enough for hood + bar + glass with a top strip, a sub-tab rail, AND a list-and-detail split? | **Yes.** Glass inner: **634×262px**. Top strip 23 + sub-rail 32 → **content region 207px tall** — comfortably 6 list rows + a full detail pane with actions. | Hood thinned to **24px**; lamp bar to **52px** (domes 24px, stamped labels above); fins to 9px; the gauge and knob moved **off the bottom entirely onto the left rail** (86px wide — width is the cheap axis in landscape). The `▲▼` steppers had to go **horizontal** (`[▼][val][▲]`, each arrow 28×28) — the classic stacked-arrow stepper is untappable in a 28px row and failed the probe at 14px. | | Does the Vault Boy figure fit with six labelled limb boxes? | **Yes — 193px tall rendered, no compact pose needed.** Landscape is the gift: the limb boxes flank the figure (3 left, 3 right) with leader lines, and the vitals column sits beside them. | Nothing cut. The figure + 6 boxes + HP/RAD/effects all fit the 207px content region with room. | Verified at capture: zero overflow, zero page scroll, every tap ≥28px, 16px inputs, portrait correctly hands off to the legacy card. --- ## 3. The structure — 11/6/6 boards onto 5/5/5 rails Three domed lamps (the only nav on the bar), each opening a 5-sub-tab rail **inside the glass**. The groupings are more authentic than the current stack, not a compromise of it: **STATS lamp (OPERATOR, hotkey 1) — 11 boards → 5 sub-tabs** | Sub-tab | Absorbs | Layout | Note | |---|---|---|---| | STATUS | Vital Telemetry + Skeletal Harness + Status Effects | **full-bleed: the Vault Boy figure** | three boards BECOME the thing they were imitating — HP, rads, limb boxes, effect chips arranged around the figure | | SPECIAL | S.P.E.C.I.A.L. Tuning | full-bleed 7-row list | inline meters + boxed value + `▲▼` per row (tap parity) | | SKILLS | Skill VU Array + Skill Books + Magazines | list + detail | inline `▲▼` per skill row; books/mags = the read-tracker sub-list with `[X]` toggles | | PERKS | Perk Loadout + Traits | list + detail | `[+ ADD PERK]` boxed autocomplete (16px), `REMOVE ▢` per row | | GENERAL | Position & Clock + Faction Standing + Karma | list + detail | FO3's real General tab IS the karma/rep screen; faction rows carry inline fame/infamy `▲▼` | **ITEMS lamp (OPERATIONS, hotkey 2) — 6 boards → 5 sub-tabs** | Sub-tab | Absorbs | Layout | |---|---|---| | MANIFEST | Cargo Manifest (+ ammo) — the Weapons/Apparel/Aid/Misc/Ammo drawers become the **filter row inside the tab** (they already are the drawers) | list + detail + actions | | CRAFT | Field Fabrication | list + detail, `CRAFT △` | | BARTER | Barter Uplink | full-bleed form (a calculator isn't a list) | | SQUAD | Squad Roster | list + detail | | CURIO | Bobblehead Archive | tracker rows, inline `[X]` | **The Weigh Bridge needs no tab** — carry weight rides the top strip (`Wg 142/230`), exactly where the real device puts it. **DATA lamp (DATABANK, hotkey 3) — 6 boards → 5 sub-tabs** MAP (cartography, **full-bleed** — a map is not a list) · QUESTS (Directive Registry) · NOTES (Field Notes) · LOG (Campaign Chronicle + Service Tally, read-only as today) · QUERY (Catalog Query). **The other subsystems are CONTROLS ON THE BODY** (kept from pass 4 — the breakthrough): | Subsystem | Control | Placement | Active state | |---|---|---|---| | UPLINK [4] | the big black ribbed **KNOB** | left rail, bottom | needle swings to the amber 98.3 detent, ring glows, **all three lamps go dark** — you're on the radio | | CHASSIS [5] | the white-face red-needle **GAUGE** | left rail, top | phosphor ring around the dial | | SETTINGS [6] | the **flick TOGGLE** | right column, under the arc rail | lever drops to the amber position | **DIR IS CUT FROM FO3** — a directory listing is a desk-terminal concept; a Pip-Boy has none. The a11y promise holds without it: three lamps → sub-tab is never more than 2 taps deep, and **hotkey [0] still opens the flat directory** (behavior preserved, invisible affordance; the modal itself is shared app furniture). Every control carries its real name stamped beside it (clarity outranks flavor); every subsystem is one tap; hotkeys [1]–[6]/[0] route through `selectSubsystem()` unchanged; the scattered controls remain one `role=tablist` (display:contents — a knob that selects a view is still a tab); the 5-sub-tab rails are a second-level `role=tablist` inside the glass. --- ## 4. The screen anatomy & the FO3 control language Every tab, same skeleton: **top strip** (boxed phosphor segments — view name + LVL, HP, Wg, RAD, Caps) · **content** · **bottom sub-tab rail** (dash-connected, active boxed). **List-and-detail where the content IS a list; full-bleed where it isn't** (STATUS figure, MAP, BARTER form, SPECIAL's 7 rows). The control language is deliberately SMALL — four primitives, reused everywhere, never bespoke per board: 1. **The stepper** — `[▼] [boxed value] [▲]`, horizontal, every arrow 28×28 (measured constraint, §2). 2. **The boxed field** — 16px text input in a phosphor box (search, add-perk, notes, location). 3. **The toggle** — `[X] / [ ]` inline on tracker rows (books read, curios acquired, tactics). 4. **The action** — plain text + symbol in the detail pane: `EQUIP ✕ · USE ◯ · CRAFT △ · DROP ▢` (straight off the reference's own `Equip ✕ / Drop ◯ / Repair △`). Selected list rows get the thin boxed outline + `►` cursor. That is the entire vocabulary. --- ## 5. The Vault Boy figure Original inline SVG (zero assets, ~20 shapes): standing figure in the FO3 outline style — phosphor stroke, round head, hair swoosh, dot eyes, the grin, tapered torso with belt, one arm down, **one arm up in a thumbs-up** — plus five limb condition boxes (HEAD, L.ARM, R.ARM, L.LEG, R.LEG) with leader lines, `[████] OK / [▒░░░] CRPL` bars, crippled state red and blinking (plain `@keyframes`, reduced-motion-neutralized). **The boxes are buttons** — tap toggles the limb state, same one tap as today's harness. The SVG strokes use the phosphor token, so it re-tints with the optic and is themeable per game off the same shapes. --- ## 6. ⚠ THE EDIT AUDIT — how editing survives on all 15 sub-tabs The invariant: *if you can change it today, you can change it in the Pip-Boy — in no more taps than now.* Verdict per sub-tab (**✓ parity** = equal taps; **⚑ FLAG** = honestly flagged, never silently downgraded): | # | Sub-tab | Edits | Verdict | |---|---|---|---| | 1 | STATUS | HP/RAD steppers inline; limb boxes ARE toggle buttons; effects chips + `+ ADD` | **✓ parity** | | 2 | SPECIAL | inline `▲▼` on each of the 7 rows (no select step) | **✓ parity** | | 3 | SKILLS | inline `▲▼` per skill row; read-tracker `[X]` inline | **✓ parity** | | 4 | PERKS | add via boxed autocomplete; `REMOVE ▢` per row | **✓ parity** | | 5 | GENERAL | location/clock boxed fields; faction rows inline fame/infamy `▲▼`; karma stepper | **✓ parity** (11 faction rows carry the steppers inline, not in detail) | | 6 | MANIFEST | actions in detail: `EQUIP ✕ / USE ◯ / qty ▲▼ / DROP ▢` | **⚑ FLAG: +1 tap on the FIRST action per item** (today's inline row buttons act without selecting; here you select the row, then act — equal from the second action on, and rapid qty runs are equal). Mitigation if the owner wants strict parity: a compact inline EQP glyph on each row alongside the detail actions. Owner call. | | 7 | CRAFT | select recipe → `CRAFT △` | **✓ parity** (today is select-then-craft too) | | 8 | BARTER | boxed value fields, full-bleed form | **✓ parity** | | 9 | SQUAD | affinity `▲▼`, tactics `[X]`, `DISMISS ▢` in detail | **⚑ FLAG: same +1-first-action class as MANIFEST** | | 10 | CURIO | `[X]` acquired toggles inline on tracker rows | **✓ parity** | | 11 | MAP | full-bleed; tap nodes = TRAVEL / MARK SURVEYED as today | **✓ parity** | | 12 | QUESTS | `+ ADD` boxed input; status CYCLE in detail | **⚑ FLAG: cycle is +1 on first action per quest** (same class) | | 13 | NOTES | list + detail edit box | **✓ parity** | | 14 | LOG | read-only | **✓ (read-only today too — the one legitimately read-only tab)** | | 15 | QUERY | boxed search input + results | **✓ parity** | **One flag class, three tabs** (MANIFEST/SQUAD/QUESTS): the master-detail select step costs one extra tap on the *first* action per item, equal thereafter. The reference itself blesses detail-pane actions, and the common rapid case (qty runs) is at parity — but it is a real deviation from the letter of the rule, so it is flagged, with the inline-primary-glyph mitigation priced in. **No tab goes read-only.** --- ## 7. ⭐ THE TEMPTATION LIST — every place this design wanted to fork per-game *(Discipline 4 — this list IS the spec for the future N-game abstraction, written from evidence. Each entry: what tempted a fork, and how FO3 resolves it without one.)* 1. **The nav skeleton itself** (NV: 7-keycap row · FO3: 3 lamps + knob + gauge + toggle) → both markup blocks exist in the shared DOM, display-gated by `[data-game]`. *Future abstraction: a per-game "nav layout" partial selected by `identity.machine`.* 2. **Where the live status text lives** (NV: bezel telemetry LCD · FO3: in-glass top strip) → ONE writer (`_bezelTelemetryText()`), two projection targets, CSS decides which shows. 3. **Which stats ride the strip** (FO3 adds `Wg` because the Weigh Bridge folded into it) → an `identity.statusStrip` field list, not code. 4. **Sub-tab rails / board grouping** (FO3 groups 23 boards onto 15 rails; NV shows boards as a stacked page) → a per-game *board-grouping map* in identity (`rails: {stats:[…]}`); the boards themselves are shared. 5. **Orientation behavior** (FO3: landscape-true/portrait-legacy · NV: agnostic) → an `identity.orientation` flag driving which layout the orientation query activates. 6. **The control skin** (NV faders/steppers · FO3 `▲▼` boxes) → one shared handler set; per-game **control-kit CSS classes**; the temptation is per-board bespoke controls — the 4-primitive language (§4) is the fence. 7. **The figure** (FO3 Vault Boy · NV zone plate · a future game's silhouette) → per-game inline SVG blocks in shared markup, display-gated; strokes on the phosphor token. 8. **List-row treatment** (selected-row box + `►` vs NV's tracker rows) → control-kit CSS. 9. **The DIR affordance existing at all** (cut on FO3) → `identity.nav.hasDirectoryKey`; hotkey [0] stays wired app-wide regardless. 10. **Sounds** (rotary detent, dead-lamp thunk vs key click) → `identity.audio` facets (already data). 11. **Motion textures** (DETENT-ROLL vs phosphor smear on the same SWEEP verb) → already `identity.motionTexture` + `[data-game]` keyframes. 12. **Boot flavor, empty-state voice, Overseer framing, cursor** → already identity data (shipped stubs; refresh per this design). 13. **Hotkey glyph presentation** (NV etched `[1]` on keycaps · FO3 stamped labels, no visible numbers on lamps) → aria-labels keep the hotkey text; visual glyphs are CSS content from identity strings, never literals. 14. **The wire/accent color and its *usage sparsity*** (NV amber = ambient wire · FO3 amber = exactly one lit lamp + tuned knob) → the token is per-game (`--bezel-wire`); the discipline of WHERE it's spent is per-skin CSS. 15. **Per-game panel *presence*** (FO3 hides nothing NV shows — but a future game might) → already `GAME_DEFS` capability flags (hasTraits, hasMagazines…); the rails map (item 4) must consume them so a rail drops absent boards. **Owner real-device landscape feedback pass, round 2 (room reclaim + Vault Boy) adds these:** 16. **The Vault Boy figure as a duplicate limb-toggle control.** Tempted to give the figure its own tappable limb hit-areas (closer to the reference's own clickable body). Resolved: the figure is purely decorative (`aria-hidden`); the REAL toggle stays the five existing `toggleLimb()` buttons, CSS-flowed to flank the figure via `order` + `display:contents` on their wrapper divs — one control, one id, one state path (Protocol 22), never a second interactive surface duplicating the same five booleans. 17. **The sub-tab-rail-overlays-content fix as a JS scroll-position hack.** Tempted to patch the bug by having JS clamp scroll position or toggle a class when content got "too close" to the rail. Resolved: the real defect was structural (`position:sticky` sharing a scroll container with taller board content) — the fix is a plain-layout wrapper div (`#fo3BoardScroll`) plus three flex `order` values, zero JS, zero new state to keep in sync with scroll events. 18. **The KARMA CENTER real-label leak** (literal `(FO3 — karmaCenterDisplay)` text on screen — the internal element id AND a hardcoded game literal, both violations at once) → the plainest possible fix: swap it for a real-world term like every other real-label on the page. *Future abstraction: a lint-style guard that a `.real-label` span's text can never match an `id="..."` pattern would catch this class of leak before it ships.* 19. **Reclaiming header/strip space as a JS visibility toggle keyed on subsystem.** Tempted to write a small `_fo3HideChromeFor(subsystem)` helper that JS-toggles the casing-top / carrier-strip / Director-Uplink-header visibility per subsystem. Resolved: all three are unconditional `display:none` under `[data-game='FO3']` landscape — no subsystem-keyed branching needed, because none of the three ever belonged on the Pip-Boy screen in ANY subsystem, so a static rule is both simpler and strictly correct. **We deliberately do NOT build this framework now** — FO3 is built concretely; the abstraction is extracted later from two real machines. The four disciplines hold meanwhile: never hardcode `FO3` anywhere; **the FO3 skin gets its own numbered CSS file** (slot ~12, e.g. `12-fo3-pipboy.css` — a third game ADDS a file, never edits one); every flavor string in `identity`; this list stays maintained. --- ## 8. Identity data (refresh of the shipped FO3 stubs) Palette: phosphor `green3 #4fb05a` (shipped default; figure/strips/rails all ride the optic token) · **the amber `#ffa030`** — spent ONLY on the lit lamp, the tuned knob, the toggle's active lever, the UPLINK lamp dot, and warm accents (`UNEQUIP`, RAD readouts). Shell: weathered olive castings (`#4a5132 → #22270f`). Motion: SWEEP texture = `detent-roll` (vertical hold slip, overlay-only). Audio: `humFreq 55`, `navClick: rotary-detent`, a dull *dead-lamp thunk* for lamp presses. Boot: the Vault-Tec POST (authored in pass 3, unchanged — it ends `CARRIER ACQUIRED — GALAXY NEWS RADIO 98.3 MHz` / `WELCOME BACK, VAULT DWELLER`). Serial flavor: `UNIT PB3K-101-77 · VAULT-TEC ISSUE — VAULT 101` + the scratch *"happy 10th birthday, kiddo — love, dad"* (desktop casing has room; landscape phone may carry it on the left rail as a micro-etch — owner call). Cursor: `pipboy-reticle`. Overseer: `OVERSEER UPLINK / GNR RELAY · 98.3 MHz` (shipped stub, kept). --- ## 9. Risks & worries (the Opus audit's first stops) - **The rails are new INFORMATION ARCHITECTURE, not just chrome.** Grouping 23 boards onto 15 sub-tabs means per-game *composition* of shared boards. The clean mechanism: boards keep their one shared markup; FO3's rails show/hide them per sub-tab via the grouping map (temptation item 4). This is the unit's real engineering risk — panel visibility today is tab-based (`data-tab`); the sub-tab layer adds a second axis. Must not fork the render pipeline (Protocol 22/23). - **Landscape-primary is new for the app.** The shipped app has no orientation-specific layout; the desktop-gate media queries key on width+hover. The FO3 landscape layout must gate on `(orientation: landscape)` scoped under `[data-game='FO3']` without disturbing NV or the desktop shell. Real-device verify (Protocol 10/29-class caution): browser chrome in landscape (URL bars, notches/safe-areas) eats height — test with `100dvh` on the real phone, and PWA standalone mode is the true target (no browser chrome). - **The edit-flag class (§6)** needs the owner's explicit sign-off on the +1-first-action tap for MANIFEST/SQUAD/QUESTS, or the inline-glyph mitigation ships with it. - **Second-level tablist a11y**: lamps tablist + sub-rail tablist must be distinct, labelled, and axe-clean; the scattered-controls `display:contents` tablist needs the same verification flagged in pass 4. - **The counter-rotated glass** (±0.7° here) — same real-device crispness check as pass 4; retreat is 0° with lighting + arm carrying the read. - **Scope**: this is the largest FO3 unit yet (new IA + skin + figure + control kit). Cut order if hot: the cant → the arm → gauge sway/roller dressing → SKILLS/PERKS/GENERAL ship as re-skinned stacks before full rail-composition lands (the rails can arrive per-tab). --- ## 10. Artifacts & open questions **Canonical mockup:** `planning/mockups/fo3/fo3-pipboy-true.html` — landscape 780×360 primary; desktop landscape centered; portrait shows the legacy handoff card. Fully built: STATS>STATUS (figure, editable limbs/HP/RAD), STATS>SPECIAL (inline-stepper editing), ITEMS>MANIFEST (drawers + list + detail + actions); other sub-tabs are austere placeholders naming their real boards. Params `?tab=…&sub=…`, hotkeys [1]–[6]/[0]. Screenshots: `fo3-true-780x360-{status,special,items,uplink}.png`, `fo3-true-desktop-status.png`, `fo3-true-portrait-legacy.png`. *(All `fo3-body-*` and `fo3-pipboy-mockup.html` files = history.)* **Open questions for the owner:** 1. The §6 flag class — accept +1 first-action tap on MANIFEST/SQUAD/QUESTS, or ship the inline primary-action glyph on rows? 2. The birthday scratch's landscape home (left-rail micro-etch vs desktop-only). 3. Lamp sub-labels (OPERATOR/OPERATIONS/DATABANK) — keep visible under the domes (current), or aria-only once learned? 4. The cant (−0.7°) — keep pending real-device crispness, or drop?
STAMP · generated for RELEASE v2.8.5 commit 06e5180 (06e51801b38a) · archive input-tree hash c07fbfbdd2e1ddeb · 754 files · no wall-clock timestamp (regenerates identically when nothing changed).