A wall of analog clocks that together tell the time.
Now and then the wall glitches: every clock breaks away into a shared pattern, holds it for a few seconds, then springs back to the time. Made to sit on a second screen and catch your eye when you look back at it.
Live at timewith.fun.
Every load opens on a start screen over a still wall. Pick Classic or Trip and a theme, and press Start fullscreen (or Enter): a tear drops on the wall from the button. Start in a window (or Esc) starts without fullscreen, leaving it if the page is fullscreen. Where the browser can't go fullscreen, like on iPhones, there is just Start. After that, any key, mouse move or tap shows settings in the corner: mode, theme and fullscreen. They fade out after a few seconds without input, or right away on Esc. Exit to main menu, their last row, stops the show and brings back the start screen over a still wall, to start again like the first time.
A bigger window means more clocks. On a narrow wall, like a phone, the hours sit above the minutes.
Once started, the mouse cursor vanishes into the nearest clock. Move it and the clock resists, glued to the wall, trembling harder the further you pull, until it rips off and becomes your cursor: its ring gone, its hands locked into an arrow that points up and to the left at rest and swings round to point wherever you head. Rest for a few seconds and it drifts back to its place, and the cursor vanishes into the clock nearest to it again. Over the settings, the clock rips off right away and stays your cursor, drawn over them, for as long as you are there.
At /, in grayscale.
Shows the time and glitches into a pattern every 1-3 minutes.
Every clock the digits leave blank quietly shows the real time as an analog clock, with a short hour hand and faint hands.
Once started, the cursor pulls the hands of the clocks near it round like a magnet, fully close by and less further off, coloring them into a color wheel around it.
Rest for a few seconds and it lets go.
At /trip: colors, gently swelling clocks and love-themed patterns that bloom into each other nonstop.
Every hand keeps turning, the tempo ebbs and flows, and every run gets its own center, direction and twist, so the show never visibly repeats.
Every few patterns a phrase shows: a warm question, a nudge, or a quote from Rumi, Rilke, Thich Nhat Hanh and others. A wave runs down the wall and writes the whole phrase in as it passes: hands slow down and settle into letters while the pattern plays on around them. The next wave washes it out again, the letters easing back into the pattern, or writes the next part in, as with I LOVE YOU, then DO YOU LOVE YOU. Word ladders like LOVE, LIVE, LIFE morph in place, only the changed letter turning. Letters are outlines drawn by the hands, running diagonally where a letter slants or rounds off.
LOVE MOVES PEOPLE alone comes as a spectacle, a word at a time: the wall calms down, then the words show on one half while rings move the other. One clock starts turning as the first word writes itself in, a few around it follow word by word, and with the last word the rings spread over the rest of the wall, faster and faster.
Press w to show the time for a few seconds between patterns.
| Key | Action |
|---|---|
w |
Play patterns back to back, or stop (trip starts on) |
g |
Glitch now |
1-9 |
Play that pattern of the mode and hold it, until g |
d |
Switch between light and dark |
| Esc | Hide settings |
Add ?demo=N to the URL, like /trip?demo=9, to hold pattern N from the start, e.g. to record it.
Add ?stream=1 to start on its own in the dark theme, with no start screen or settings, e.g. as a live stream's browser source.
Add ?scale=N, from 0.5 to 4, to draw the clocks N times their size, and fewer of them.
Click or tap the wall to send a ripple out from there: every clock it passes spins a whole turn and lands right back on what it showed.
The theme is dark until you pick Light, System or Dark (or press d), and the pick is remembered.
With reduced motion turned on, hands snap into place, patterns never play and clicks send no ripples.
<script lang="ts">
import { CLASSIC } from '$lib/game/modes';
import ClockWall from '$lib/ui/ClockWall.svelte';
</script>
<div style="height: 16rem">
<ClockWall mode={CLASSIC} />
</div>The wall fills its container and plays right away, in the system theme unless dark says otherwise.
Pass waiting to keep its hands flat and still until drop(x, y) (via bind:this) drops a tear at viewport px x, y, like the start screen does.
wait() goes back to that.
src/routes/+layout.svelte draws one wall for both routes, with the start screen and settings over it.
Switching modes keeps the clocks where they are and only fades the colors over.
The wall is an ECS in src/lib/game/.
Each grid cell is an entity, and components are typed arrays (Float32Array per field), so there are no objects per clock.
One requestAnimationFrame loop runs the systems in order:
sys_glitch: starts and ends patterns, blooms each one out over the last, and points hands along the running ones. It also directs the phrases: which pattern plays under which words, and when the rings of the spectacle move each clock.sys_words: runs waves down the wall that turn the clocks under each glyph of a phrase into letters as they pass, and let them go again. Words are planned ahead withplan_words, so the spectacle can be timed to them.sys_time: points the remaining hands at the current HH:MM. In classic, the clocks the digits leave blank become stealth clocks showing the real time.sys_ripple: runs ripples out from where the wall was clicked, spinning each clock they pass a whole turn on top of whatever it shows.sys_cursor: glues the clock the cursor has to the wall until it rips off, then hangs it from the cursor as an arrow of its hands that swings to point where it heads, and brings it home after a rest.sys_magnet: bends the hands of the stealth clocks near the pointer round to point at it, and lets go after a rest. The bends are only drawn, so a magnet can swing hands either way while underneath they still only turn clockwise.sys_reveal: fades the wall in as a diagonal wave on load.sys_spring: moves every hand on a critically damped spring, always clockwise, and eases sizes and stealth.sys_draw: draws every clock in one instanced WebGL2 call, only when something moved, lifted clocks on top, and the clock hanging from the cursor on a second canvas above the page.
A 4K wall (~8500 clocks) holds 120fps with the main thread about 4% busy.
A pattern is a function in src/lib/game/modes.ts.
It gets a clock's offset from the pattern center (x, y, in cells), the seconds since the pattern started (t), half the shorter wall side (span) and a random number fixed for the run (r).
It returns both hand angles in degrees, plus an optional clock size.
Hands must keep turning clockwise as t grows.
Every run gets a random center and its own ebb and flow of t for free.
// Diagonal wave rolling across the wall.
const wave: Pattern = (x, y, t) => [
...line((x + y) * 15 + t * 120),
swell((x + y) * 0.3 - t * 1.2)
];Add it to a mode's patterns list.
A mode is a plain object in the same file: which patterns it plays, how long patterns and the time show, and whether it uses colors and sizes.
HAND_FREQUENCYinsrc/lib/game/components.ts: how snappy hands are.swell()insrc/lib/game/modes.ts: how much and how fast clock sizes change.phrasesinsrc/lib/game/modes.ts: what trip says, andPHRASE_EVERYinsrc/lib/game/sys_glitch.ts: how often.SPEED,SWELLandHOLDinsrc/lib/game/sys_words.ts: how fast the waves run down the wall, how much they swell clocks, and how long a phrase holds.LETTER_FREQUENCYinsrc/lib/game/components.ts: how gently letters settle.CALM_FOR,MOVED,CASCADEandRINGS_FORinsrc/lib/game/sys_glitch.ts: how the spectacle builds up.RIP,GIVE,REST,SPREAD,SPEEDandSWINGinsrc/lib/game/sys_cursor.ts: how hard a clock is glued, how long the cursor rests before it goes home, how wide its arrow is, and how quickly and loosely the arrow turns to where it heads.NEAR,FAR,GRIPandSWAYinsrc/lib/game/sys_magnet.ts: how far the magnet reaches, how quickly it takes hold and lets go, and how quickly hands swing round to it.THEMESand thetint()shader insrc/lib/game/sys_draw.ts: colors and grayscale shading, andHOURandFAINT: how short and faint stealth clocks' hands are.
pnpm install
pnpm devOpen the URL Vite prints.
pnpm test: plays every pattern and phrase headless and fails if a hand turns backwards, a trip hand stops, a pattern comes back too soon, the time does not come back, sizes pulse, words show out of turn, the spectacle's rings spread too soon, the cursor's clock rips off too easily, points wrong or never gets home, or the magnet points hands wrong or never lets go. Needs Node 22.18 or later.pnpm check: type check.pnpm lint: Prettier and ESLint.pnpm build: static production build inbuild/.pnpm run deploy: builds and deploys to Cloudflare at timewith.fun (wrangler.jsonc). Needswrangler loginfirst. The old time.readsimon.com is a separatetime-readsimon-redirectWorker that 301s to timewith.fun, keeping path and query.
Copyright (c) 2025 Szymon Gracki. Licensed under the GNU AGPL v3.



