Skip to content

blust.ch's two decks adopt deck runtime and deck transport v2 - #46

Merged
robertblust merged 6 commits into
mainfrom
deck-runtime
Sep 1, 2026
Merged

blust.ch's two decks adopt deck runtime and deck transport v2#46
robertblust merged 6 commits into
mainfrom
deck-runtime

Conversation

@robertblust

Copy link
Copy Markdown
Owner

Summary

  • Pins @robertblust/design to the published v0.6.0 with a real npm install (both package.json and package-lock.json move to the real tag and resolved commit — not a lockfile-only bump).
  • Each deck declares its own TALK payload (title/desc, de/en) extracted verbatim from its existing UI object, then wraps its runtime in a new deck runtime · v1 · shared fence. The nested language fence is untouched, exactly where it already sat.
  • Because the runtime block was extracted from talks/mental-model/index.html, syncing it back returns the runtime body byte-for-byte identical except for the intended title:'…'/desc:'…'title:TALK.xx.title/desc:TALK.xx.desc substitution — verified line by line against a pre-sync copy of both decks.
  • deck transport moves to v2, which brings .tbtn:disabled{opacity:.35; cursor:default} (the boundary-state styling) and folds .lcd:has(.n.msg) into the fence. Each deck's own unfenced copy of that rule, and the comment noting a later plan would decide it, is dropped — this is that plan.
  • verify/check.mjs's fences and fenceOrder arrays for both decks now include "deck runtime", positioned between deck transport and language — matching where its opening marker physically sits relative to the nested language fence.
  • og.sha refreshed for both decks: their markup moved, so the recipe hash changed, even though the rendered cards are pixel-identical to before.

Test plan

  • npm install github:robertblust/design#v0.6.0 — real install, node_modules and lockfile both on v0.6.0
  • npm run design — synced deck runtime and deck transport fences on both decks
  • Diffed each deck: beyond marker/doc-comment lines and the TALK block, only the transport's two new :disabled rules and the removed duplicate .lcd:has(.n.msg) (+ its comment, + the now-empty media block) changed
  • Isolated the runtime body (var slides … through the beforeunload line) in a before/after diff for both decks — the only difference is the two title/desc lines now reading TALK.xx.title/TALK.xx.desc
  • npm run verify — all checks pass, including the new fenceOrder position
  • npm run design:check — 7 files / 43 fences match
  • npm run og && npm run og:check — every card matches the page it renders
  • Rendered the boundary state on both decks at slide 0: tPrev.disabled === true, computed opacity 0.35
  • Opened talks/mental-model/index.html from file:// directly (no server): renders correctly, no console/page errors, no failed requests — confirms no external assets and that the deck still stands alone

🤖 Generated with Claude Code

robertblust and others added 6 commits September 1, 2026 07:29
… what it is

go() has always clamped, so prev at slide zero and next at the last slide
were already no-ops. Nothing said so: the buttons looked live and did
nothing. render() now sets disabled on both, and on first alongside prev,
which is equally inert at slide zero, in both decks.

The styling arrives with the next design release — .tbtn lives inside the
shared transport fence, so a disabled treatment is a package change.

role=group and aria-label go on both decks' language control, which
measured pixel-identical: they change only what a screen reader announces,
from two unlabelled buttons to one named control.

mental-model's narration comments also move to essential-complexity's
wording. Both quoted an example from a note, and the quoted phrase lives
only in guestgraph's content — a comment shared by four decks cannot
illustrate itself with one deck's speaker notes. essential-complexity's
deck-agnostic phrasing is what the shared runtime carries now.
A release shipped the deck lockup visible on mobile, on two decks, because
the lockup and the transport fences both carry a .name rule at identical
specificity and one site emitted them in the opposite order. Every gate was
green: design:check compares each fence's bytes independently, and the
fences check asserts presence. Neither can see a relationship between two
fences.

fenceOrder takes the order from PAGES — the site's own declaration of what
it ships — and asserts the fences appear in it. Demonstrated by swapping two
adjacent blocks and watching it name both orders.
Pins @robertblust/design v0.6.0 with a real install (node_modules and the
lockfile both move to v0.6.0, not just the lockfile). Each deck declares
its own TALK payload — four strings extracted verbatim from its current
UI — above a new `deck runtime · v1 · shared` fence, and the nested
`language` fence stays exactly where it already was, untouched. Since the
runtime block was extracted from mental-model's own code, syncing it back
returns the runtime body byte-identical except for the intended
TALK.xx.title/desc substitution — verified line by line.

deck transport v2 arrives with the boundary-state styling
(.tbtn:disabled{opacity:.35}) and brings `.lcd:has(.n.msg)` inside the
fence, so each deck's own unfenced copy of that rule — and the comment
noting a later plan would decide it — is dropped.

Both decks' `fences` and `fenceOrder` arrays in verify/check.mjs now
carry "deck runtime" in the position it actually occupies: between
`deck transport` and `language`, matching where its opening marker sits
relative to the nested language fence.

npm run verify, design:check and og:check all pass; og.sha refreshed for
both decks since their markup moved, even though the rendered cards are
pixel-identical.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
v0.6.0's deck runtime block baked blust.ch's own storage key into the
nested language fence instead of carrying the {{langKey}} template, and
declared no params — so a sync had no fixed point: one pass wrote
rb-lang, the nested pass rewrote it, and design:check never settled.
This site's decks were green only by coincidence, because rb-lang is
also this site's own key.

v0.6.1 fixes it. Re-syncing moves the runtime fence's marker v1 -> v2
and its documentary comment; LANG_KEY resolves through the template to
rb-lang, unchanged in value. A second npm run design writes nothing.
…ion check

Finding 6: fences and fenceOrder on the two decks' PAGES entries read as though they
disagreed — deck runtime last in one, third in the other. They don't: fences is
presence-only and order-blind. One line beside the pair says so, as promised when
the fifth fence landed.

Finding 7: CLAUDE.md said "Six blocks are generated" when there are ten now, and still
described the deck footer as a hand-maintained copy asserted by footerVersion — both
retired in the previous plan and replaced by four generated fences (deck transport,
deck lockup, deck fit, deck runtime), enforced by design:check instead. Corrected the
count, the block list and every footerVersion/deck-footer reference; left the rest of
the prose alone.

npm run verify, design:check and og:check all still pass.
deck runtime v2 -> v3: boundary controls set aria-disabled and guard
their own handlers instead of setting the disabled property, so a
control that goes inert under the user's own Enter keypress does not
drop focus to <body>. deck transport v2 -> v3 follows with the
matching CSS selector, .tbtn[aria-disabled="true"].

Verified in Chromium on the mental-model deck: focus stays on tPrev
after it goes inert (aria-disabled=true, disabled property false,
opacity 0.35).
@robertblust
robertblust merged commit b3712b9 into main Sep 1, 2026
1 check passed
@robertblust
robertblust deleted the deck-runtime branch September 1, 2026 09:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant