fuzzyworld

nordic-skating / commit

docs: pace, and whose the pictures are; screenshots retaken

3f3d6bcebc8266d1750a25552b95f5eb04fe596b · Pavel Safronov · 2026-10-10 17:35:06 -0700 · parents 1ee103b4b9af

Claude Code usage: this commit ≈0 out / ≈0 cached · cost unknown (no per-model trailer) · session 1 tally 1.4K in / 1.2M out / 220.6M cached · usage by commit and session

docs: pace, and whose the pictures are; screenshots retaken

The skate and the two speakers are by Icongeek26. Whether the two tilt
pictures are as well is still to be confirmed, and the README says so.

Usage: 1.4K in / 1.2M out / 220.6M cached (session tally)
rtk:   1.7M saved, 25.3% over 2701 cmds (global/lifetime)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
 PLAN.md                               |  27 +++++++++++++--
 README.md                             |  63 +++++++++++++++++++++++++---------
 docs/screenshots/about.png            | Bin 226914 -> 227783 bytes
 docs/screenshots/aeroplane.png        | Bin 345858 -> 347456 bytes
 docs/screenshots/aurora-phone.png     | Bin 236951 -> 244134 bytes
 docs/screenshots/aurora.png           | Bin 289040 -> 294490 bytes
 docs/screenshots/autopilot.png        | Bin 189181 -> 195419 bytes
 docs/screenshots/blizzard.png         | Bin 181606 -> 186917 bytes
 docs/screenshots/comet.png            | Bin 277652 -> 283544 bytes
 docs/screenshots/dusk.png             | Bin 233670 -> 240088 bytes
 docs/screenshots/far.png              | Bin 254036 -> 259856 bytes
 docs/screenshots/fork.png             | Bin 327506 -> 328426 bytes
 docs/screenshots/island-alongside.png | Bin 210011 -> 217682 bytes
 docs/screenshots/island.png           | Bin 328058 -> 329403 bytes
 docs/screenshots/islets-dusk.png      | Bin 199652 -> 205122 bytes
 docs/screenshots/islets.png           | Bin 294338 -> 297626 bytes
 docs/screenshots/landscape.png        | Bin 253280 -> 257040 bytes
 docs/screenshots/night.png            | Bin 241177 -> 247456 bytes
 docs/screenshots/olympic.png          | Bin 0 -> 287430 bytes
 docs/screenshots/pass.png             | Bin 237300 -> 243410 bytes
 docs/screenshots/sea.png              | Bin 224383 -> 227671 bytes
 docs/screenshots/settings.png         | Bin 235018 -> 241399 bytes
 docs/screenshots/snow.png             | Bin 281763 -> 286762 bytes
 docs/screenshots/steering.png         | Bin 219260 -> 223866 bytes
 docs/screenshots/thin-ice.png         | Bin 279066 -> 282642 bytes
 docs/screenshots/tracks.png           | Bin 247850 -> 252677 bytes
 tools/screenshots.mjs                 |   2 ++
 27 files changed, 74 insertions(+), 18 deletions(-)

diff --git a/PLAN.md b/PLAN.md
index c617973..1504652 100644
--- a/PLAN.md
+++ b/PLAN.md
@@ -163,6 +163,26 @@ channel is left or joined.
 **Still to judge.** Is one every 5 km right? Do the reeds read as an island from a
 distance, or as a smudge? Should some islands be wooded, like the ones at forks?
 
