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

GAME_THEMING_AUDIT.md



RELEASE

planning/2.8.0/audits/GAME_THEMING_AUDIT.md

sha256 e5ec75a3b48c5cec · 20013 bytes · original held in the private archive

# GAME_THEMING_AUDIT.md — RobCo U.O.S. Stage A10 (Game-Specific Theming / Optics & Layout) > **FILED UNDER 2.8.0 — PRODUCED-BY, NOT MEASURED-VERSION.** This document *measures* an earlier codebase > (see its baseline stamp below), but it was *produced* as part of the audit/planning phase that became the > 2.8.0 overhaul. Planning artifacts are filed by the release whose work produced them, never by the version > they discuss. The version in the title or baseline is the code it examined, not the folder it belongs in. > (A 2.5.0 and 2.6.0 folder do exist, holding feature designs for features that shipped in those releases. There > is no 2.7.0 folder because no artifact has been identified as produced during 2.7.0.) > **PLAN-ONLY.** Untracked (matches `.gitignore` `*_AUDIT.md`). Implements nothing, commits nothing. > Baseline: `origin/main` @ `c458a9d` — v2.6.0 + WU-A1/A2 live, cache `…-r2`, 89+ suites. > **Owner intent:** each game should feel UNIQUE to its real-world RobCo software — per-game optics + layout + a save manager that feels native, so an FO3 campaign vs an FNV campaign (vs a future FO4) reads as a distinct terminal. > **Hard constraint:** the mechanism MUST be game-agnostic (Protocol 38, from A9) — per-game theme declared in `GAME_DEFS[ctx].theme`, driven by the active registry, so FO4 (Round 3) drops in with ZERO feature-code change. --- ## 0. CURRENT STATE (what the code does today) | Aspect | Current reality | Problem for per-game identity | |---|---|---| | **Theme application** | `changeOpticsColor(color)` (`ui-audio.js:328`) — a **hardcoded if/else chain** setting 5 CSS vars (`--robco-green-rgb`, `--robco-green`, `--robco-glow`, `--robco-dark`, `--robco-refresh`) on `documentElement.style`. | Not data-driven (A9-class hardcoding); adding/varying a theme = editing a JS branch. | | **Palette set** | 6 themes: **robco green `#14fdce` (the New Vegas software/terminal color — canon)**, amber `#ffb642`, blue `#42cbf5`, legion red `#ff4040`, ghoul `#7dff5f`, neon purple `#c084fc`. | **Correction (owner):** robco green `#14fdce` IS canonical — it's the New Vegas terminal color. It's a permanent selectable option and the FNV per-game default. The gap is only that it isn't *tied to game context* — every game currently shares one global optic. | | **Persistence** | Single **global** key `localStorage['robco_optics']`; applied on boot (`ui-core.js:313`). | **Not per-game, not tied to `gameContext` at all** — switching FNV↔FO3 keeps the same optics. | | **Duplication** | The palette is **re-declared** as `fgMap` in `ui-saves.js:11` (HTML log export). | Two sources of truth for the same colors (Protocol 22 violation). | | **Save manager** | `renderSavesList` / `ui-saves.js` / `ui-account.js` render a **uniform** save list regardless of game. | No game identity — an FO3 save looks identical to an FNV save. | | **`GAME_DEFS`** | Has `factions`, `skillKeys`, `usesKarmaCenter`, `collectibleLabel`, `calendar`, `ai.*` — **no `theme` field.** | The agnostic seam exists; theming just isn't plugged into it yet. | **Net:** the theming surface (5 CSS vars + a palette) already exists and is clean to drive from data — but it's hardcoded, duplicated, and game-blind. The fix is small and high-leverage: make it a data table keyed off `GAME_DEFS[ctx].theme`. --- ## 1. PER-GAME IDENTITY TABLE (grounded in the real RobCo/Pip-Boy aesthetics) > Aesthetic research per fallout.wiki + the games' known UI. The goal is **concrete, buildable** per-game cues — default phosphor, framing, voice, Pip-Boy identity, save treatment. | Dimension | **Fallout 3** (Capital Wasteland) | **Fallout: New Vegas** (Mojave) | **Fallout 4** (Commonwealth — Round 3) | |---|---|---|---| | **Pip-Boy model** | Pip-Boy 3000 | Pip-Boy 3000 (Mojave variant) | Pip-Boy 3000 **Mark IV** | | **Default phosphor** | **Classic / duller green (RESOLVED, owner):** a muted/darker terminal green (dimmer, olive-leaning) clearly distinguishable from NV's bright robco green — the grungier/heavier DC-terminal shade. Concrete AA-passing hex picked at build (must pass Suite 90 ≥4.5:1). | **robco green `#14fdce`** — the canonical **New Vegas software/terminal color** (owner: this IS a real canon color). FNV's per-game default. | **Brighter refined green** `#18ff90`-class (cleaner, higher-legibility Mark IV UI) — Round 3 data | | **Tint / bg** | Deep green-black, heaviest scanline/grime | The current near-black `#021c14` (NV) | Cleaner near-black, crisper bloom | | **Framing / density** | **Heavy/utilitarian** — riveted, thick borders, densest chrome (DC ruin vibe) | **Vegas** — slightly warmer/ornate accent, same density | **Clean/modern** — thinner borders, more legible spacing (Mark IV polish) | | **Boot / voice flavor** | "ROBCO INDUSTRIES (TM) … PIP-BOY 3000 … CAPITAL WASTELAND" grungier degraded-tube boot | "… PIP-BOY 3000 … MOJAVE WASTELAND / LUCKY 38 UPLINK" | "… PIP-BOY 3000 MARK IV … COMMONWEALTH" cleaner cold-start | | **Terminology nuance** | Karma Center (FO3 uses Karma); "WASTELAND" | Faction Standing (FNV reputation); "MOJAVE" / "COURIER" | (Round 3 — TBD; Sole Survivor) | | **Save-manager treatment** | Grungy header "VAULT-TEC ARCHIVE — CAPITAL WASTELAND", FO3-green chrome, heavy divider | Header "MOJAVE ARCHIVE / LUCKY 38 TELEMETRY", robco-green chrome | Clean "COMMONWEALTH ARCHIVE", brighter-green chrome | **Signature win:** FO3 = **classic/duller green** (muted/darker, olive-leaning — RESOLVED), FNV = **robco green `#14fdce`** (canon NV color, the existing default), FO4 = **brighter green** (Round 3). The "feels different" lever is **FO3 getting its own duller green** vs NV's bright robco green — that's the per-game default-on-context change. **robco green `#14fdce`, amber `#ffb642`, and the FO3 classic-green are ALL selectable options for any game** (robco green never removed). The other optics (blue/legion/ghoul/neon) remain selectable as today. --- ## 2. PROPOSALS (triaged BUILD-NOW / SPEC-FIRST / SKIP, with file-touch) ### GT-1 · Data-drive the theme palette (`THEMES` map) + dedup — **BUILD-NOW** *(quick win; the agnostic foundation)* - **Does:** Replace the `changeOpticsColor` if/else chain AND the `ui-saves.js` `fgMap` with one `THEMES` data table (each entry: `{ rgb, hex, glow, dark, refresh, label, contrastSafe }`). `changeOpticsColor(key)` becomes a table lookup + apply-the-5-vars loop; the save export reads the same table. Behavior-neutral (same 6 palettes), fixes the duplication (Protocol 22), and is the prerequisite for per-game defaults. - **Files:** `js/ui-audio.js` (`changeOpticsColor` → table-driven), `js/ui-saves.js` (use `THEMES` not `fgMap`), `js/state.js` or a small theme module (`THEMES` const — read-only), `css/terminal.css` (no change unless consolidating), `tests/check-persistence.{js,ps1}` (THEMES structural guard + no-duplicate-palette guard), `sw.js`, docs. · **Tags:** `[CACHE][TEST]` · **Severity/leverage:** HIGH (foundation). ### GT-2 · Per-game DEFAULT optics on context — **BUILD-NOW** *(the headline "feels different" win)* - **Does:** `GAME_DEFS[ctx].theme.defaultOptics` names a `THEMES` key. On context load/switch, if the user has **not explicitly overridden** optics for that game, apply the game default (**FNV → robco green `#14fdce`** = the canon NV color / current default; **FO3 → its classic/duller green** = RESOLVED, a muted/darker olive-leaning terminal green ≠ robco green; FO4 later). **Manual override preserved (Protocol 25 / UX stability):** store the user's explicit pick **per game** (e.g. `robco_optics_<ctx>` or an "explicit" flag) so a user who chose amber/neon for a game keeps it; only un-chosen games get the default. The global `robco_optics` legacy key migrates to the per-game scheme (fail-safe to current value — so existing users keep robco green). **Net behavior change is FO3 only** (gets its own duller green); FNV stays robco green. - **Files:** `js/state.js` (`GAME_DEFS[ctx].theme.defaultOptics`), `js/ui-audio.js` (apply-default helper respecting explicit override), `js/ui-core.js` (boot optics init + `onGameContextChange` hook to re-apply on switch), `tests/check-persistence.{js,ps1}` (per-game default applied; explicit override wins; migration), `sw.js`, docs. · **Tags:** `[CACHE][TEST]` · **Severity/leverage:** HIGH. ### GT-3 · Diegetic per-game identity strings (Pip-Boy model + boot + save label) — **BUILD-NOW** *(cheap immersion)* - **Does:** `GAME_DEFS[ctx].theme` carries `pipBoyModel`, `bootFlavor`, `saveLabel`. Surface the Pip-Boy model + game name in the boot sequence and the save-manager header (text only — HOUSE_STANDARD voice). Big immersion-per-byte; no layout work. - **Files:** `js/state.js` (theme strings), `js/ui-audio.js` (`runBootSequence` reads `bootFlavor`/`pipBoyModel`), `js/ui-saves.js`/`js/ui-account.js` (`renderSavesList` header reads `saveLabel`), `tests/check-persistence.{js,ps1}` (presence guards), `sw.js`, docs. · **Tags:** `[CACHE][TEST]` · **Severity/leverage:** MEDIUM (cheap, visible). **Coordinates with WU-F6 Cold-Start Boot** (same `runBootSequence`). ### GT-4 · Per-game framing / accent CSS — **SPEC-FIRST** *(bigger layout work → Round 2)* - **Does:** A `data-game="<ctx>"` attribute on a root element + `GAME_DEFS[ctx].theme.framing` ('heavy' | 'vegas' | 'clean'); per-game CSS adjusts border style/density/accent so FO3 reads heavier, FNV warmer, FO4 cleaner. Needs design + **Protocol-10 render verification at 360/412/desktop × each game** (3×N matrix) — non-trivial. - **Files:** `index.html` (`data-game` on root, set by context), `js/ui-core.js` (set attribute on load/switch), `css/terminal.css` (`[data-game="FO3"] …` blocks), `js/state.js` (`framing`), `tests/check-persistence.{js,ps1}` + `tests/render-check.mjs`, `sw.js`, docs. · **Tags:** `[CACHE][TEST]` · **Tier:** SPEC-FIRST. ### GT-5 · Game-badged / styled save manager — **SPEC-FIRST** *(the "native save manager" ask → Round 2, data hooks in 2.7.0)* - **Does:** Restyle `renderSavesList` per game — game badge per save row, per-game header (`saveLabel` from GT-3), framing from GT-4 (FO3 grungy / FNV Vegas / FO4 clean). The **data hooks land in 2.7.0 via GT-3** (saveLabel + the game already stored in each save envelope's `gameContext`); the **full visual restyle is Round 2** (depends on GT-4 framing). - **Files:** `js/ui-saves.js` / `js/ui-account.js` (`renderSavesList` per-game header + row badge), `css/terminal.css`, `tests/check-persistence.{js,ps1}`, `sw.js`, docs. · **Tags:** `[CACHE][TEST]` · **Tier:** SPEC-FIRST (badge/label = near BUILD-NOW once GT-3 lands; full restyle Round 2). ### SKIP - **Removing/relabeling robco green `#14fdce`.** It's the **canonical New Vegas terminal color** and the FNV default — keep it as a permanent selectable option for any game (label it plainly, e.g. "ROBCO GREEN", not as merely a "classic" relic). Removing it would break canon AND UX muscle memory (Protocol 25). Per-game defaults layer **on top**, not replace. - **Per-game fonts / heavy skinning.** Out of scope for the CRT house standard; would fragment the diegetic voice. The phosphor + framing cues carry the identity. --- ## 3. ARCHITECTURE — `GAME_DEFS.theme` shape (game-agnostic, Protocol 38) Per-game theme is **declared data**, not code. A new game (FO4) adds an entry; zero feature-code change. ```js // In GAME_DEFS[ctx] (state.js) — FNV shown: theme: { defaultOptics: 'robco', // FNV default = robco green (canon NV color). FO3 = 'fo3green' (classic/duller green). REQUIRED, must exist in THEMES. framing: 'vegas', // 'heavy' (FO3) | 'vegas' (FNV) | 'clean' (FO4) — CSS [data-game] hook (GT-4) pipBoyModel: 'Pip-Boy 3000', // diegetic identity (boot + chrome) bootFlavor: 'MOJAVE WASTELAND', // per-game boot line (HOUSE_STANDARD voice) saveLabel: 'MOJAVE ARCHIVE / LUCKY 38 TELEMETRY', // save-manager header } // Shared palette (read-only, single source of truth — replaces the if/else + fgMap): const THEMES = { robco: { rgb: '20, 253, 206', hex: '#14fdce', dark: '#021c14', label: 'ROBCO GREEN', contrastSafe: true }, // canon New Vegas color; FNV default; permanent option fo3green:{ rgb: '…', hex: '#……', dark: '#……', label: 'FO3 GREEN', contrastSafe: true }, // RESOLVED: a classic/duller (muted, olive-leaning) terminal green ≠ robco green; concrete hex picked at build, must pass Suite 90 ≥4.5:1 amber: { rgb: '255, 182, 66', hex: '#ffb642', dark: '#2e1d03', label: 'AMBER', contrastSafe: true }, // selectable option (not a per-game default) // … blue, legion, ghoul, neon (existing; legion/neon flagged contrastSafe:false per A2) … }; ``` - **`defaultOptics` must reference a `THEMES` key**; `framing` maps to a CSS hook. FO3 = `{ defaultOptics:'fo3green', framing:'heavy', … }` (the `fo3green` classic/duller-green hex is picked at build); FO4 = `{ defaultOptics:'green4', framing:'clean', pipBoyModel:'Pip-Boy 3000 Mark IV', … }` + a `green4` THEMES entry — **no JS branch added.** - Resolution order at runtime: **explicit per-game user pick → `GAME_DEFS[ctx].theme.defaultOptics` → `robco` fallback.** All via the active def (`_activeDef().theme`), never a game literal (Protocol 38). (Fallback is `robco` — the canon NV color and the app's existing default.) - This **also resolves A9's spirit for theming** — the if/else chain (a latent two-game-ish hardcode) becomes a data table that scales to N games. --- ## 4. CONSTRAINTS HONORED - **HOUSE_STANDARD voice:** all per-game strings (boot, save label, Pip-Boy model) stay in the diegetic register (`> `, ALL-CAPS, bracketed) — they extend the locked terminology, not add modern-web phrasing. "OPTICS COLOR" framing preserved (never "theme/dark mode"). - **A2 ACCESSIBILITY — AA contrast (checked):** every per-game **default** palette must pass AA (≥4.5:1) on the near-black field (`#010a07`/dark var). Defaults are all high-contrast: **robco green `#14fdce` (~12:1, FNV default — passes)**, amber `#ffb642` (~10:1, selectable), brighter-green `#18ff90` (~13:1, FO4). **The FO3 classic/duller green MUST pass the ≥4.5:1 contrast gate (Suite 90) before it's accepted** — a muted/darker green dims toward the threshold, so the exact hex is chosen to clear it (hard requirement). The risky optics (legion red, neon purple) the A2 audit flagged stay **manual-only, never a per-game default**, `contrastSafe:false`. - **Self-improving — gate guard (propose Suite 90, or extend Suite 89):** assert **every `GAME_DEFS` entry declares `theme` with a `defaultOptics` that exists in `THEMES`**, and **every `THEMES` entry used as a per-game default computes AA contrast ≥4.5:1** against the dark bg (static contrast-ratio assertion). Adding a non-contrast-safe or undeclared game theme then **fails the build** — a new game can't ship an illegible terminal. Both runners (Protocol 15) + count sync (Protocol 2a). - **Never bump APP_VERSION** (folds into the 2.7.0 program). **No served-file behavior break** — GT-1 is behavior-neutral; cache bump per Protocol 1 since `ui-audio.js`/`css` change. --- ## 5. PLACEMENT RECOMMENDATION (2.7.0 vs Round 2 vs Round 3) | Proposal | Tier | Placement | Rationale | |---|---|---|---| | **GT-1** palette → `THEMES` data table + dedup | BUILD-NOW | **2.7.0** | Cheap, behavior-neutral, fixes duplication, and is the agnostic foundation GT-2/3 need. | | **GT-2** per-game default optics on context | BUILD-NOW | **2.7.0** | The headline "each game feels different" win; small once GT-1 lands; preserves manual override. | | **GT-3** per-game identity strings (Pip-Boy model + boot + save label) | BUILD-NOW | **2.7.0** | Cheap text, high immersion; coordinates with WU-F6 boot. Gives the save manager its native header. | | **Suite 90** theme-declared + AA-contrast gate guard | BUILD-NOW | **2.7.0** | Self-improving; lands with GT-1/2 (the units it guards). | | **GT-4** per-game framing/accent CSS | SPEC-FIRST | **Round 2** | Bigger layout work; 3-breakpoint × N-game render matrix; needs design pass. | | **GT-5** full game-styled save manager | SPEC-FIRST | **Round 2** (data hooks in 2.7.0 via GT-3) | Visual restyle depends on GT-4 framing; the badge/label part is near-free once GT-3 ships. | | **FO4 theme** (`green4`, Mark IV, `clean`) | data-only | **Round 3** | Drops into `GAME_DEFS.FO4.theme` + one `THEMES` entry with ZERO feature-code change (proof the architecture works). | **Net 2.7.0 fold-in:** GT-1, GT-2, GT-3, + Suite 90 — three small data-driven units + a guard that deliver the per-game-optics + native-save-header identity cheaply, on the agnostic seam. **Round 2:** GT-4 + GT-5 (per-game framing + full save restyle). **Round 3:** FO4 theme as data. --- ## 6. FEEDS THE MASTER_PLAN UPDATE Fold the BUILD-NOW set into the 2.7.0 program as new work-units (suggest a small **Phase T — Theming**, or attach to Phase A since GT-1 is foundational + agnostic): - **WU-T1 · `THEMES` palette data table + dedup** (GT-1) — Phase A-adjacent (foundation; coordinates with A9/Protocol 38). `[CACHE][TEST]`. - **WU-T2 · Per-game default optics on context** (GT-2) — depends on T1 + `GAME_DEFS[ctx].theme`; preserves manual override. `[CACHE][TEST]`. - **WU-T3 · Per-game identity strings + native save header** (GT-3) — coordinates with WU-F6 (boot) + the save manager. `[CACHE][TEST]`. - **Suite 90 guard** folds into WU-T1/T2 (every `GAME_DEFS` declares a contrast-safe `theme`). Extends the born-compliant rule: a new game ships a declared, contrast-checked theme. - **Round 2 (deferred):** GT-4 framing, GT-5 full save restyle. **Round 3:** FO4 theme data. - Count impact: +3 work-units (T1–T3) to THIS BUILD; ~+6–8 tests (THEMES structure + per-game default + override + migration + contrast guard), synced both runners + docs (Protocol 2a). --- ## 7. SUMMARY FOR THE OWNER - **Per-game identity (per owner):** **FNV = robco green `#14fdce`** (the canonical NV terminal color — already the default), **FO3 = a classic/duller green** (RESOLVED — muted/darker, olive-leaning, distinct from robco green; exact hex picked at build, must pass the contrast gate), **FO4 = brighter Mark-IV green** (Round 3) — each with its own Pip-Boy model, boot flavor, save header. **robco green, amber, and the FO3 green are all selectable options for any game** (robco green never removed). - **Standout buildable quick wins (2.7.0):** (1) **per-game default optics on context** — the single biggest "feels different" change, cheap once the palette is data-driven; (2) **data-drive the palette** (`THEMES` table) — kills the if/else chain + the duplicated save-export map; (3) **per-game identity strings** — Pip-Boy model + boot + native save-manager header for near-free immersion. - **Bigger (Round 2):** per-game framing/accent CSS (GT-4) and the full game-styled save manager (GT-5) — real layout work needing a 3-breakpoint × N-game render pass. - **Architecture:** `GAME_DEFS[ctx].theme = { defaultOptics, framing, pipBoyModel, bootFlavor, saveLabel }` + a shared read-only `THEMES` palette; resolution is explicit-pick → game-default → **`robco` (canon NV green) fallback**, all via `_activeDef().theme` — **FO4 drops in as data, zero feature-code change** (Protocol 38). - **Constraints:** diegetic voice kept; **every per-game default palette passes AA contrast** (legion/neon stay manual-only, flagged); a proposed **Suite 90 guard** makes "every game declares a contrast-safe theme" a build requirement; no APP_VERSION bump. - **Next:** feeds a MASTER_PLAN update — adds WU-T1/T2/T3 + Suite 90 to the 2.7.0 build; GT-4/GT-5 to Round 2; FO4 theme to Round 3. --- *GAME_THEMING_AUDIT.md — Stage A10, plan-only. No code changed, nothing committed. FO4 theming is researched as forward input for Round 3; nothing here designs FO4 beyond its drop-in theme entry.*
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).