Open
Conversation
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
f6e591d to
50ed727
Compare
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
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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