+### 2c. Pace — built, waiting to be felt
+
+Asked for by Pavel on 2026-10-10: a peaceful meander, something faster, and something
+ridiculously fast, as if training for the Olympics, with whatever between makes sense.
+
+**What was built.** Five paces: Meander (13 km/h), Cruise (25, as it was), Brisk (36),
+Racing (45) and Olympic (54). A button at the bottom right steps through them; so do
+the up and down keys and a controller; and they are in Settings. Strides shorten and
+quicken with pace, the skater crouches, the view widens, the air rushes, the turning
+circle grows, and the autopilot looks and steers further ahead.
+
+**Still to judge.**
+- The names, which Pavel was not sure of.
+- Is Olympic fast enough to be ridiculous? It is a real speed skater's pace. There is
+  room above it, though the lake's bends and narrows were made for 25 km/h.
+- At a racing pace a skater is kept well back from the shores, so in ordinary water
+  there is not much steering to be done. Too restrictive?
+- Should a pass, a fork or a bed of islets slow a racer down?
+- Does the wider view at speed feel fast, or only odd?
+
 ### 3. Installable app — built, not yet tried on a phone
 
 A web manifest and a service worker, made by `vite-plugin-pwa`. Installed, the app has
@@ -174,8 +194,11 @@ Checked in a desktop browser: with the network off and the server stopped, the a
 opens, opens a lake by number, and Randomize works. Not checked: installing it on a
 phone, on either Android or an iPhone.
 
-**The icon** is a skate, supplied by Pavel: by Icongeek26, from Flaticon, credited in
-the About box and the README as its licence requires. The artwork is
+**The icons** are supplied by Pavel: a skate for the app and the pace button, and a
+speaker and a crossed-out speaker for the sound button, all by Icongeek26, from
+Flaticon, credited in the About box and the README as the licence requires. The Tilt
+button has a phone in a hand for on and a phone by itself for off, also supplied by
+Pavel; **to confirm: whether those two are by Icongeek26 as well**. The artwork is
 `assets/skate-shoes.png`, and `npm run icons` makes the home-screen and tab icons from
 it, pale on the colour of black ice.
 
diff --git a/README.md b/README.md
index d5351b3..868f2be 100644
--- a/README.md
+++ b/README.md
@@ -37,9 +37,9 @@ blizzard; with, some nights, a comet, and some days an aeroplane drawing its tra
 ## Controls
 
 The button at the top right turns the sound on and off, as does the M key, and shows
-which it is: a speaker, or a speaker struck through. Sound cannot start by itself: a
+which it is: a speaker, or a speaker crossed out. Sound cannot start by itself: a
 browser lets a page make sound only after it has been touched, so until then the
-speaker is struck through, and the first tap or key anywhere starts it. Turning it off is remembered for next time. On an iPhone the
+speaker is crossed out, and the first tap or key anywhere starts it. Turning it off is remembered for next time. On an iPhone the
 ring/silent switch also silences it.
 
 Do nothing and the skater follows the middle of the lake, round every bend and down
@@ -52,6 +52,7 @@ one side of every fork, for as long as you leave it.
 | Turn right round, or circle an islet | Hold the steer over | the same |
 | Choose a way at a fork, or a side of an island | A touch towards it on the way up | the same |
 | Sound on or off | The button at the top right | M |
+| Go faster or slower | The pace button at the bottom right: each press is the next pace up, and from the fastest back to the slowest | ↑ ↓ or W S |
 | Go to another lake | Randomize, at the top left | R |
 
 At the top left, **About** opens a box that explains the app and its controls, and
@@ -81,6 +82,7 @@ Each takes effect as it is touched, behind the box, and is remembered for next t
 |---|---|---|
 | Time of day | Surprise me, Day, Dusk, Night, Aurora | Surprise me: whichever the lake comes with |
 | Weather | Surprise me, Clear, Snow, Blizzard | Surprise me: whichever the lake comes with |
+| Pace | Meander, Cruise, Brisk, Racing, Olympic | Cruise |
 | Impossible ice | on or off | off |
 | Lake | Another lake (the same as Randomize); a link back to this one | a different lake every visit |
 
@@ -88,8 +90,9 @@ Each takes effect as it is touched, behind the box, and is remembered for next t
 
 ### Tilt to steer
 
-On a phone or tablet there is a **Tilt** button at the bottom left; anywhere else it is
-not shown. Turned on, which is remembered, the phone is leaned
+On a phone or tablet there is a **Tilt** button at the bottom left, showing a phone held
+in a hand when tilt is on and a phone by itself when it is off; anywhere else it is not
+shown. Turned on, which is remembered, the phone is leaned
 left or right like a wheel, about the line the skater looks along: more lean, tighter
 turn, full steering at 28°. Within 4° of level counts as level, since nobody holds a
 phone dead level, and held level the skater skates itself. It works held upright or on
