Themable chrome, DeckOverlay primitives, a living sitemap, and a status-discipline framework — four days of shell hardening
After Phase A+ shipped `@dididecks/shell` to its first cross-client functional state on 2026-05-12, the next four days were spent giving the shell its bones: a calmstorm-grade themable chrome (with the `--ddd-chrome-*` CSS-custom-property contract), a `<SlideCanvas>` + `/print` PDF-export route, the `<DeckOverlay--Scroll-UI>` / `<DeckOverlay--Play-UI>` paired-suffix discipline for any UI-mode-specific composition, a `context-v/sitemap/` living map that turns the shell's component+route surface into agent-readable mini-specs, and a status-discipline framework codified at the skill level that swept all nine plans into accurate state-of-record. None of this is shippable code-as-product on its own; together it's the architectural ledger that makes the next iteration tractable.
Themable chrome, DeckOverlay primitives, a living sitemap, and a status-discipline framework — four days of shell hardening
Why care?
Phase A+ shipped a working shell — TOC route, slide-rank API, decompose-stub generator, a basic /play runtime. Working but bare. The chrome was a heavy dark bottom bar that always claimed viewport real-estate. There was no way to read the shell's component surface without reading the source. The /play chooser on chroma-decks was an empty-state stub. And nine plans on disk all said status: Draft regardless of whether they'd shipped, half-shipped, or been deliberately deferred.
The four days from 2026-05-13 through 2026-05-16 made the shell legible. Themable chrome with a CSS-custom-property contract that lets every client deck re-skin without forking. Paired-variant components (<DeckOverlay--Scroll-UI> / <DeckOverlay--Play-UI>) that codify the difference between the two UI modes the framework actually operates in. A context-v/sitemap/ directory with one mini-spec per artifact — routes, components, the composition graph between them — so an agent or human landing cold can answer "what changes if I touch X" in under a minute. And a status-discipline framework promoted into the context-vigilance skill itself, then operationalized as a Maintain-Status-Discipline-Across-Context-V-Files habit at the monorepo root, then applied to all nine plans in this repo on the same day.
None of this is a feature a founder sees. All of it is the difference between a tool that's "working today" and a tool that's "still working six weeks from now when the next agent picks it up." If you came expecting a What shipped to end-users? answer, the answer is: chroma's enhanced-v2 is fully play-ported (17 of 17 slides), the /play/ chooser works, and the print route exports PDF. If you came for the architectural ledger, the rest of this entry is for you.
What's new
Themable chrome — the --ddd-chrome-* contract
<DeckChrome>(470 LOC) replaces v0.1's heavyPlayChromebar with a floating bottom-right capsule. Idle-fades to 30%; lights up on hover/focus-within. Two-axis nav (← → slot, ↑ ↓ variant), custom tooltips, tabular-num counter, full keyboard contract preserved (← / → / Space / PageUp / PageDown / Home / End / F / C / T / Esc).chrome-tokens.cssdeclares the--ddd-chrome-*namespace — 22 CSS custom properties for surface, border, type, behavior, tooltip. Neutral defaults inline at:root; per-client overrides go in<consumer>/src/styles/dididecks-chrome.cssscoped to:root[data-deck-skin="<client>"].themes/neutral.cssauthors the neutral / calmstorm-flavored default — what every consumer gets when they override nothing.PlayChromeis now a@deprecated79-LOC shim around<DeckChrome>so any in-flight imports stay green.ddd:section-changedevent contract defined in<DeckChrome>for future scroll-sidePageAsDeckWrappercoordination (Phase 2 of the Restore plan).
<SlideCanvas> + /print PDF-export route
Pure-CSS 16:9 wrapper using container queries (
container-type: size) —min(100cqw/1920, 100cqh/1080) * <stage transform>. Letterboxes correctly when canvas aspect ≠ 16:9. No JS in the scaling pipeline so rendered play decks stay static HTML/CSS and PDF-export cleanly./play/[deck]/[variant]/print/route stacks all slots vertically for a one-shot⌘P → Save as PDF. Calmstorm-pattern verbatim.
<DeckOverlay--Scroll-UI> / <DeckOverlay--Play-UI> paired-suffix discipline
Single mount point per UI mode that composes the persistent overlay affordances — classifier pill today, named slots (
nav/notes/telemetry) for future variant-cycling chrome, presenter notes (Phase 3), and engagement-pixel beacons (Phase D).The
--Scroll-UI/--Play-UIsuffix is part of the public name, not a private flag. The two are sibling files, not props on one file. Codifies how to name any future component whose UI mode matters.<DeckOverlay--Play-UI>wraps the slide content in<section data-slot data-variant>so<SlideRankPill>'s existing IntersectionObserver finds exactly one section in view — the play-mode adapter is the section wrap itself, no new code path on the pill.<SlideRankPill>gains apositionprop (bottom-rightdefault,top-rightfor Play-UI) so it can compose inside<DeckOverlay--Play-UI>without stacking on top of<DeckChrome>.
context-v/sitemap/ — the living map
13 shell-side mini-specs covering all current and adjacent components + routes:
DeckChrome,DeckOverlay--Scroll-UI,DeckOverlay--Play-UI,SlideCanvas,SlideRankPill,DididecksNav,DecomposeFirstPlaceholderand routestoc,play-index,play-slot,api-slide-rank,api-slide-decompose.Frontmatter convention with
composes:/composed_by:fields that form the composition graph an agent walks when answering "what changes if I touch X."client-sites/chroma-decks/context-v/sitemap/carries the consumer-side counterpart — 5 mini-specs for chroma's/scroll/pitch/enhanced-v3/route and three per-slide components.
Scroll-UI vs. Play-UI framing — codified, then corrected
CLAUDE.mdgained a "Naming is fuzzy here — Scroll-UI vs. Play-UI" section that distinguishes between the two UI modes and codifies the slide / variant / deck vocabulary.The framing was initially expressed as "two coordinated views of the same content" — that was wrong, and the founder corrected it inline. Scroll-UI and Play-UI are two coordinated implementations per slide, with different constraints (responsive sections vs. rigid 16:9 no-JS standalone files), coupled only by slot identity. The conversion is non-trivial: it's the "recreate, don't extract" discipline encoded in
/api/slide-decompose, which is Phase 1 → Phase 2 of the deck-iteration-workflow.An agent-memory note (
feedback_scroll_vs_play_are_different_components.md) was saved at user-memory level so future sessions don't repeat the misframing.The corrected framing propagated into the sitemap README and (in the consumer-side companion changelog) into chroma's sitemap README.
Status-discipline framework — skill amendment + habit + sweep
context-vigilanceskill gained a status-discipline section inSKILL.md, an expandedstatus:row infrontmatter-spec.md, and a new deep reference atreferences/status-discipline.mdcovering the lifecycle (Draft → In-Review → Signed-Off → Implementing → Shipped·Partially-Shipped·Deferred·Stale·Superseded·Archived), the required companion fields per status, the## Remaining work (as of YYYY-MM-DD)section convention for partials, and the anti-patterns.lossless-monorepo/context-v/habits/Maintain-Status-Discipline-Across-Context-V-Files.mdoperationalizes the framework as a periodic sweep procedure.All nine plans in
dididecks-ai/context-v/plans/swept on 2026-05-16: 5 promoted to Shipped (Init-DidiDecks, Init-Chroma-Decks, Phase A+, Port-Enhanced-v2, Refactor-Scroll-Ported-Slides), 3 promoted to Partially-Shipped with Remaining-work sections (Stand-Up-Shell with A.7 publish + A.8 verification still pending, Phase A++ with A++.1 variant URL safety + A++.2 route refactor + A++.3 ContentFit still pending, Restore-Calmstorm-Nav-Elegance with Steps 3, 4, 7, 10, 11 still pending), 1 promoted to Deferred with a deferral_note (Componentize-Slides, whose destination retargets into the shell — and which<DeckOverlay>is the first instance of).
Plans-Inventory refresh
The 2026-05-12
Plans-Inventory-and-Phase-A-Outcome.mdexploration was superseded byPlans-Inventory-2026-05-16.md— a fresh state-of-the-union doc designed for a cold-start future-session land. The old doc carries ahistorical_correction_note:flagging the since-corrected Scroll-UI/Play-UI framing in its body; per status-discipline rules, the historical narrative was preserved, not rewritten.
The story
2026-05-13 → 14: chrome elegance + canvas
Phase A+'s PlayChrome worked but felt like a dev tool, not a presentation surface. The 2026-05-12 Plans-Inventory-and-Phase-A-Outcome.md doc already named the gap: "Play works, doesn't have an elegant UI like calmdecks, needs more fidelity to that UI we worked on it hard." The fix was the Restore-Calmstorm-Nav-Elegance-as-Themable-Shell-Primitives.md plan, authored 2026-05-14, which set out to lift calmstorm's mature floating-capsule nav forward as a themable shell primitive — structure / behavior / styling cleanly separated so each consumer can re-skin without forking. Six of eleven steps landed in b21ab84: the --ddd-chrome-* token namespace, <DeckChrome> itself, the event contract, the neutral default theme, the PlayChrome deprecation shim, and the /play[slot] route's adoption of <DeckChrome> via the shim. The five remaining steps (<DeckHeader>, <ModeToggleScrollPlay>, the chroma override sheet, the smoke test, the README docs) are the highest-value next-iteration work in that plan.
Adjacent to the chrome work: <SlideCanvas> lifted in 2f7a8d0 as the pure-CSS 16:9 wrapper, and /play/.../print/ shipped as the calmstorm-pattern verbatim PDF-export route. Two follow-on fixes (6ed9e8b, 11b166a) cleaned up the SlideCanvas wiring and a Vite dynamic-import warning surfaced during the v2 SLOTS port.
2026-05-15: DeckOverlay paired components
Reading-and-ranking the scroll deck in dev surfaced a pattern: three persistent affordances (paginator + nav, classifier pill, future presenter-notes/telemetry) should ride together as a single overlay layer over every slide, but the overlay surface differs by UI mode — Scroll-UI walks sections via IntersectionObserver while Play-UI shows one slot at a time. Hence the paired-variant components, hence the --Scroll-UI / --Play-UI suffix discipline added to CLAUDE.md. The Play-UI variant's trick: wrap the slide in <section data-slot data-variant> so the existing IntersectionObserver inside <SlideRankPill> finds exactly one section in view — no special play-mode branch on the pill, no new prop. The position-conflict between the pill (bottom-right) and <DeckChrome> (also bottom-right) was resolved with a position prop additive change (bottom-right default, top-right for Play-UI compositions). Chroma's /scroll/pitch/enhanced-v3/ adopted <DeckOverlay--Scroll-UI> the same day; the /play/[slot].astro refactor to consume <DeckOverlay--Play-UI> (which would close A++.2 in-play classifier ranking) was deliberately held for a future session.
The context-v/sitemap/ directory shipped the same day. The convention: shell-side mini-specs at the dididecks-ai level (universal artifacts every client inherits), consumer-side mini-specs per client (consumer-authored routes, per-slide components annotated with which shell slot they inject into). The mini-spec frontmatter carries composes: / composed_by: so an agent reading any one file can trace the composition graph in both directions.
2026-05-16: framing correction, /play chooser fix, status sweep
The founder noticed the Play-UI vs. Scroll-UI framing in CLAUDE.md still characterized them as "two coordinated views of the same content." That framing was wrong — Scroll-UI sections and Play-UI standalone files are different components with different constraints, and the difference matters for how to design and how to convert between them. CLAUDE.md and the sitemap READMEs were sharpened to the corrected model; a feedback-memory note was saved so future sessions don't repeat the framing. The Plans-Inventory exploration's misframed "same content viewed three ways" line was preserved as historical narrative with a top-of-file correction note pointing at the corrected anchor.
/play/ on chroma was empty-stating because decksByFormat("play") always returned nothing — and because the chooser's non-empty branch was a placeholder. The deeper mistake the prior model encoded was that Scroll-UI vs. Play-UI was a registry flag; the corrected model says a deck has Play-UI only insofar as per-slide files exist. The companion chroma-decks changelog covers the chooser rebuild in detail; from the dididecks-ai side, the relevant change was a parent-side gitlink bump (2e33a0c) picking up the chroma fix triple.
All nine plans were status-swept that same day per the new framework (codified the same morning into the context-vigilance skill and the monorepo-root habit). The sweep produced the Plans-Inventory-2026-05-16.md replacement and the Remaining-work sections on each Partially-Shipped plan.
Shell version
Stayed at 0.1.0-rc.0. None of these changes warranted a version bump on their own; the next bump (0.1.0-rc.1 or 0.1.0 final) will land alongside either the A++.2 route refactor or the A.7 publish unblock, whichever comes first.
How it works (or "Under the hood")
The --ddd-chrome-* theming contract
Every visual property <DeckChrome> reads is namespaced --ddd-chrome-*. The component never sets visual values directly on its own root — it reads tokens with neutral inline defaults. A consumer overrides at any wrapping element:
:root[data-deck-skin="chroma"] {
--ddd-chrome-bg: rgb(251 248 241 / 0.92); /* cream */
--ddd-chrome-fg: #27201c; /* dark brown */
--ddd-chrome-fg-strong: #f05100; /* chroma orange */
--ddd-chrome-radius: 3px;
/* ... */
}Same DOM. Same behavior. Different skin. Partial overrides work — un-overridden tokens fall back to the neutral default. The full token catalog is in the Restore-Calmstorm-Nav-Elegance plan.
DeckOverlay paired-variant discipline
<!-- Scroll-UI: one long page, sections walked by scroll -->
<DeckOverlayScrollUI deckSlug="pitch" variantSlug="enhanced-v3">
<slot name="nav" /> {/* future: variant-cycling chrome */}
<slot name="classify" /> {/* defaults: SlideRankPill */}
<slot name="notes" /> {/* Phase 3: presenter notes */}
<slot name="telemetry" /> {/* Phase D: engagement beacons */}
</DeckOverlayScrollUI>
<!-- Play-UI: one slot per route, slot-step nav -->
<DeckOverlayPlayUI {...allChromeProps} deckSlug variantSlug slot>
<slot name="nav" /> {/* defaults: DeckChrome */}
<slot name="classify" /> {/* defaults: SlideRankPill position=top-right */}
<slot /> {/* slide content, wrapped in section[data-slot] */}
</DeckOverlayPlayUI>The Play-UI variant's section-wrap is the load-bearing adapter — it lets SlideRankPill's existing IntersectionObserver work in Play context with zero pill-side changes. When the /play/[slot].astro route is refactored to consume <DeckOverlay--Play-UI> (A++.2), the in-play classifier lights up structurally.
What's next
The full state-of-the-union with three concrete next-iteration directions lives in Plans-Inventory-2026-05-16.md. Short version:
Path A — A++.2 route refactor (1–2h, medium risk). Refactor
/play/[deckSlug]/[variantSlug]/[slot].astroto consume<DeckOverlay--Play-UI>. Closes in-play classifier ranking. Founder-facing impact.Path B — Restore Step 7 chroma override sheet (1h, low risk). Author
client-sites/chroma-decks/src/styles/dididecks-chrome.csswith chroma's orange/cream skin scoped to:root[data-deck-skin="chroma"]. Validates the--ddd-chrome-*contract end-to-end. Visible to anyone running chroma's dev server.Path C — A++.1 empty-state for variants without SLOTS (30m, lowest risk). Variant URL safety: render a "no Play-UI yet" panel instead of redirecting to a 404 when
SLOTS[variantSlug]is empty.
Other live directions on the partial plans: A++.3 ContentFit (the other half of SlideCanvas), Restore Steps 3+4 (<DeckHeader> + <ModeToggleScrollPlay>), Phase A.7 publish (still blocked on the dididecks GitHub-org-name decision).
Related
[[../context-v/explorations/Plans-Inventory-2026-05-16]] — the cold-start orientation doc this changelog complements.
[[../context-v/plans/Restore-Calmstorm-Nav-Elegance-as-Themable-Shell-Primitives]] — the plan most of the visible chrome changes execute against.
[[../context-v/plans/Phase-A-Plus-Plus-Play-Fidelity-In-Play-Ranking-and-Variant-URL-Safety]] — the plan A++.2 + A++.3 ContentFit will execute against next.
[[../context-v/sitemap/README]] — the living map this changelog is the first to reference.
[[../client-sites/chroma-decks/changelog/2026-05-16_01]] — the companion consumer-side entry covering the v2 port, the deck dashboard, and the
/play/chooser rebuild.context-v/skills/context-vigilance/references/status-discipline.md(inlossless-agent-skills) — the framework that produced today's status sweep.lossless-monorepo/context-v/habits/Maintain-Status-Discipline-Across-Context-V-Files.md— the habit for future sweeps.
