Skip to content

Add marginalia gestalt page#1

Open
adewale wants to merge 5 commits intomainfrom
claude/tuftean-marginalia-viz-TB0fw
Open

Add marginalia gestalt page#1
adewale wants to merge 5 commits intomainfrom
claude/tuftean-marginalia-viz-TB0fw

Conversation

@adewale
Copy link
Copy Markdown
Owner

@adewale adewale commented May 9, 2026

Single static HTML page rendering every example and journey as a
small card with its proposed marginalia visualisation, drawn in a
shared visual language so the set can be reasoned about as a whole
before each card is placed beside its lesson.

https://claude.ai/code/session_01MazwoRWAihW6dwso3fMCHE

The branch landing covers the entire visual-explainer thread of work.
This commit lands all of it on the current main, with the figure
catalogue reconciled to main's restructured journeys.

Net additions:
- docs/visual-explainer-spec.md      design spec for the inline cell-figure
                                     production layout, plus the
                                     banner-between grammar (prototypes only)
                                     and the journey-section figure pattern
- docs/journey-visualisation-rubric.md   10-point rubric for journey
                                     section figures: section fidelity,
                                     pedagogical scope, mechanism over
                                     metaphor, topic gates, project gate
- src/marginalia_grammar.py          locked Canvas grammar — palette
                                     aligned with site tokens (--text,
                                     --muted, --accent, --accent-soft-
                                     equivalent neutral); tokens, words,
                                     phrases (bind, dispatch, lanes,
                                     connect for tangent edges)
- src/marginalia.py                  27 figures: 18 journey-section,
                                     plus 9 lesson + library figures
- src/app.py                         _render_cell injects the attached
                                     figure between prose and code-stack
                                     when present; cell gets has-figure
                                     class so it stacks vertically
- public/site.css                    .lp-cell.has-figure single-column;
                                     .cell-figure styling
