I used to walk past the Funan mall almost nightly. The kinetic wall art clock outside it is really cool. I took some inspiration from it while adding my own twist: spatial audio with the Web Audio API.
The Character Set
Any time I walked by I was more interested in watching the clock than taking photos of it. Thankfully it only took about 15 minutes of image searching to find reference photos with all the digits and characters used on the clock.
I made a <canvas> based character creator that exported each character as a 2D JavaScript array.
Creating the “glow”
While it is visible during the daylight, the Funan clock looks great at night when it’s lit up. The <canvas> rendering context has 4 useful properties – shadowColor, shadowOffsetX, shadowOffsetY and shadowBlur – that produce decent results for minimal effort. It takes a bit of playing around with the properties to get the result you might like the best. It sounds bizarre to use a shadow to create a lighting effect but it does a decent job.
Tick! Audio Spatialisation! Tock!
The Web Audio API has a PannerNode that allows the positioning of sound in 3D in relation to the position and orientation of a Listener.
Apart from the additional Z dimension pointing out of the screen, PannerNodes use a different coordinate system (cartesian coordinates, the positive Y axis going up the screen) to the <canvas> (positive Y goes down the screen). This means that by default rotations go in the opposite direction (counter clockwise) to the <canvas>‘s clockwise rotations.
This isn’t necessarily a big deal unless you forget about it – like I might have done ๐ – and then you think you’ve got your headphones on the wrong way for a little while! In order to give the impression the ticking is moving around with the seconds hand of the clock the PannerNode‘s position is rotated around the Z axis.
The “tick” and “tock” come from the audio in the Anno Labs video and then I sliced them into individual files using Audacity.
Due to the auto-play policy you can’t play any audio until the User interacts with the page. The easiest way to manage that was to mute it by default and let the User click on the Clock to unmute or mute it.
It works best with (most) desktop browsers and headphones, see and hear the finished working clock here.