Scroll-Synced Ticking Audio with CSS Clocks
A tutorial demonstrating how to create CSS-animated clocks that trigger synchronized ticking sound effects based on scroll position using JavaScript and Web
Scroll-Synced Ticking Audio with CSS Clocks
@keyframes tick {
0%, 100% { transform: rotate(0deg); }
50% { transform: rotate(6deg); }
}
.clock-hand {
animation: tick 1s steps(60, end) infinite;
animation-play-state: paused;
animation-delay: calc(var(--scroll) * -1s);
}
This CSS creates a clock hand that advances in discrete steps as users scroll down a page. By pairing the visual animation with Web Audio API sounds triggered at matching scroll positions, developers can synchronize ticking audio with the rotation of CSS-rendered clock elements.
Background
The technique emerged from experiments combining CSS scroll-driven animations with the Web Audio API. Traditional CSS animations run on a timeline independent of user interaction, but the animation-timeline: scroll() property introduced in 2023 changed this paradigm. Developers can now tie animation progress directly to scroll position.
Clock animations present a unique challenge because they require precise synchronization between visual and auditory feedback. A clock hand moving smoothly without corresponding ticks feels disconnected, while audio playing independently of visual position creates jarring mismatches. The solution involves calculating scroll percentage and using that value to control both CSS animation delay and JavaScript audio playback.
The implementation requires tracking scroll position through an Intersection Observer or scroll event listener. As the scroll value updates, it gets stored in a CSS custom property (--scroll) that the animation references. Meanwhile, JavaScript monitors the same scroll value to trigger audio samples at specific thresholds corresponding to each tick mark.
Technical Implementation Details
The visual component relies on CSS custom properties and calc() functions. The animation-delay property accepts negative values, which causes the animation to start partway through its cycle. By setting the delay to the negative of the scroll percentage, the animation frame matches the scroll position.
window.addEventListener('scroll', () => {
const scrollPercent = window.scrollY / (document.body.scrollHeight - window.innerHeight);
document.documentElement.style.setProperty('--scroll', scrollPercent);
const tickPosition = Math.floor(scrollPercent * 60);
if (tickPosition !== lastTick) {
playTickSound();
lastTick = tickPosition;
}
});
The audio portion uses the Web Audio API to load and play short tick samples. Pre-loading the audio buffer prevents delays, and creating new AudioBufferSourceNode instances for each tick avoids overlap issues. Some implementations use a single tick sound, while others alternate between two samples for a more realistic clock mechanism sound.
Performance considerations matter significantly. Scroll event listeners fire frequently, so throttling or using requestAnimationFrame prevents excessive function calls. The Intersection Observer API offers an alternative approach, triggering audio only when the clock element enters the viewport.
Creative Applications and Developer Response
Web designers have adapted this technique for storytelling experiences where time passage correlates with scroll depth. One notable implementation created a 24-hour clock that completed a full rotation across a long-form article about circadian rhythms, with ticking sounds reinforcing the temporal theme.
The approach has sparked discussions about accessibility. Screen reader users don’t benefit from visual-audio synchronization, and repetitive ticking can annoy users who prefer reduced motion. Responsible implementations include a pause button and respect the prefers-reduced-motion media query:
@media (prefers-reduced-motion: reduce) {
.clock-hand {
animation: none;
}
}
Developers have noted that mobile Safari requires user interaction before playing audio, necessitating a “start experience” button. This limitation actually improves the user experience by preventing unexpected sounds on page load.
Influence on Interactive Web Design
This technique represents a broader shift toward scroll-based narratives that engage multiple senses. Traditional web animations played automatically or on hover, creating passive experiences. Scroll-driven animations with synchronized audio give users direct control over pacing while maintaining authorial intent about sequence and rhythm.
The pattern has applications beyond clocks. Developers have created scroll-synced music visualizers, step counters with footstep sounds, and loading bars with mechanical clicking. Each implementation reinforces the connection between user action and interface response.
Browser support continues improving, with scroll-driven animations now available in Chrome, Edge, and Safari. Firefox support arrived in version 115. Polyfills exist for older browsers, though they sacrifice some performance benefits of native CSS implementations.
The technique demonstrates how combining established web technologies in novel ways creates experiences impossible with either technology alone. CSS handles the visual performance efficiently, while JavaScript manages the audio timing and user interaction logic. This separation of concerns produces maintainable code that degrades gracefully when either component fails.
Related Tips
Caveman: Slashing AI Development Time on Benchmarks
Caveman is an AI development tool that dramatically reduces the time required to run and iterate on machine learning benchmarks through intelligent caching and
Abliteration: Surgical Removal of AI Safety Filters
Abliteration is a technique that surgically removes safety filters from AI language models by identifying and eliminating specific neural pathways responsible
AgentHandover: Auto-Generate AI Skills from Screen Use
AgentHandover automatically generates reusable AI skills by observing and learning from user screen interactions, enabling automation of repetitive computer