From 682e0da9954354f5d49ceeae76d030b5d117ef03 Mon Sep 17 00:00:00 2001 From: onatozmenn Date: Fri, 31 Jul 2026 18:05:53 +0300 Subject: [PATCH] Walk through it instead of filming it The last box on #14 asked for a recording that works with the sound off. A recording of this page would be a copy of what the compiler said on the day it was filmed, and this page's whole claim is that it prints what the compiler prints. The two would part company and the recording would win, because it is the thing that looks authoritative. So the walkthrough moves through the page that is already here. Five steps, a caption saying what to look at, four and a half seconds each. No sound to turn off and nothing that only works if you can see colour: the caption carries it and the section is scrolled to. Auto-advance is off entirely under prefers-reduced-motion, and anything that means "I am reading this myself", a wheel, a touch, a key, ends the tour rather than fighting it. The two playground links still carried 0.2.1, which the playground would have warned about for no reason since the programs did not change. tools/check.mjs now reads the version out of every share link on the site and compares it to the pin, verified by writing 0.1.9 into one and watching it complain. Closes #14 Co-authored-by: GitHub Copilot --- assets/style.css | 27 ++++++++++++++++++ assets/walk.js | 66 +++++++++++++++++++++++++++++++++++++++++++ one-clause/index.html | 20 ++++++++----- tools/check.mjs | 12 ++++++++ 4 files changed, 118 insertions(+), 7 deletions(-) create mode 100644 assets/walk.js diff --git a/assets/style.css b/assets/style.css index 4e830f6..78e5c53 100644 --- a/assets/style.css +++ b/assets/style.css @@ -160,6 +160,33 @@ pre.code b { max-width: 68ch; } +.walk { + display: flex; + flex-wrap: wrap; + align-items: baseline; + gap: 0.75rem; + margin: 1.5rem 0 0; +} + +.walk .summary { + margin: 0; +} + +[data-step] { + scroll-margin-top: 2rem; + transition: color 0.2s; +} + +[data-step].here { + color: var(--accent); +} + +@media (prefers-reduced-motion: reduce) { + [data-step] { + transition: none; + } +} + .next { display: grid; grid-template-columns: repeat(3, 1fr); diff --git a/assets/walk.js b/assets/walk.js new file mode 100644 index 0000000..03148dc --- /dev/null +++ b/assets/walk.js @@ -0,0 +1,66 @@ +// The thirty seconds a recording would have shown, without the recording. +// +// A video of this page would go stale the moment the compiler said anything +// differently, and this page's whole claim is that it prints what the compiler +// prints. So the walkthrough moves through the page that is already here +// rather than a copy of it filmed in the past. +// +// No sound to turn off, and nothing that only works if you can see colour: the +// caption says what to look at and the section is scrolled to. + +const BUTTON = document.getElementById("walk"); +const CAPTION = document.getElementById("caption"); +const STEPS = Array.from(document.querySelectorAll("[data-step]")); + +const STILL = matchMedia("(prefers-reduced-motion: reduce)"); +const PAUSE = 4500; + +let at = -1; +let timer = null; + +function show(index) { + at = index; + const step = STEPS[at]; + for (const other of STEPS) other.classList.toggle("here", other === step); + CAPTION.textContent = `${at + 1} of ${STEPS.length}. ${step.dataset.step}`; + step.scrollIntoView({ + block: "center", + behavior: STILL.matches ? "auto" : "smooth", + }); +} + +function stop() { + clearTimeout(timer); + timer = null; + BUTTON.textContent = at + 1 < STEPS.length ? "Keep going" : "Start again"; +} + +function next() { + if (at + 1 >= STEPS.length) { + stop(); + return; + } + show(at + 1); + // Someone who wants to read a step should be able to. Auto-advance is off + // entirely when the reader has asked for less movement. + if (!STILL.matches) timer = setTimeout(next, PAUSE); + else stop(); +} + +BUTTON.addEventListener("click", () => { + if (timer) { + stop(); + return; + } + if (at + 1 >= STEPS.length) at = -1; + BUTTON.textContent = "Pause"; + next(); +}); + +// Anything that means "I am reading this myself" ends the tour rather than +// fighting it. +for (const event of ["wheel", "touchstart", "keydown"]) { + addEventListener(event, () => { + if (timer) stop(); + }, { passive: true }); +} diff --git a/one-clause/index.html b/one-clause/index.html index b05673a..797cf41 100644 --- a/one-clause/index.html +++ b/one-clause/index.html @@ -41,7 +41,12 @@

One clause, two worlds.

wrong, and why. --> -

Two functions

+
+ + +
+ +

Two functions

Identical, except for one line. They are demo/read_only.deed and @@ -82,7 +87,7 @@

read_write

-

Two worlds

+

Two worlds

Compiled to WebAssembly components, the import section of each module is its world. It lists what the module asks a host for, and @@ -108,7 +113,7 @@

read_write.wasm imports

code is the manifest.

-

What the host does with it

+

What the host does with it

A host that offers Io.read and not Io.save runs the first module and refuses the second. The refusal is not a @@ -134,7 +139,7 @@

What the host does with it

process executes.

-

None of this is checked by eye

+

None of this is checked by eye

The import sections, the host's refusal and the listing printed further up this page are all pinned in the compiler's repository, and @@ -156,7 +161,7 @@

None of this is checked by eye

import section with nothing to notice the prose no longer matching.

-

Try them

+

Try them

Both programs open in the playground, running the same compiler this page is describing. Add Io.save to the first one's @@ -166,14 +171,14 @@

Try them