nordic-skating / commit
docs: the sky's visitors, the weather, and what is named and not yet built
PLAN.md | 44 +++++++++++++++++++++++++++++++++++++- README.md | 39 ++++++++++++++++++++++++++++++--- docs/screenshots/about.png | Bin 223387 -> 223868 bytes docs/screenshots/aeroplane.png | Bin 0 -> 384016 bytes docs/screenshots/aurora-phone.png | Bin 256152 -> 255430 bytes docs/screenshots/aurora.png | Bin 308040 -> 308507 bytes docs/screenshots/autopilot.png | Bin 226224 -> 231399 bytes docs/screenshots/blizzard.png | Bin 0 -> 197232 bytes docs/screenshots/comet.png | Bin 0 -> 264905 bytes docs/screenshots/dusk.png | Bin 256885 -> 262119 bytes docs/screenshots/far.png | Bin 264297 -> 271905 bytes docs/screenshots/fork.png | Bin 338327 -> 342342 bytes docs/screenshots/islets-dusk.png | Bin 199662 -> 206712 bytes docs/screenshots/islets.png | Bin 300899 -> 304547 bytes docs/screenshots/landscape.png | Bin 280727 -> 283927 bytes docs/screenshots/night.png | Bin 259964 -> 261510 bytes docs/screenshots/pass.png | Bin 223547 -> 231057 bytes docs/screenshots/sea.png | Bin 231845 -> 237546 bytes docs/screenshots/settings.png | Bin 218026 -> 215007 bytes docs/screenshots/snow.png | Bin 0 -> 275512 bytes docs/screenshots/steering.png | Bin 179001 -> 178739 bytes docs/screenshots/thin-ice.png | Bin 284179 -> 287907 bytes tools/screenshots.mjs | 37 ++++++++++++++++++-------------- 23 files changed, 100 insertions(+), 20 deletions(-) diff --git a/PLAN.md b/PLAN.md index dcc043e..7efb122 100644 --- a/PLAN.md +++ b/PLAN.md @@ -93,6 +93,48 @@ how hilly, the colour of the aurora, how fast it moves. **Ideas for more settings**, none started: speed, how far the autopilot carves, how long the strides are, how much the ice cracks, falling through, the haze. +### 2b. More in the scene — partly built + +Pavel, 2026-10-10: more details in the scene are welcome, and named these. + +**Built, waiting to be looked at.** +- **In the sky**: shooting stars at night; a comet over one night lake in three; an + aeroplane and its trail over two day or dusk lakes in three. +- **Weather**: clear, snow, or a blizzard, as a setting that starts on "Surprise me". + Falling snow that streams past the skater, wind from a direction of the lake's own, + the wind's sound, cloud over the sky, and less distance to see through. + +**Still to judge.** Is a blizzard thick enough, and is 200 m too little to see by? Is +the wind too loud over the ice? Are shooting stars too frequent? The aeroplane is +silent; should it be? + +**Named and not yet built.** +- **Snow drifts**: snow lying on the ice in streaks blown by the wind, building up in + a blizzard. They would want to slow a skater and deaden the ice's sound where they + lie, which is the "bad ice" of the first description of this app. +- **Cracks made by the skater**: on ice thin enough to crack, the cracks that are now + only heard would be seen, spreading from under the skates and left behind. This + needs a way to draw on the ice where the skater has been, which would also give + skate tracks, loops and all, as in the film. +- **A long island in the middle of the lake**: see "Channels that part and join again". + +**Further ideas, none started**: a moon and its phase; mist that thins and thickens; +dawn; how wooded and how hilly the banks are; the colour of the aurora; birds; a far +shore with the lights of a house at night; satellites; a bare rock, as in the film. + +### Channels that part and join again + +**Pavel's question**: is this something like a long island of grass in the middle of a +lake or river? **Yes.** Today a fork's two channels draw apart and never meet again: +the lake is a tree. The other kind is an island with water both sides that comes back +together beyond it: a few hundred metres long, low, covered in reeds like the islets, +or wooded like the banks. The skater picks a side, and both lead on to the same lake. + +It is a smaller thing to build than it sounds, since a fork already is two channels +drawn side by side: this is a fork whose channels come back to the same line. What it +needs that forks do not have is the rejoining: both channels drawn all the way along +the island, and the skater's channel becoming the one channel again at its far end. + ### 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 @@ -140,7 +182,7 @@ And at 1:17 the ice is measured on camera: 45 mm. The sound alone gives 41 mm. - Are there too many islets, or too few? Do the reeds look like reeds? **Not done, and wanted or possible.** -- Forks of three, and channels that part and join again. +- Forks of three. Channels that part and join again: see the section of that name. - A bare rock, as in the film. A drawing of the skater's own tracks on the ice, as in the film: with loops now possible, they would show them. - Forks cannot be gone back through: a skater who turns back above a fork stays in the diff --git a/README.md b/README.md index 9cbde2d..99b1f1c 100644 --- a/README.md +++ b/README.md @@ -22,7 +22,8 @@ a pitch set by how thick it is there. Thin ice is black, sings high and cracks u you. Nobody falls through: how thick the ice is decides only how it sounds. Every visit is to a different lake, one of a million, by day, at dusk, at night under -the Milky Way, or under the northern lights. +the Milky Way, or under the northern lights; in clear air, in falling snow, or in a +blizzard; with, some nights, a comet, and some days an aeroplane drawing its trail. <img src="docs/screenshots/aurora.png" alt="The lake at night under green curtains of aurora" width="640" /> @@ -79,6 +80,7 @@ Each takes effect as it is touched, behind the box, and is remembered for next t | Setting | Choices | To begin with | |---|---|---| | 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 | | Impossible ice | on or off | off | | Lake | Another lake (the same as Randomize); a link back to this one | a different lake every visit | @@ -109,7 +111,8 @@ Browsers give a page the phone's tilt only over HTTPS, which the live site is an ### A different lake every visit A lake is a number from 1 to 999,999, and everything about it follows from the number: -its bends, widths and forks, its ice, its trees, and the time of day it comes with. +its bends, widths and forks, its ice, its trees, the time of day and the weather it +comes with, which way its wind blows, and what is in its sky. Opening the app picks a number, and so do Randomize and reloading the page: each is a new lake under a new sky. Settings shows the number and a link to it, and `?seed=1234` on the address asks for a lake by number, which is how to come back to one or send it @@ -136,6 +139,34 @@ address asks for a time whatever the settings say. <img src="docs/screenshots/night.png" alt="The lake at night, the Milky Way overhead" width="640" /> +### What else is in the sky + +- **Shooting stars**, at night and under the aurora: one every quarter of a minute or + so, somewhere in the sky, gone in under a second. +- **A comet**, over one night lake in three: ahead and low, with a tail. +- **An aeroplane**, over two day or dusk lakes in three: a bright speck crossing the + sky ahead in four or five minutes, drawing a trail that widens and fades behind it, + white by day and pink at dusk. When it has gone, a while later another comes. + +<img src="docs/screenshots/comet.png" alt="A comet with a long tail over the lake at night" width="640" /> + +### Weather + +| Weather | Snow | How far you can see | The sky | Wind | How often a lake comes with it | +|---|---|---|---|---|---| +| Clear | none | 600 m | as the time of day has it | none | 64% | +| Snow | falling quietly | 420 m | mostly cloud | 0.5 to 3 m/s | 26% | +| Blizzard | thick, and driven | 200 m | all cloud | 7 to 16 m/s, in gusts | 10% | + +Snow is a box of flakes that stays round the skater (`src/render/snow.ts`): they fall, +the wind carries them, and they stream past as the skater moves, which is most of what +makes a blizzard feel fast. Each lake's wind blows from a direction of its own. The wind +can be heard, louder and higher in its gusts. Cloud hides the stars, the aurora and +whatever else is up there, and takes the colour out of a sunset. `?weather=snow` on the +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" /> + Steering turns the skater: the harder the steer, the tighter the curve, up to a circle 16 m in radius, with a moment to lean into it. Held over, the skater turns right round and can skate back up the lake, or round and round; that needs open water, about 24 m @@ -289,6 +320,7 @@ measured the spreading directly, with instruments on the ice. - **The ring**: at each stride, every 1.4 to 3.2 s, a skate strikes the ice, which answers with a narrow band of noise at its note, starting a little high and falling onto it, then dying away. - **The hum and the scrape**: the gliding blade keeps the note faintly alive and hisses. +- **The wind**, when there is one: low, loose noise, louder and higher in its gusts. - **The cracks**: every few seconds the ice cracks somewhere between 40 and 600 m off, and the chirp for that distance and that thickness arrives. The falling chirp is a sine wave and stops the moment it lands on the note; what rings on after it is the @@ -321,7 +353,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`), and `?s=2500` starts that many metres down the lake. The +`dusk`, `night`, `aurora`), `?weather=snow` for a weather (`clear`, `snow`, `blizzard`), +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. The screenshots and the sound check need Playwright's Chromium once: diff --git a/docs/screenshots/about.png b/docs/screenshots/about.png index c684294..9a6b17f 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 new file mode 100644 index 0000000..5fc73da Binary files /dev/null and b/docs/screenshots/aeroplane.png differ diff --git a/docs/screenshots/aurora-phone.png b/docs/screenshots/aurora-phone.png index 14dd639..c7d6e12 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 f5cbb0c..e1613be 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 4be3eef..c7688f7 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 new file mode 100644 index 0000000..f7ff35a Binary files /dev/null and b/docs/screenshots/blizzard.png differ diff --git a/docs/screenshots/comet.png b/docs/screenshots/comet.png new file mode 100644 index 0000000..8450f05 Binary files /dev/null and b/docs/screenshots/comet.png differ diff --git a/docs/screenshots/dusk.png b/docs/screenshots/dusk.png index 8961610..516e977 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 2d0b531..27e20e7 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 f1438b8..5c49207 100644 Binary files a/docs/screenshots/fork.png and b/docs/screenshots/fork.png differ diff --git a/docs/screenshots/islets-dusk.png b/docs/screenshots/islets-dusk.png index 943ab2d..809cba2 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 e38e926..4a4b063 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 097cd56..6481b1b 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 4f034b9..907d94c 100644 Binary files a/docs/screenshots/night.png and b/docs/screenshots/night.png differ diff --git a/docs/screenshots/pass.png b/docs/screenshots/pass.png index 28222a9..862f4a1 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 bf8fcd3..62fb7ac 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 a13248e..03a04c8 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 new file mode 100644 index 0000000..d7746cc Binary files /dev/null and b/docs/screenshots/snow.png differ diff --git a/docs/screenshots/steering.png b/docs/screenshots/steering.png index 5923e50..d2157d2 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 b881552..3d1ddea 100644 Binary files a/docs/screenshots/thin-ice.png and b/docs/screenshots/thin-ice.png differ diff --git a/tools/screenshots.mjs b/tools/screenshots.mjs index a696c72..805a7c3 100644 --- a/tools/screenshots.mjs +++ b/tools/screenshots.mjs @@ -16,34 +16,39 @@ const PHONE = { width: 390, height: 844 } * time of day by name, so that the pictures are of the same thing from one run to the next. */ const SHOTS = [ - { name: 'autopilot', query: '?seed=1&time=day&s=400', act: async () => {} }, + { name: 'autopilot', query: '?seed=1&weather=clear&time=day&s=400', act: async () => {} }, { name: 'steering', - query: '?seed=1&time=day&s=2600', + query: '?seed=1&weather=clear&time=day&s=2600', act: async (page) => { await page.keyboard.down('ArrowRight') await page.waitForTimeout(1500) }, }, // The first fork: the island between its two channels is a little way ahead. - { name: 'fork', query: '?seed=1&time=day&s=790', viewport: { width: 844, height: 390 }, act: async () => {} }, - { name: 'pass', query: '?seed=1&time=day&s=6400', act: async () => {} }, - { name: 'sea', query: '?seed=1&time=day&s=3400', viewport: { width: 844, height: 390 }, act: async () => {} }, + { name: 'fork', query: '?seed=1&weather=clear&time=day&s=790', viewport: { width: 844, height: 390 }, act: async () => {} }, + { name: 'pass', query: '?seed=1&weather=clear&time=day&s=6400', act: async () => {} }, + { name: 'sea', query: '?seed=1&weather=clear&time=day&s=3400', viewport: { width: 844, height: 390 }, act: async () => {} }, // Impossibly thin ice lies to the left of the middle here, faintly lit from within. - { name: 'thin-ice', query: '?seed=1&time=day&s=2795', viewport: { width: 844, height: 390 }, act: async () => {} }, - { name: 'about', query: '?seed=1&time=day&s=400', act: async (page) => { await page.click('#about') } }, + { name: 'thin-ice', query: '?seed=1&weather=clear&time=day&s=2795', viewport: { width: 844, height: 390 }, act: async () => {} }, + { name: 'about', query: '?seed=1&weather=clear&time=day&s=400', act: async (page) => { await page.click('#about') } }, // A bed of reed islets, just down the lake from where it starts. - { name: 'islets', query: '?seed=1&time=day&s=150', viewport: { width: 844, height: 390 }, act: async () => {} }, - { name: 'islets-dusk', query: '?seed=1&time=dusk&s=7040', act: async () => {} }, + { name: 'islets', query: '?seed=1&weather=clear&time=day&s=150', viewport: { width: 844, height: 390 }, act: async () => {} }, + { name: 'islets-dusk', query: '?seed=1&weather=clear&time=dusk&s=7040', act: async () => {} }, // The same water at the other times of day. - { name: 'dusk', query: '?seed=1&time=dusk&s=5200', viewport: { width: 844, height: 390 }, act: async () => {} }, - { name: 'night', query: '?seed=1&time=night&s=5200', viewport: { width: 844, height: 390 }, act: async () => {} }, - { name: 'aurora', query: '?seed=1&time=aurora&s=5200', viewport: { width: 844, height: 390 }, act: async () => {} }, - { name: 'aurora-phone', query: '?seed=1&time=aurora&s=400', act: async () => {} }, - { name: 'settings', query: '?seed=1&time=night&s=400', act: async (page) => { await page.click('#settings') } }, - { name: 'landscape', query: '?seed=1&time=day&s=5200', viewport: { width: 844, height: 390 }, act: async () => {} }, + { 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 () => {} }, + { name: 'aurora', query: '?seed=1&weather=clear&time=aurora&s=5200', viewport: { width: 844, height: 390 }, act: async () => {} }, + { name: 'aurora-phone', query: '?seed=1&weather=clear&time=aurora&s=400', act: async () => {} }, + { name: 'settings', query: '?seed=1&weather=clear&time=night&s=400', act: async (page) => { await page.click('#settings') } }, + // Weather, and what is in the sky besides stars. Lake 13 has a comet and lake 2 an aeroplane. + { name: 'snow', query: '?seed=1&weather=snow&time=day&s=5200', viewport: { width: 844, height: 390 }, act: async () => {} }, + { name: 'blizzard', query: '?seed=1&weather=blizzard&time=dusk&s=5200', act: async () => {} }, + { name: 'comet', query: '?seed=13&weather=clear&time=night&s=3400', viewport: { width: 844, height: 390 }, act: async () => {} }, + { name: 'aeroplane', query: '?seed=2&weather=clear&time=day&s=3400', viewport: { width: 844, height: 390 }, act: async () => {} }, + { name: 'landscape', query: '?seed=1&weather=clear&time=day&s=5200', viewport: { width: 844, height: 390 }, act: async () => {} }, // Ten thousand kilometres down the lake: the picture must be as sharp as at the start. - { name: 'far', query: '?seed=1&time=day&s=10000000', act: async () => {} }, + { name: 'far', query: '?seed=1&weather=clear&time=day&s=10000000', act: async () => {} }, ] mkdirSync(OUT, { recursive: true })