Skip to content

Commit 43b5056

Browse files
committed
Fix figure scaling and strip duplicate prose from inside SVGs
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
1 parent 8c88d44 commit 43b5056

20 files changed

Lines changed: 127 additions & 127 deletions

public/prototyping/journey-control-flow.html

Lines changed: 2 additions & 2 deletions
Large diffs are not rendered by default.

public/prototyping/journey-figures-gestalt.html

Lines changed: 2 additions & 2 deletions
Large diffs are not rendered by default.

public/prototyping/journey-interfaces.html

Lines changed: 2 additions & 2 deletions
Large diffs are not rendered by default.

public/prototyping/journey-iteration.html

Lines changed: 2 additions & 2 deletions
Large diffs are not rendered by default.

public/prototyping/journey-reliability.html

Lines changed: 2 additions & 2 deletions
Large diffs are not rendered by default.

public/prototyping/journey-runtime.html

Lines changed: 2 additions & 2 deletions
Large diffs are not rendered by default.

public/prototyping/journey-shapes.html

Lines changed: 2 additions & 2 deletions
Large diffs are not rendered by default.

public/prototyping/journey-types.html

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
.journey-section { grid-template-columns: minmax(0, 1.4fr) minmax(220px, 320px); align-items: start; }
2323
}
2424
.journey-figure { margin: 0; padding: 0; }
25-
.journey-figure svg { width: 100%; height: auto; display: block; }
25+
.journey-figure svg { max-width: 100%; height: auto; display: block; }
2626
.journey-figure figcaption { margin-top: var(--space-2); color: var(--muted); font-size: .85rem; font-style: italic; }
2727