@@ -175,8 +178,9 @@ address asks for a weather whatever the settings say.
 
 <img src="docs/screenshots/snow.png" alt="Snow falling over the lake by day" width="640" />
 
-**A game controller** works as well: either stick or the direction buttons steer, Y or
-triangle goes to another lake, and X or square turns the sound on and off. It needs no
+**A game controller** works as well: either stick or the direction buttons steer, up
+and down on the direction buttons or the shoulder buttons change pace, Y or triangle
+goes to another lake, and X or square turns the sound on and off. It needs no
 setting up beyond being connected, though a browser shows a page a controller only
 once one of its buttons has been pressed.
 
@@ -196,9 +200,27 @@ you sent it off at an angle, and settling back to its usual 6 m over about twent
 seconds. It does not return to where it was, or to the middle of the lake. Steer left
 out of a right-hand curve and you have a left-hand curve.
 
-The speed breathes with the stride: each push adds about 1 m/s over half a second, and
-the glide after it gives that back, around 7 m/s (25 km/h). Strides last 1.4 to 3.2 s
-and no two are the same, so neither are the speeds.
+The speed breathes with the stride: each push adds about a seventh of it, and the glide
+after it gives that back. Strides are of different lengths, and no two the same, so
+neither are the speeds.
+
+### Pace
+
+| Pace | Speed | Strides | Turning circle | |
+|---|---|---|---|---|
+| Meander | 3.5 m/s, 13 km/h | 2 to 4.5 s, long and lazy | 8 m | Standing tall. Tight enough to circle an islet closely |
+| Cruise | 7 m/s, 25 km/h | 1.4 to 3.2 s | 16 m | Where it starts |
+| Brisk | 10 m/s, 36 km/h | 1 to 2.4 s | 22 m | |
+| Racing | 12.5 m/s, 45 km/h | 0.8 to 1.9 s | 31 m | |
+| Olympic | 15 m/s, 54 km/h | 0.6 to 1.4 s, short and quick | 45 m | Down in a crouch. The pace of a long-track speed skater in a 1500 m, kept up for ever |
+
+A change of pace is worked up to, or eased down to, over a few strides. Everything
+else follows the speed. A faster skater is held to half a g sideways and so turns in a
+wider circle; looks further ahead, and steers round an islet from further off; keeps
+further from the shores, which in ordinary water leaves a racer little room to weave;
+swings wider on the autopilot's line; sees a wider view, which is most of what makes
+speed look like speed; and hears the air rush past. The pace is remembered, and
+`?pace=olympic` on the address asks for one for a visit.
 
 The screen is kept awake while the page is open, where the browser allows it.
 
