Advertisement

Minimalist Radial Dot Clock

| by Vladimir | 3 min read | code by Chris Bolson
Intermediate

Tech & Dependencies

HTML CSS JavaScript

Features

  • Radial Layout
  • requestAnimationFrame
  • CSS Light-Dark Mode

Browser Support

Chrome 123+ Edge 123+ Safari 17.5+ Firefox 120+

Core

This is a Minimalist Radial Dot Clock. It visualizes time through three concentric rings of geometric dots (hours, minutes, seconds) rather than traditional sweeping hands. Its function is to provide an ambient, modern alternative to standard analog or digital readouts, integrating seamlessly into high-end, futuristic interfaces.

Specs

  • Weight: ~3 KB. Zero external dependencies.
  • Performance: High. The script utilizes requestAnimationFrame for a smooth tick, but intelligently caches previous values (prevActive) so it only touches the DOM when a unit of time actually changes.
  • Theming / Customization: Fully governed by CSS variables. Colors, dot dimensions, and opacities are defined at the .clock root. It utilizes the modern CSS light-dark() function for native theme switching.
  • Responsiveness: Scales dynamically using a clamp() formula applied to the --clock-radius variable.
  • Graceful Degradation: [!] If JavaScript fails, the clock remains an empty circular layout. It lacks <time> semantics and screen-reader accessibility for the visual layout.

Anatomy

  • HTML: A structural shell. A #clock container holds three .ring divs for the time units and a .time div for the digital readout.
  • CSS: The visual engine. It establishes the grid overlay to stack the rings (grid-area: 1/1). It defines the varying widths and heights for the dots based on their role (e.g., long ticks for hours, small circles for seconds) and handles the :has() logic for the visibility toggle.
  • JS: The logic controller. It dynamically generates the DOM nodes for the dots, calculates their static radial coordinates via trigonometry, and loops the active .active class assignment based on the current system time.

Logic

The architectural efficiency of this snippet lies in its initial trigonometric layout and subsequent minimal DOM manipulation.

// Calculate radial position once
const angle = (360 / item.numbers) * i;
dot.style.transform = `
  rotate(${angle}deg)
  translateY(calc((var(--clock-radius) + var(--dot-h) * .5) * -1))
`;

// Update loop logic
if (prevActive[unit] !== value) {
  if (prevActive[unit] !== null) {
    ring.children[prevActive[unit]].classList.remove('active');
  }
  ring.children[value].classList.add('active');
  prevActive[unit] = value;
}

Instead of rotating large div containers acting as invisible hands every frame, the JavaScript generates every possible dot (12 hours, 60 minutes, 60 seconds) on load and pushes them out to the perimeter using rotate and translateY. During the updateClock loop, the script simply swaps a single .active class. The prevActive check ensures the browser isn’t needlessly recalculating styles on all 132 elements 60 times a second.

Feel

Precise, quiet, and mechanical. The lack of CSS transitions on the dots means the time snaps forward instantly, mirroring the crisp, binary logic of a digital system rather than the analog sweeping of physical gears. It feels like a high-grade piece of telemetry equipment.

Advertisement