Sometimes a project starts with a single visual idea — and then it grows into multiple implementations, each teaching you something different.
This one began as a fascination with “clock hands as pixels”: lots of small analog clocks arranged in a grid, where each clock has two hands that rotate to form shapes, patterns, and eventually a readable time display.
Inspiration credit: the spark came from ClockClock by Humans since 1982 — beautiful kinetic clock artworks made from many small clocks. If you’re into this aesthetic, you can actually buy these artworks there. My project is a software homage to that concept.
The result is A Million Times — a Windows screensaver and a web version that runs smoothly on an nginx-hosted page.
- Web: https://www.a-million-times.com
- Repo (web): https://github.com/techniccontroller/a-million-times
- Repo (screensaver): https://github.com/techniccontroller/a-million-times-screensaver
The core idea: hands as pixels
Instead of drawing pixels, I draw two rotating bars (hands) inside each cell. With enough cells, the brain starts reading the grid as a coherent image.
Each “pixel clock” has:
- a center hub
- a background face (subtle radial gradient)
- two hands, each with a target angle
Then I define patterns as “target angle fields”: for every grid cell, compute two angles (A, B) and animate the hands to those targets.
That “angle field” concept is the key: once you have it, you can generate patterns from:
- geometry (circles, tangents, vectors)
- math fields (vortex / flow maps)
- discrete glyph patterns (digits for time)
Two implementations, one visual language
1) Windows screensaver (C# / WinForms)
The screensaver version is the “native” implementation. I went with WinForms because it’s lightweight, easy to distribute, and gives direct control over a fast drawing loop.





Interesting bits:
- Preview embedding: Windows screensavers support a “preview pane” mode. That means the app needs to embed its window into a parent handle (Win32
SetParent, style changes, resize viaSetWindowPos). - 60 FPS-ish animation: a timer drives updates; each frame advances angles toward their targets. Depending on the screen resolution and computer performance, the frequency may drop. I draw the background image only once at the beginning to save workload.
- Shortest-path rotation: if you go from 350° to 10°, you want to rotate +20° (not −340°). So the interpolation always chooses the shortest angular distance around the circle.
- Clean vector drawing: I draw rounded hands, a subtle face gradient, and keep everything anti-aliased.
- Background photos from the internet: In the screensaver version, I added a feature that fetches a new random wallpaper image from Pexels each time the screensaver starts, so the animation always runs against a fresh backdrop. For this feature to work, a free API Key from pexels.com needs to be added in the settings of the screensaver.
Repo: https://github.com/techniccontroller/a-million-times-screensaver
2) Web version (Canvas / JavaScript)
The web version is intentionally minimal: a single static index.html served by nginx.

Interesting bits:
- Canvas is perfect for this: 256 clocks × 2 hands is 512 hand draws per frame — a workload that Canvas 2D handles well.
- Same mental model: it’s the same “angle field + animation” architecture as the screensaver.
- Performance tuning: the browser wants to redraw at display refresh rate (often 60–144 Hz), but this project doesn’t need that. I capped the rendering loop to 20 FPS and added an “only redraw while animating” mode.
- Shadows without expensive layering: the blurred offset shadow behind each hand uses Canvas’ built-in shadow settings (
shadowBlur,shadowOffsetX/Y). That gives a nice depth effect with minimal extra work.
Repo: https://github.com/techniccontroller/a-million-times
Patterns: where the fun happens
I implemented multiple pattern modes and let the system rotate through them with transitions.
Tangent / circle patterns




One family of patterns uses basic geometry:
- compute a “radial angle” from the grid center to each cell
- derive a “tangent direction”
- close the V shape more in the center and opening it on the outside
It’s surprisingly expressive: tiny differences in spread curves make the whole grid feel alive.
Vector / flow fields (vortex)


Another pattern family treats the grid as a sample of a 2D vector field:
- create a few vortices with different signs/strengths
- add a small background drift and wave perturbation
- sample the direction at each cell (with a short RK4 integration step)
- map direction to angles
This is the pattern that always feels like it has “motion” even though it’s still just hands rotating.
The time display

The most “useful” pattern is the time display: it maps digits into a 3×6 grid per digit, and each cell uses one of a small set of predefined hand-angle pairs (a little “alphabet” of clock states).
That gives a digital readout made of analog hands, which is exactly the kind of contradiction I enjoy.
A note on animation: making it feel right
The animation quality is mostly about two things:
Shortest-path angle interpolation
Angles wrap, so interpolation must wrap too. A naive lerp makes hands spin the long way around, which looks wrong immediately. Both implementations normalize angles and interpolate along the shortest delta.
Transitions as a first-class feature
I don’t “snap” between patterns — I assign new targets and let every hand animate toward them over a consistent transition duration. That’s what makes pattern changes feel intentional rather than random.
Theme selection
Once the motion and patterns felt right, I added a simple way to change the look without changing the logic: theme selection. Both the website and the screensaver support six predefined color themes that tweak the overall mood — background, clock face shading, hand color, and shadow intensity.






I kept the themes intentionally curated (instead of a full color picker) so every option stays readable and “designed,” while still giving enough variety to fit different setups — bright rooms, dark rooms, high-contrast displays, or more subtle tones.
Under the hood, a theme is just a small set of color values that gets applied consistently across the rendering pipeline. That means the pattern logic stays identical; only the visual styling changes.
Hosting the web version
The website is deliberately simple: static files behind nginx. That gives:
- low maintenance
- low resource usage
- easy deployment
Once DNS and the nginx server block were correct, enabling HTTPS was a standard Let’s Encrypt + Certbot flow.
References
- Inspiration: ClockClock / Humans since 1982
- Web: https://www.a-million-times.com
- Repo (web): https://github.com/techniccontroller/a-million-times
- Repo (screensaver): https://github.com/techniccontroller/a-million-times-screensaver
0 Comments