@@ -400,7 +422,8 @@ npm run icons  # remake the home-screen and tab icons from assets/skate-shoes.pn
 ```
 
 On the address: `?seed=1` asks for lake number 1, `?time=night` for a time of day (`day`,
-`dusk`, `night`, `aurora`), `?weather=snow` for a weather (`clear`, `snow`, `blizzard`),
+`dusk`, `night`, `aurora`), `?weather=snow` for a weather (`clear`, `snow`, `blizzard`), `?pace=olympic` for a pace
+(`meander`, `cruise`, `brisk`, `racing`, `olympic`),
 and `?s=2500` starts that many metres down the lake. The
 screenshots use all three, so that they are of the same thing every run.
 
@@ -418,17 +441,25 @@ named `public`, and a `public/` already in the repository would collide with it.
 
 ## Licence
 
-[MIT](LICENSE), for everything here but the icon. What it builds on is credited below.
+[MIT](LICENSE), for everything here but the icons. What it builds on is credited below.
 
 ## Attribution
 
-- The app's icon is a skate by [Icongeek26](https://www.flaticon.com/authors/icongeek26),
-  from Flaticon, used under the Flaticon free licence, which requires attribution. The
-  credit is in the app's About box as well as here. The artwork is
-  `assets/skate-shoes.png`; the icons in `static/` are made from it by `npm run icons`,
+- The app's icon and the pictures on its buttons are by
+  [Icongeek26](https://www.flaticon.com/authors/icongeek26), from Flaticon, used under
+  the Flaticon free licence, which requires attribution. The credit is in the app's
+  About box as well as here. None of them is covered by this project's MIT licence.
+- Of those, the app's icon is a skate. The artwork is `assets/skate-shoes.png`; the icons in `static/` are made from it by `npm run icons`,
   which uses only its shape: pale on the colour of black ice for a home screen, and
   as it was drawn, black on a see-through background, for a browser's tab (white where
-  the browser is dark). It is not covered by this project's MIT licence.
+  the browser is dark). The same skate is on the pace button.
+- And the pictures on the sound button, a speaker and a speaker crossed out, are
+  `assets/sound-on.png` and `assets/sound-off.png`. On a button only a picture's shape
+  is used, in the colour of the button's words.
+- The pictures on the Tilt button, a phone held in a hand for on and a phone by itself
+  for off, are `assets/tilt-on.png` and `assets/tilt-off.png`. **Whether these two are
+  by the same author has not been confirmed**; if they are not, the credit here and in
+  the About box needs their author added.
 - [three.js](https://threejs.org/) — MIT licence.
 - [simplex-noise](https://github.com/jwagner/simplex-noise.js) — MIT licence.
 - [Workbox](https://developer.chrome.com/docs/workbox), by way of
diff --git a/docs/screenshots/about.png b/docs/screenshots/about.png
index 4c33171..9b99837 100644
Binary files a/docs/screenshots/about.png and b/docs/screenshots/about.png differ
diff --git a/docs/screenshots/aeroplane.png b/docs/screenshots/aeroplane.png
index 0fbd401..338f263 100644
Binary files a/docs/screenshots/aeroplane.png and b/docs/screenshots/aeroplane.png differ
diff --git a/docs/screenshots/aurora-phone.png b/docs/screenshots/aurora-phone.png
index 2ce9fcf..5f95510 100644
Binary files a/docs/screenshots/aurora-phone.png and b/docs/screenshots/aurora-phone.png differ
diff --git a/docs/screenshots/aurora.png b/docs/screenshots/aurora.png
index 29e16a8..c0e0010 100644
Binary files a/docs/screenshots/aurora.png and b/docs/screenshots/aurora.png differ
diff --git a/docs/screenshots/autopilot.png b/docs/screenshots/autopilot.png
index 8054d1a..835a32a 100644
Binary files a/docs/screenshots/autopilot.png and b/docs/screenshots/autopilot.png differ
diff --git a/docs/screenshots/blizzard.png b/docs/screenshots/blizzard.png
index 86caca0..f79fcc0 100644
Binary files a/docs/screenshots/blizzard.png and b/docs/screenshots/blizzard.png differ
diff --git a/docs/screenshots/comet.png b/docs/screenshots/comet.png
index b2fa7c0..4648106 100644
Binary files a/docs/screenshots/comet.png and b/docs/screenshots/comet.png differ
diff --git a/docs/screenshots/dusk.png b/docs/screenshots/dusk.png
index 39585e8..dbfdd72 100644
Binary files a/docs/screenshots/dusk.png and b/docs/screenshots/dusk.png differ
diff --git a/docs/screenshots/far.png b/docs/screenshots/far.png
index d597044..fd7d785 100644
Binary files a/docs/screenshots/far.png and b/docs/screenshots/far.png differ
diff --git a/docs/screenshots/fork.png b/docs/screenshots/fork.png
index babcab9..91c3fe1 100644
Binary files a/docs/screenshots/fork.png and b/docs/screenshots/fork.png differ
diff --git a/docs/screenshots/island-alongside.png b/docs/screenshots/island-alongside.png
index 7b3f029..9d3b472 100644
Binary files a/docs/screenshots/island-alongside.png and b/docs/screenshots/island-alongside.png differ
diff --git a/docs/screenshots/island.png b/docs/screenshots/island.png
index 0c9e71c..b7bf0a2 100644
Binary files a/docs/screenshots/island.png and b/docs/screenshots/island.png differ
diff --git a/docs/screenshots/islets-dusk.png b/docs/screenshots/islets-dusk.png
index 69a625e..3edd3bd 100644
Binary files a/docs/screenshots/islets-dusk.png and b/docs/screenshots/islets-dusk.png differ
diff --git a/docs/screenshots/islets.png b/docs/screenshots/islets.png
index 8a157d8..30054d6 100644
Binary files a/docs/screenshots/islets.png and b/docs/screenshots/islets.png differ
diff --git a/docs/screenshots/landscape.png b/docs/screenshots/landscape.png
index fb17f56..a4328a1 100644
Binary files a/docs/screenshots/landscape.png and b/docs/screenshots/landscape.png differ
diff --git a/docs/screenshots/night.png b/docs/screenshots/night.png
index 4fe22bf..0d9c98c 100644
Binary files a/docs/screenshots/night.png and b/docs/screenshots/night.png differ
diff --git a/docs/screenshots/olympic.png b/docs/screenshots/olympic.png
new file mode 100644
index 0000000..a7f6aea
Binary files /dev/null and b/docs/screenshots/olympic.png differ
diff --git a/docs/screenshots/pass.png b/docs/screenshots/pass.png
index c9fe818..a862786 100644
Binary files a/docs/screenshots/pass.png and b/docs/screenshots/pass.png differ
diff --git a/docs/screenshots/sea.png b/docs/screenshots/sea.png
index cbd21fc..b6ecec0 100644
Binary files a/docs/screenshots/sea.png and b/docs/screenshots/sea.png differ
diff --git a/docs/screenshots/settings.png b/docs/screenshots/settings.png
index af3d2b0..5209d14 100644
Binary files a/docs/screenshots/settings.png and b/docs/screenshots/settings.png differ
diff --git a/docs/screenshots/snow.png b/docs/screenshots/snow.png
index faea993..0db2957 100644
Binary files a/docs/screenshots/snow.png and b/docs/screenshots/snow.png differ
diff --git a/docs/screenshots/steering.png b/docs/screenshots/steering.png
index f3ff21a..f0d33ab 100644
Binary files a/docs/screenshots/steering.png and b/docs/screenshots/steering.png differ
diff --git a/docs/screenshots/thin-ice.png b/docs/screenshots/thin-ice.png
index d670f30..e7b6e43 100644
Binary files a/docs/screenshots/thin-ice.png and b/docs/screenshots/thin-ice.png differ
diff --git a/docs/screenshots/tracks.png b/docs/screenshots/tracks.png
index 483a533..3400caf 100644
Binary files a/docs/screenshots/tracks.png and b/docs/screenshots/tracks.png differ
diff --git a/tools/screenshots.mjs b/tools/screenshots.mjs
index 72be2eb..e872eda 100644
--- a/tools/screenshots.mjs
+++ b/tools/screenshots.mjs
@@ -49,6 +49,8 @@ const SHOTS = [
       await page.keyboard.up('ArrowRight')
     },
   },
+  // At an Olympic pace, a few seconds in: down in a crouch, with a wider view.
+  { name: 'olympic', query: '?seed=1&weather=clear&time=day&pace=olympic&s=5200', viewport: { width: 844, height: 390 }, act: async (page) => { await page.waitForTimeout(9000) } },
   // The same water at the other times of day.
   { name: 'dusk', query: '?seed=1&weather=clear&time=dusk&s=5200', viewport: { width: 844, height: 390 }, act: async () => {} },
   { name: 'night', query: '?seed=1&weather=clear&time=night&s=5200', viewport: { width: 844, height: 390 }, act: async () => {} },