Skip to content

Live explorable /explain.html — log → bend → exp pipeline#13

Merged
silviot merged 14 commits into
mainfrom
explainer-page-2
Jun 2, 2026
Merged

Live explorable /explain.html — log → bend → exp pipeline#13
silviot merged 14 commits into
mainfrom
explainer-page-2

Conversation

@silviot

@silviot silviot commented May 29, 2026

Copy link
Copy Markdown
Collaborator

Supersedes #10. A standalone, GPU-rendered explorable at /explain.html that walks from the everyday Droste effect to Escher's closed spiral and the de Smit–Lenstra map — built for someone who knows no complex numbers or logs.

Staging: https://silvio-tententoon.pgs.sh/explain.html

Function playground (new)

Before the log → bend → exp construction, a free function playground teaches readers to read a complex function as "a machine that moves the plane."

  • src/explain/playground.ts — self-contained Canvas-2D explorer (no WebGL, independent of the Droste pipeline). Drag a point on the input plane, watch where f(z) lands on the output plane.
  • Functions: z, 2z, iz, , exp(z), log(z). Toggle grid / rings / photo (all forward-warped). Continuous identity → function slider (f_t(z) = (1−t)z + t·f(z)).
  • New prose: First, what is a function?, The function we need, and a conformality section Why the picture still looks like a picture.

The spine: one pipeline, four live panels