- public/_headers                    /prototyping/* no-cache rule
- scripts/fingerprint_assets.py      digests src/marginalia.py and
                                     src/marginalia_grammar.py so figure
                                     edits invalidate HTML cache
- scripts/build_marginalia.py        76-card gestalt review page
- scripts/build_prototypes.py        15 prototypes: index, design-review
                                     pair, three banner-grammar demos,
                                     eight journey demos, one journey-
                                     figures gestalt

Reconciled with main's restructure of journeys (Streams was split into
Control Flow + Iteration; Workers added; some titles renamed):

  Old key                              → New key
  Streams · Make decisions explicitly  → Control Flow · Choose between paths
  Streams · Recognize iter as protocol → Iteration · See the protocol behind `for`
  Streams · Choose the right loop      → Iteration · Choose the right loop shape
                                         (unchanged)

Three new figures designed to close coverage gaps surfaced by audit:
  naming-decisions  Control flow · Name and shape decisions
  early-exit        Control flow · Stop as soon as the answer is known
  lazy-stream       Iteration · Compose lazy value streams

Coverage: 21 of 24 journey sections have figures. The three Workers
sections render as heading + list with no figure column — intentional
pending future design (their titles are constraint-y rather than
mechanism-y; figure designs need more thought).

Audit results clean:
- production rendering: has-figure class + cell-figure svg present;
  no margin-anchor or margin-collected leaks
- palette: only the seven site-token values appear across all
  prototype output
- PROTOTYPES list and on-disk files agree
- every journey figure has a non-empty caption
- 39 unit tests pass

https://claude.ai/code/session_01MazwoRWAihW6dwso3fMCHE
@adewale adewale force-pushed the claude/tuftean-marginalia-viz-TB0fw branch from f6e591d to 50ed727 Compare May 10, 2026 12:38
adewale and others added 4 commits May 10, 2026 14:00
The journey-types screenshot showed two related defects on every page
that uses small-viewBox figures:

1) text inside small-viewBox figures was rendered too large because the
   SVG had only viewBox set; CSS width: 100% then stretched a 156-wide
   viewBox to ~320px in the journey-section figure column, doubling all
   text sizes inside the SVG.

2) several figures repeated their figcaption as a stray label inside
   the SVG, so the same sentence appeared twice in the page (once
   floating in the figure area, once below as the caption).

Fixes:
- Canvas.to_svg() now emits width="W" height="H" matching the viewBox.
  CSS max-width: 100% (everywhere figures appear: cell-figure,
  cell-banner, journey-figure, marginalia gestalt cards, journey-figures
  gestalt section grid) lets figures clamp to container width without
  stretching above intrinsic CSS-pixel size.
- Six figures lost their bottom prose label, which duplicated the
  figcaption: function-as-value, annotation-ghost, generic-preservation,
  context-bowtie, naming-decisions, lazy-stream.
- ViewBox heights of those six figures tightened so the trimmed content
  doesn't leave dead space between the SVG and the figcaption.

Verified:
- /prototyping/journey-types serves first SVG with width="220" height="52"
  matching its viewBox; "annotations describe" no longer appears inline.
- 39 unit tests pass.
- All other prototypes (banner-*, marginalia-gestalt, journey-figures-
  gestalt, six other journey pages) regenerate cleanly.

https://claude.ai/code/session_01MazwoRWAihW6dwso3fMCHE
plus the 6 follow-ups

Identified root cause and prevention rules
------------------------------------------

The previous fix patched two failure modes; this commit documents the
underlying rules in docs/visual-explainer-spec.md as pipeline invariants
so they cannot drift back:

  1. The SVG element renders at intrinsic CSS-pixel size.
     Canvas.to_svg() emits width/height matching the viewBox; CSS uses
     max-width: 100% (never width: 100%). Otherwise small viewBoxes
     stretch and text inside doubles in size.

  2. A figure's diagrammatic content does not duplicate its figcaption.
     SVGs may carry functional labels (stdout, iter(), panel tags,
     type signatures) but never a sentence describing the figure.
     Captions are the canonical prose. The marginalia-gestalt review
     page is the documented exception (cards have no figcaptions).

Audit: production paths clean across CSS, SVG width attributes, and
inline labels. Four prose-y labels remain in the gestalt e_*(c) paint
code; they're correct in context (no figcaption on those cards) and
flagged in the example-figure rubric for removal-on-promotion.

The six follow-ups
------------------

1. docs/example-figure-rubric.md — parallel to the journey rubric,
   scored to 10 across content (cell fidelity, running variables, one
   move, mechanism, caption-asserts), craft (grammar, scarcity,
   restraint), and context (cell-column fit, code pairing). Topic gates
   per cell shape; release gates and project gate.

2. Scored all 70 gestalt example figures against the new rubric. SCORES
   dict in scripts/build_marginalia.py keyed by slug, with a brief
   rationale per entry. Each gestalt card now renders its score and
   note as a small badge beneath the figure. Distribution: ~30 score
   9.0+, ~25 score 8.0-8.9, ~5 score 7.0-7.9.

3. Promoted 11 high-scoring gestalt figures into src/marginalia.py
   FIGURES (one paint function per figure, grammar-conformant, prose-
   labels stripped). Plus operator-dispatch reused for special-methods.
   Twelve new ATTACHMENTS rows wired so /examples/<slug> renders the
   figure between cell prose and code:

     variables · variables-bind            decorators · decorator-rebind
     recursion · call-stack                inheritance-and-super · mro-chain
     dataclasses · dataclass-fields        classes · class-triangle
     special-methods · operator-dispatch   exception-chaining · cause/context
     unpacking · unpacking-bind            comprehensions · comprehension-equiv.
     lists · list-append                   dicts · dict-buckets

   FIGURES went 27 → 41; thirteen example pages now render a figure
   (was one).

4. Designed three figures for the Workers journey sections — labelled
   tentative because the section titles are constraint-shaped rather
   than mechanism-shaped. Journey-section figure coverage: 24/24.

5. (Same as 3.) Wired ATTACHMENTS for the promoted figures.

6. /prototyping/production-figures-gestalt.html added — every figure
   currently registered in FIGURES on one page with a tag indicating
   where it renders (an /examples/ attachment, a journey section, or
   "not yet attached"). Closes the visibility gap between
   "designed in build_marginalia.py" and "shipping in production".

Centralised review pages now:
  /prototyping/marginalia-gestalt              70 examples + 6 journeys
                                               (gestalt design review,
                                               scored against the new
                                               example-figure rubric)
  /prototyping/journey-figures-gestalt         all journey-section
                                               figures grouped by journey
  /prototyping/production-figures-gestalt      every figure shipping in
                                               production with attachment
                                               status

39 unit tests pass.

https://claude.ai/code/session_01MazwoRWAihW6dwso3fMCHE
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.

2 participants