diff --git a/README.md b/README.md index 8b0253f..6c6cd27 100644 --- a/README.md +++ b/README.md @@ -1,129 +1,69 @@ -# Tententoon +
noun · a self-repeating image whose copies spiral as they shrink — in the manner of M. C. Escher's Print Gallery (1956).
-A browser-native Droste machine. Drop in any photograph, frame the rectangle that should -contain a smaller copy of itself, and watch the image recurse into its own infinity — the -way the boy in Escher's *Print Gallery* stares into the picture he is standing inside of. - -Everything runs locally. No uploads, no backend, no account. Just the canvas, the maths, -and your image. - ---- - -## What it does - -- **Drop or pick** any image — JPEG, PNG, anything the browser can decode. -- **Frame** a rectangle inside it. That rectangle becomes the next iteration of itself. -- **Zoom forever** — a continuous, seamless loop into (or out of) the nested copy. -- **Export** the result as a still PNG, a looping MP4, or a GIF. All produced in-browser. -- **Tweak** the spiral: pick the centre, the scale ratio, the rotation, the depth. -- **Two views**: a polished editor (top bar, tool rail, canvas, inspector, timeline) and a - log-domain explorable for those who like to see the conformal map at work. - -The geometry is the same one Escher's mathematicians used to "complete" the Print Gallery: -a log-polar warp that turns nested similarity into a straight line. We let you see both -sides of that mirror. +
+from the Dutch title Prentententoonstelling — prenten (prints) + tentoonstelling (exhibition),
+with the coined word sitting right where the two halves meet.
+A browser tool for making the same move with your own images.
+
![]() |
+![]() |
+
| Droste — a picture inside itself, dropping straight down forever. (this one is a real photograph) |
+tententoon — the same recursion, bent into a spiral that still closes seamlessly. | +
+ ten·ten·toon + /ˌtɛn.tɛnˈtoːn/ + noun +
+ ++ 1. a self-repeating image whose copies spiral as + they shrink, in the manner of M. C. Escher's + Print Gallery. +
+• a tententoon of the old + gallery, winding inward without end.
+ ++ Origin + coined from the Dutch Prentententoonstelling + (“print exhibition”): prenten, prints + + tentoonstelling, exhibition. The coined word sits right where + the two halves meet. +
++ Put a picture inside itself. Then put it inside that copy, and inside + the next, and don't stop. +
+ +
+ + Every copy sits squarely inside the one before it. The picture drops + straight down into itself, shrinking by the same step each time, + forever. That is the Droste effect, and you have seen it a + hundred times. +
+ ++ Here is a stranger question. What if each copy does not only shrink? What + if it also turns? +
+ ++ Same picture. Same rule: a copy, inside a copy, inside a copy. But now every + copy is rotated a little as it shrinks, and the whole stack winds up into a + spiral. Watch the edges: straight lines bow into curves, the room twists, and + nothing tears. Follow any line inward and it meets itself exactly. Zoom + forever and you never find a seam. +
+ ++ Same picture. Two infinities. One drops straight down; the other takes the + scenic route, and still arrives on time. +
+ ++ All of it comes from one move: take the logarithm. +
++ Measure every point by how far it sits from the centre c and at what + angle, then take the logarithm of the distance. Shrinking-and-repeating is + multiplication, and logarithms turn multiplication into addition, so the + endless nested frames unroll into a plain, repeating lattice: step + sideways by log S for one Droste jump, up or down by 2π + for one full turn around c. Straight. Boring. Tiling forever. +
++ And here is the surprise, in your fingertips. The panel on the left is that + lattice, log(z − c). Drag it. A + sideways drag zooms the original on the right; an up-and-down drag + rotates it. A slide in the log is nothing but a rotate-and-zoom back + in the original picture. That is the whole trick, and the readout keeps the + score. Feed the same machine something cleaner, too: a grid, or polar circles + with each ring styled so you can follow it through the bend. +
+ ++ This live experiment needs WebGL2 and JavaScript. In short: a sideways slide in + the log panel zooms the original picture, and a vertical slide rotates it. +
+ ++ Now add the turn for real. A copy that shrinks and rotates leans that + lattice over by a fixed angle, β = arctan(log S / 2π). It + is the one tilt that lets the pattern line up with itself again after a slide: +
+ ++ Roll the logarithm back up and the tilted lattice winds into the spiral you saw + above: the tententoon. In a single line it is the map + w(z) = c + (z − c)α with + α = 1 − i·(log S / 2π): the real part carries + the picture, the imaginary part is the lean. +
++ And here is why it never tears. In the lattice there is nothing to tear, + only a pattern that repeats. Slide it by exactly one tile and you land on an + identical picture; roll that back up and “one tile” becomes + “one full turn of the spiral.” The loop closes because the shift + closes. The seam isn't hidden; there simply isn't one. +
+ ++ Escher had no computer in 1956. He worked the curved grid out by eye, ruled it + onto the canvas, and painted a gallery, a print, a town, and the gallery again + into the bend. And he got it right: the mathematics later showed his + intuition was very nearly exact. +
++ But a spiral tightens forever toward its centre, and a pen can only go so fine. + So Escher stopped, left a soft white patch in the middle of the picture, curled + his signature into it, and called it finished. The one place the picture could + not finish itself. +
+ ++ In 2003, two mathematicians in Leiden (Bart de Smit and + Hendrik Lenstra) worked out the exact map hiding in Escher's + grid. The idealised Print Gallery, they showed, contains a complete + copy of itself rotated by 157.6256° and shrunk by a factor + of 22.5837. Pin those two numbers down and the rest of the + picture is forced, including the part Escher left blank. +
++ This is not a theorem so much as a recipe: with the map in hand, you can hand + the missing centre to a computer and have it do what a pen could not. That is + exactly what they did, continuing the spiral inward far past the reach of any + hand and closing the white hole at last. +
+ ++ If you'd like the whole argument in motion, Grant Sanderson + (of 3Blue1Brown) made a beautiful animated tour of the paper in 2026. + It is the clearest walk through the mathematics there is: + watch it here. +
+ ++ This tool does the bending for you. Drop in any photo, draw the rectangle where + the next copy should sit, and flip between the two infinities: the straight + Droste fall, or the tententoon spiral. Export the loop as a PNG, a GIF, or a + video. It all runs in your browser: no upload, no account, no server. +
+A toy for re-creating the Droste effect from Escher's Print Gallery.
+A toy for re-creating the Droste effect from Escher's Print Gallery.
Inspired by M. C. Escher's lithograph
Prentententoonstelling (1956) — Dutch for
diff --git a/src/explain/main.ts b/src/explain/main.ts
new file mode 100644
index 0000000..a1a9d8c
--- /dev/null
+++ b/src/explain/main.ts
@@ -0,0 +1,281 @@
+/**
+ * Live panels for explain.html, rendered by the app's own GPU pipeline
+ * renderer (PipelinePanelGLRenderer) — no duplicated map math.
+ *
+ * #exp-escher — the tententoon spiral, in "Now bend it". Its twist follows
+ * the angle slider, so you see how β shapes the final spiral.
+ * #exp-rotlog — the rotated-log lattice (leans by the same angle).
+ * #exp-log — log(z − c). DRAGGABLE. + #exp-orig — "the original".
+ *
+ * Two global controls feed every panel from one swappable test image:
+ * • source mode — picture / grid / polar / overlay (see patterns.ts).
+ * • twist angle — overrides β = atan(logS / 2π); only at β does the spiral
+ * close on itself.
+ *
+ * The experiment: dragging #exp-log pans log space. Horizontal pan = a shift in
+ * u = log|z − c| (a ZOOM); vertical pan = a shift in v = arg(z − c) (a
+ * ROTATION). The same pan drives #exp-orig (the picture with the twist off), so
+ * a slide in the log visibly becomes a rotate-and-zoom of the original.
+ */
+
+import { fitCropToNest, type Rect } from '../lib/math/droste';
+import { buildPanelGeometry, panelPxPerUnit, panelURef } from '../lib/ui1/pipeline-panels';
+import { PipelinePanelGLRenderer } from '../lib/render/pipeline-gl';
+import { makeSource, type SourceMode } from './patterns';
+
+// ─── Swappable test image ───────────────────────────────────────────────────
+// To use a different picture: drop it in /public and point SOURCE at it. NEST
+// is the nest rectangle in *image pixels* — load it in the editor, draw the
+// rectangle, read x / y / w / h off the readout. Leave NEST = null to drop a
+// ~half-size nest in the centre of whatever image you give (S ≈ 2).
+const SOURCE = '/Droste_1260359-nevit.jpg';
+const NEST: Rect | null = { x: 343.2, y: 334.7, w: 583.5, h: 454.9 };
+// ─────────────────────────────────────────────────────────────────────────────
+
+const TWO_PI = 2 * Math.PI;
+const MAX_PX = 720;
+
+const byId =