the original → we log it → we bend it → we exponentiate it, connected in realtime (horizontal row on desktop, stacked on mobile):

  • we log it — flatten the nested frames into a repeating strip; drag it (↔ zoom, ↕ turn) and every panel follows.
  • we bend it — lean the flat strip; at one angle the tiles click back into register (closed ✓). The one lean control twists the spiral too.
  • we exponentiate it — roll the bent strip back up into the tententoon spiral (manual roll slider; spiral by default, no autoplay).
  • Live, value-bearing math under each panel — S, log S, α = 1 − k·i — updates as you pick a source or drag the lean.
  • Source switcher (ring / grid / photo / overlay, default overlay) under every panel, one global state. Ring/grid use a bold synthetic geometry (β ≈ 25.5°, near Escher's 26°) that stays seamless at any scale; the photo keeps its honest gentle nesting.

Pedagogy & prose

  • Slower open: an ordinary photo with an empty frame, then build the Droste by dropping the photo into its own frame.
  • "A circle unrolls into a repeating line" gets its own diagram; the payoff is why it closes — periodic, so a one-tile step lands on an identical region, no seam.
  • Voice pass: precise, no filler or false claims, jargon named only after the mechanism. Dropped the standalone formula section in favour of the live per-panel math.
  • Vendored a local 3Blue1Brown thumbnail in "See it move."

Engine

  • New shared-shader unroll mode + u_morph, fully additive (the main app's PipelinePanel and all existing tests are untouched).
  • Natural drag (strip follows the pointer). Typecheck clean, 22/22 tests pass, production build clean (both entry points).

🤖 Generated with Claude Code

silviot and others added 9 commits May 29, 2026 00:06
Reframe the README around the tententoon idea (same picture, two infinities) rather than implementation: a side-by-side Droste/tententoon visual, a precise one-line definition, the log-polar idea in plain language, and the Escher / de Smit-Lenstra origin. Run and tech details move to a collapsed footer.

Add public/explain.html: a standalone 'what is a tententoon' deep-dive styled as an aged-paper dictionary card (syllabified headword, IPA, numbered sense + usage example, bracketed etymology, inline nested-squares SVG mark), flowing into a plain-language account of why the spiral closes seamlessly (the logarithm trick), Escher's hand-drawn blank centre, and the 2003 de Smit-Lenstra completion.

Revert the in-app InfoModal copy to the hand-written original and tag it .human-written so it is preserved from future rewrites.

Add public/tententoon-demo.gif (spiral demo) for the README + page visuals. docs/screenshots/ holds card previews for this PR.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Fold in the math from the feat/pipeline-explorable-view worktree's 4-panel view: source + rect -> log(z-c) lattice (periods logS, 2pi) -> tilt by beta = arctan(logS/2pi) -> roll back up via w(z) = c + (z-c)^alpha. Turns the 'why doesn't it tear' section from intuition into the concrete four frames the maths passes through, with named parameters.

Drops the earlier complex-map aside, now redundant (step 4 carries the exact map).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
explain.html moves from public/ (static) to a Vite entry (added to rollupOptions.input) with src/explain/main.ts. It loads a swappable test image (SOURCE + optional NEST consts at the top of main.ts), builds the Droste geometry with fitCropToNest/buildPanelGeometry, and renders source - log(z-c) - rotated-log - tententoon live via the app's PipelinePanelGLRenderer. No duplicated math: the page reuses the same GPU renderer and geometry helpers the in-app pipeline view uses.

Dragging the log panel pans log space: horizontal pan = zoom, vertical pan = rotation, and the tententoon follows with a live readout (verified at 144 deg / x33). Falls back to the four-step prose if WebGL2 is unavailable.

Removes the now-superseded static public/explain.html.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Per feedback, drop the 2x2 grid and the source panel. The tententoon spiral now replaces the animated GIF in 'Now bend it'. In 'Why doesn't it tear?', the log(z-c) panel becomes a hands-on experiment: drag it and the original picture beside it rotates (vertical) and zooms (horizontal), with a live readout. The rotated-log lattice stands on its own as the 'lean it over' illustration.

'The original' is rendered by the same engine with the twist off (kTwist=0), so it zooms cleanly (mipmapped) and seamlessly. Verified: vertical drag -> 144 deg rotation, horizontal -> x33 zoom.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Add two controls to the explorable, both feeding the reused GPU pipeline: a source toggle (picture / grid / polar / overlay) and a twist-angle (beta) slider.

src/explain/patterns.ts generates grid + polar sources centred on the limit point c at the photo's pixel size. Polar rings are individually styled (thick / dashed / plain, in ink then red) so you can follow one through the map, and spaced by S^(1/6) so the style cycle is S-periodic = seamless under the Droste fold; in the log panel each ring becomes its own vertical line.

The slider overrides beta = atan(logS/2pi): the tententoon twist is tan(beta) and the rotated-log leans by beta. Only at the canonical beta does the spiral close (a 'closed' marker shows it). Verified live: circles -> vertical lines, grid warps, overlay, and a 20deg twist clearly tightens the spiral.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
It was never a theorem. de Smit and Lenstra worked out the exact map (the structure) hiding in Escher's grid, and the missing centre was then filled by computer. That is analysis plus a method/recipe, not a theorem. Rename the heading 'The theorem that filled the hole' -> 'The map that filled the hole', say 'worked out' (not 'wrote down'), and call the distinction out in the text ('this is not a theorem so much as a recipe').

Voice pass over the prose per the writing profile: drop em-dash connectors throughout (colons / parentheses / periods instead) and remove 'seamlessly' from the UI copy. Code comments left untouched (not published prose).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The centrepiece spiral barely bent: the demo photo's honest closing
angle is only ~6.8°, so "now bend it" landed flat. Drive the hero from a
bold synthetic geometry (S=20 → β≈25.5°, just shy of Escher's 26°) using
the scale-invariant ring/grid patterns, which twist hard AND still close
seamlessly. The photo keeps its faithful gentle nesting for "photo" mode;
switching source switches geometry, and β + the "closed ✓" mark follow.

New, all reusing the shared GPU pipeline (no duplicated map math):
- unroll: a new shader mode (3) + u_morph that morphs the spiral into the
  flat leaned-over strip in source log-polar space — exact at both ends,
  genuinely curling in between. Slider + play (pauses offscreen, honours
  prefers-reduced-motion). Additive: PipelinePanel + tests untouched.
- Droste↔Escher twist slider from 0° (flat Droste) to the closing angle,
  with a "snap it shut" tween and an accent glow at closed.
- a zero-math spiral-staircase analogy (rings ↔ flat lines SVG).

Re-paced the whole page for a reader who knows no complex numbers or
logs: see the log happen (unroll) before it's ever named, with the
formula/β/lattice quarantined into one "for the curious" tier.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Reframe the explainer around the real decomposition, as one connected,
realtime pipeline: the original → we log it → we bend it → we exponentiate
it. Four panels in a row on desktop, stacked on mobile; one bend (lean)
control leans the strip and twists the spiral together, dragging the flat
strip pans all of them, and a roll control rolls the bent strip up into
the spiral. Source switcher (ring/grid/photo/overlay) under every panel,
one global state.

Live, value-bearing math under each step instead of an abstract formula
dump: S and log S at the log step, α = 1 − k·i at the bend step (updating
as you drag the lean), w = c + (z−c)^α at exp. Removed the standalone
"For the curious: the actual map" section.

Prose pass for a reader who knows no complex numbers or logs:
- slower opening — start from the pre-Droste photo (empty frame) and
  build the Droste by dropping the picture into its own frame;
- the circle → repeating-line bit gets its own diagram (angular
  periodicity), and the point is now WHY it works: the logged image is
  periodic, so a one-tile step lands on an identical region — that's the
  seamless close, not "it just repeats forever";
- cut filler/false claims (no "needs no mathematics", no "recipe not a
  theorem"), name the logarithm only after the mechanism is shown.

UX per review: default source = overlay; spiral shown by default at exp
with no auto-play and no play button; drag now follows the pointer
(inverted both axes). Vendored a local 3Blue1Brown thumbnail
(Escher → log(Escher)) into "See it move".

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@silviot silviot changed the title Live explorable /explain.html + concept-first README Live explorable /explain.html — log → bend → exp pipeline May 30, 2026
@silviot

silviot commented May 30, 2026

Copy link
Copy Markdown
Collaborator Author

Redeployed latest to staging: https://silvio-tententoon.pgs.sh/explain.html (4-panel log→bend→exp pipeline, live math, overlay default; console clean).

@silviot

silviot commented May 30, 2026

Copy link
Copy Markdown
Collaborator Author

Correction: staging serves extensionless URLs — the live page is https://silvio-tententoon.pgs.sh/explain (not /explain.html). Verified live: 4-panel log→bend→exp pipeline, live math (S, log S, α), overlay default, console clean.

silviot and others added 4 commits May 30, 2026 23:22
Add a free complex-function explorer (input plane | selector | output
plane) that runs before the log -> bend -> exp construction, so the
reader learns to read a function as a machine that moves the plane
before the spiral panels assume that language.

- src/explain/playground.ts: self-contained Canvas-2D visualiser. Drag a
  point, switch f(z) among z, 2z, iz, z^2, exp, log, toggle grid/rings/
  photo, scrub a continuous identity->f interpolation. Grid/ring lines are
  sampled and stroked through the map (broken at branch cuts); the photo
  is forward-warped through a triangle mesh.
- explain.html: 'First, what is a function?' + 'The function we need' +
  'Why the picture still looks like a picture' sections, plus CSS.
- main.ts: boot the playground alongside the pipeline.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Boot the function playground from a ResizeObserver plus a deferred rAF
pass, and make resize()/draw() no-op until the canvas actually has a
laid-out width. This keeps the explorer from drawing into a zero-size
canvas when the module evaluates before CSS layout, and removes the
temporary init logging added while diagnosing.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The output plane auto-fit its viewport to the mapped image, so f(z)=2z
doubled both the content and the frame — the two cancelled and the grid
looked untouched ("the function did nothing"). Pin the output to the
input's half-extent (D) for the linear maps z, 2z, iz, so doubling now
reads as a visibly coarser grid with the point flung outward, and the
quarter-turn is unmistakable. Nonlinear maps (z², exp, log) still
auto-fit, since for them the lesson is the shape change, not scale, and
they need the room to stay framed.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The input plane was 4.8 rad tall (D = 2.4), but exp(z) maps the
imaginary part to the output angle — so a 4.8-rad strip only swept
4.8/2π ≈ 76% of a lap and the rings stopped short, leaving "exp rolls
the plane around the origin" visibly false. Set D = π so the vertical
span is exactly 2π and exp closes into full circles. Align GRID_STEP to
π/8 so the grid divides D evenly (no edge sliver). Same 2π periodicity
that closes the tententoon spiral.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@silviot silviot merged commit c5a6d76 into main Jun 2, 2026
1 check passed
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