2828
</style>
@@ -37,7 +37,7 @@
3737
<h1>Types</h1>
3838
<p class="meta">This journey maps Python&#x27;s runtime object model to optional static annotations so learners know what types can and cannot promise.</p>
3939
</section>
40-
<section class="journey-section"><div><h2>Keep runtime and static analysis separate.</h2><p class="meta">The first lesson is that annotations describe expectations for tools while ordinary Python objects still run the program.</p><ul class="journey-list"><li><a class="text-link journey-item-title" href="/examples/type-hints">Type Hints</a><p class="meta">document expected types and feed type checkers</p></li><li><a class="text-link journey-item-title" href="/examples/protocols">Protocols</a><p class="meta">describe required behavior by structural shape</p></li><li><a class="text-link journey-item-title" href="/examples/enums">Enums</a><p class="meta">name a fixed set of symbolic values</p></li><li><a class="text-link journey-item-title" href="/examples/runtime-type-checks">Runtime Type Checks</a><p class="meta">show `type()`, `isinstance()`, and `issubclass()` without turning Python into Java</p></li></ul></div><figure class="journey-figure"><svg viewBox="0 0 220 96" xmlns="http://www.w3.org/2000/svg"><text x="0" y="50" font-family="'JetBrains Mono', 'IBM Plex Mono', Menlo, monospace" font-size="10" fill="#521000" text-anchor="start">def f(x: int, y: str) -> bool: …</text><line x1="54" y1="42" x2="76" y2="42" stroke="#521000" stroke-width="0.6" stroke-dasharray="2 2"/><line x1="102" y1="42" x2="124" y2="42" stroke="#521000" stroke-width="0.6" stroke-dasharray="2 2"/><line x1="150" y1="42" x2="192" y2="42" stroke="#521000" stroke-width="0.6" stroke-dasharray="2 2"/><text x="96" y="80" font-family="-apple-system, 'Source Sans Pro', sans-serif" font-size="9" fill="rgba(82, 16, 0, 0.7)" text-anchor="middle">annotations describe; runtime accepts any object</text></svg><figcaption>Annotations describe expected types for tools; the runtime accepts any object regardless.</figcaption></figure></section><section class="journey-section"><div><h2>Describe realistic data shapes.</h2><p class="meta">Typed Python becomes useful when annotations explain optional values, unions, callables, and JSON-like records.</p><ul class="journey-list"><li><a class="text-link journey-item-title" href="/examples/union-and-optional-types">Union and Optional Types</a><p class="meta">show `X | Y` and `None`-aware APIs</p></li><li><a class="text-link journey-item-title" href="/examples/type-aliases">Type Aliases</a><p class="meta">name complex types with `type` statements or aliases</p></li><li><a class="text-link journey-item-title" href="/examples/typed-dicts">TypedDict</a><p class="meta">type dictionary records that come from JSON</p></li><li><a class="text-link journey-item-title" href="/examples/literal-and-final">Literal and Final</a><p class="meta">express constrained values and names that should not be rebound</p></li><li><a class="text-link journey-item-title" href="/examples/callable-types">Callable Types</a><p class="meta">type functions that are passed as arguments</p></li></ul></div><figure class="journey-figure"><svg viewBox="0 0 156 80" xmlns="http://www.w3.org/2000/svg"><text x="0" y="14" font-family="-apple-system, 'Source Sans Pro', sans-serif" font-size="8" fill="rgba(82, 16, 0, 0.7)" text-anchor="start" letter-spacing="0.5">X: INT | STR | NONE</text><rect x="0" y="22" width="44" height="28" fill="none" stroke="#521000" stroke-width="1.0"/><text x="22.0" y="40.0" font-family="'JetBrains Mono', 'IBM Plex Mono', Menlo, monospace" font-size="10" fill="#521000" text-anchor="middle">x</text><line x1="44" y1="36" x2="74.02702716443629" y2="17.650150066177822" stroke="#521000" stroke-width="1.0"/><polygon points="80,14 75.48708719090742,20.039339200403308 72.56696713796516,15.260960931952336" fill="#521000"/><line x1="44" y1="36" x2="73.0" y2="36.0" stroke="#521000" stroke-width="1.0"/><polygon points="80,36 73.0,38.8 73.0,33.2" fill="#521000"/><line x1="44" y1="36" x2="74.02702716443629" y2="54.34984993382218" stroke="#521000" stroke-width="1.0"/><polygon points="80,58 72.56696713796516,56.73903906804766 75.48708719090742,51.960660799596695" fill="#521000"/><rect x="82" y="4" width="70" height="22" fill="rgba(82, 16, 0, 0.05)" stroke="#521000" stroke-width="1.0"/><text x="117.0" y="19.0" font-family="'JetBrains Mono', 'IBM Plex Mono', Menlo, monospace" font-size="10" fill="#521000" text-anchor="middle">int</text><rect x="82" y="26" width="70" height="22" fill="rgba(82, 16, 0, 0.05)" stroke="#521000" stroke-width="1.0"/><text x="117.0" y="41.0" font-family="'JetBrains Mono', 'IBM Plex Mono', Menlo, monospace" font-size="10" fill="#521000" text-anchor="middle">str</text><rect x="82" y="48" width="70" height="22" fill="rgba(82, 16, 0, 0.05)" stroke="#521000" stroke-width="1.0"/><text x="117.0" y="63.0" font-family="'JetBrains Mono', 'IBM Plex Mono', Menlo, monospace" font-size="10" fill="#521000" text-anchor="middle">None</text></svg><figcaption>A typed slot can accept one of several shapes — `int | str | None` covers expected absence and alternatives.</figcaption></figure></section><section class="journey-section"><div><h2>Scale annotations for reusable libraries.</h2><p class="meta">Advanced typing exists to preserve information across reusable functions, containers, and decorators.</p><ul class="journey-list"><li><a class="text-link journey-item-title" href="/examples/generics-and-typevar">Generics and TypeVar</a><p class="meta">write reusable typed containers and functions</p></li><li><a class="text-link journey-item-title" href="/examples/paramspec">ParamSpec</a><p class="meta">preserve callable signatures through decorators</p></li><li><a class="text-link journey-item-title" href="/examples/overloads">Overloads</a><p class="meta">describe APIs whose return type depends on the input shape</p></li><li><a class="text-link journey-item-title" href="/examples/casts-and-any">Casts and Any</a><p class="meta">show escape hatches and their tradeoffs</p></li><li><a class="text-link journey-item-title" href="/examples/newtype">NewType</a><p class="meta">create distinct static identities for runtime-compatible values</p></li></ul></div><figure class="journey-figure"><svg viewBox="0 0 250 92" xmlns="http://www.w3.org/2000/svg"><rect x="0" y="30" width="36" height="28" fill="rgba(82, 16, 0, 0.05)" stroke="#521000" stroke-width="1.0"/><text x="18.0" y="48.0" font-family="'JetBrains Mono', 'IBM Plex Mono', Menlo, monospace" font-size="10" fill="#521000" text-anchor="middle">T</text><line x1="36" y1="44" x2="65.0" y2="44.0" stroke="#FF4801" stroke-width="1.4"/><polygon points="72,44 65.0,46.8 65.0,41.2" fill="#FF4801"/><rect x="74" y="26" width="100" height="36" fill="none" stroke="#521000" stroke-width="1.0"/><text x="80" y="23" font-family="-apple-system, 'Source Sans Pro', sans-serif" font-size="8" fill="rgba(82, 16, 0, 0.7)" text-anchor="start" letter-spacing="0.5">FN[T]</text><line x1="174" y1="44" x2="203.0" y2="44.0" stroke="#FF4801" stroke-width="1.4"/><polygon points="210,44 203.0,46.8 203.0,41.2" fill="#FF4801"/><rect x="212" y="30" width="36" height="28" fill="rgba(82, 16, 0, 0.05)" stroke="#521000" stroke-width="1.0"/><text x="230.0" y="48.0" font-family="'JetBrains Mono', 'IBM Plex Mono', Menlo, monospace" font-size="10" fill="#521000" text-anchor="middle">T</text><text x="124" y="78" font-family="-apple-system, 'Source Sans Pro', sans-serif" font-size="9" fill="rgba(82, 16, 0, 0.7)" text-anchor="middle">the same T flows in and out</text></svg><figcaption>A generic type variable preserves shape across a call: the same T flows in and out.</figcaption></figure></section>
40+
<section class="journey-section"><div><h2>Keep runtime and static analysis separate.</h2><p class="meta">The first lesson is that annotations describe expectations for tools while ordinary Python objects still run the program.</p><ul class="journey-list"><li><a class="text-link journey-item-title" href="/examples/type-hints">Type Hints</a><p class="meta">document expected types and feed type checkers</p></li><li><a class="text-link journey-item-title" href="/examples/protocols">Protocols</a><p class="meta">describe required behavior by structural shape</p></li><li><a class="text-link journey-item-title" href="/examples/enums">Enums</a><p class="meta">name a fixed set of symbolic values</p></li><li><a class="text-link journey-item-title" href="/examples/runtime-type-checks">Runtime Type Checks</a><p class="meta">show `type()`, `isinstance()`, and `issubclass()` without turning Python into Java</p></li></ul></div><figure class="journey-figure"><svg viewBox="0 0 220 52" width="220" height="52" xmlns="http://www.w3.org/2000/svg"><text x="0" y="36" font-family="'JetBrains Mono', 'IBM Plex Mono', Menlo, monospace" font-size="10" fill="#521000" text-anchor="start">def f(x: int, y: str) -> bool: …</text><line x1="54" y1="28" x2="76" y2="28" stroke="#521000" stroke-width="0.6" stroke-dasharray="2 2"/><line x1="102" y1="28" x2="124" y2="28" stroke="#521000" stroke-width="0.6" stroke-dasharray="2 2"/><line x1="150" y1="28" x2="192" y2="28" stroke="#521000" stroke-width="0.6" stroke-dasharray="2 2"/></svg><figcaption>Annotations describe expected types for tools; the runtime accepts any object regardless.</figcaption></figure></section><section class="journey-section"><div><h2>Describe realistic data shapes.</h2><p class="meta">Typed Python becomes useful when annotations explain optional values, unions, callables, and JSON-like records.</p><ul class="journey-list"><li><a class="text-link journey-item-title" href="/examples/union-and-optional-types">Union and Optional Types</a><p class="meta">show `X | Y` and `None`-aware APIs</p></li><li><a class="text-link journey-item-title" href="/examples/type-aliases">Type Aliases</a><p class="meta">name complex types with `type` statements or aliases</p></li><li><a class="text-link journey-item-title" href="/examples/typed-dicts">TypedDict</a><p class="meta">type dictionary records that come from JSON</p></li><li><a class="text-link journey-item-title" href="/examples/literal-and-final">Literal and Final</a><p class="meta">express constrained values and names that should not be rebound</p></li><li><a class="text-link journey-item-title" href="/examples/callable-types">Callable Types</a><p class="meta">type functions that are passed as arguments</p></li></ul></div><figure class="journey-figure"><svg viewBox="0 0 156 80" width="156" height="80" xmlns="http://www.w3.org/2000/svg"><text x="0" y="14" font-family="-apple-system, 'Source Sans Pro', sans-serif" font-size="8" fill="rgba(82, 16, 0, 0.7)" text-anchor="start" letter-spacing="0.5">X: INT | STR | NONE</text><rect x="0" y="22" width="44" height="28" fill="none" stroke="#521000" stroke-width="1.0"/><text x="22.0" y="40.0" font-family="'JetBrains Mono', 'IBM Plex Mono', Menlo, monospace" font-size="10" fill="#521000" text-anchor="middle">x</text><line x1="44" y1="36" x2="74.02702716443629" y2="17.650150066177822" stroke="#521000" stroke-width="1.0"/><polygon points="80,14 75.48708719090742,20.039339200403308 72.56696713796516,15.260960931952336" fill="#521000"/><line x1="44" y1="36" x2="73.0" y2="36.0" stroke="#521000" stroke-width="1.0"/><polygon points="80,36 73.0,38.8 73.0,33.2" fill="#521000"/><line x1="44" y1="36" x2="74.02702716443629" y2="54.34984993382218" stroke="#521000" stroke-width="1.0"/><polygon points="80,58 72.56696713796516,56.73903906804766 75.48708719090742,51.960660799596695" fill="#521000"/><rect x="82" y="4" width="70" height="22" fill="rgba(82, 16, 0, 0.05)" stroke="#521000" stroke-width="1.0"/><text x="117.0" y="19.0" font-family="'JetBrains Mono', 'IBM Plex Mono', Menlo, monospace" font-size="10" fill="#521000" text-anchor="middle">int</text><rect x="82" y="26" width="70" height="22" fill="rgba(82, 16, 0, 0.05)" stroke="#521000" stroke-width="1.0"/><text x="117.0" y="41.0" font-family="'JetBrains Mono', 'IBM Plex Mono', Menlo, monospace" font-size="10" fill="#521000" text-anchor="middle">str</text><rect x="82" y="48" width="70" height="22" fill="rgba(82, 16, 0, 0.05)" stroke="#521000" stroke-width="1.0"/><text x="117.0" y="63.0" font-family="'JetBrains Mono', 'IBM Plex Mono', Menlo, monospace" font-size="10" fill="#521000" text-anchor="middle">None</text></svg><figcaption>A typed slot can accept one of several shapes — `int | str | None` covers expected absence and alternatives.</figcaption></figure></section><section class="journey-section"><div><h2>Scale annotations for reusable libraries.</h2><p class="meta">Advanced typing exists to preserve information across reusable functions, containers, and decorators.</p><ul class="journey-list"><li><a class="text-link journey-item-title" href="/examples/generics-and-typevar">Generics and TypeVar</a><p class="meta">write reusable typed containers and functions</p></li><li><a class="text-link journey-item-title" href="/examples/paramspec">ParamSpec</a><p class="meta">preserve callable signatures through decorators</p></li><li><a class="text-link journey-item-title" href="/examples/overloads">Overloads</a><p class="meta">describe APIs whose return type depends on the input shape</p></li><li><a class="text-link journey-item-title" href="/examples/casts-and-any">Casts and Any</a><p class="meta">show escape hatches and their tradeoffs</p></li><li><a class="text-link journey-item-title" href="/examples/newtype">NewType</a><p class="meta">create distinct static identities for runtime-compatible values</p></li></ul></div><figure class="journey-figure"><svg viewBox="0 0 250 70" width="250" height="70" xmlns="http://www.w3.org/2000/svg"><rect x="0" y="30" width="36" height="28" fill="rgba(82, 16, 0, 0.05)" stroke="#521000" stroke-width="1.0"/><text x="18.0" y="48.0" font-family="'JetBrains Mono', 'IBM Plex Mono', Menlo, monospace" font-size="10" fill="#521000" text-anchor="middle">T</text><line x1="36" y1="44" x2="65.0" y2="44.0" stroke="#FF4801" stroke-width="1.4"/><polygon points="72,44 65.0,46.8 65.0,41.2" fill="#FF4801"/><rect x="74" y="26" width="100" height="36" fill="none" stroke="#521000" stroke-width="1.0"/><text x="80" y="23" font-family="-apple-system, 'Source Sans Pro', sans-serif" font-size="8" fill="rgba(82, 16, 0, 0.7)" text-anchor="start" letter-spacing="0.5">FN[T]</text><line x1="174" y1="44" x2="203.0" y2="44.0" stroke="#FF4801" stroke-width="1.4"/><polygon points="210,44 203.0,46.8 203.0,41.2" fill="#FF4801"/><rect x="212" y="30" width="36" height="28" fill="rgba(82, 16, 0, 0.05)" stroke="#521000" stroke-width="1.0"/><text x="230.0" y="48.0" font-family="'JetBrains Mono', 'IBM Plex Mono', Menlo, monospace" font-size="10" fill="#521000" text-anchor="middle">T</text></svg><figcaption>A generic type variable preserves shape across a call: the same T flows in and out.</figcaption></figure></section>
4141
</article>
4242

4343
</body>

public/prototyping/journey-workers.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
.journey-section { grid-template-columns: minmax(0, 1.4fr) minmax(220px, 320px); align-items: start; }
2323
}
2424
.journey-figure { margin: 0; padding: 0; }
25-
.journey-figure svg { width: 100%; height: auto; display: block; }
25+
.journey-figure svg { max-width: 100%; height: auto; display: block; }
2626
.journey-figure figcaption { margin-top: var(--space-2); color: var(--muted); font-size: .85rem; font-style: italic; }
2727

2828
</style>

0 commit comments

Comments
 (0)