The CSS Clock

A quest for perfect animation

Anand Sharma
Gyroscope

--

In 2010, I released a CSS-powered clock as a coming-soon page for April Zero. Flash & jQuery were the two popular ways to do animations at the time, but native CSS animations had been added to modern browsers.

Using CSS for animations was a big change — animations had previously been treated more as functionality in Javascript rather than styles in CSS. Instead of mixing style and logic, there could now be a stronger separation. And having hardware-acceleration for the first time suggested potentially fantastic performance.

This would be a fun project to push it to the limits and see if it made sense to use for a real project. I had been constantly hitting performance bottlenecks with my designs, and wanted to figure out how to write code that would always be 60fps and easy to maintain.

Inspirations

I had been working at theory11, a magic & playing cards company. One of the things we designed was a new steampunk-style deck of cards, with steam-powered machinery and lots of moving parts. Even though it was just a flat illustration on paper, it felt like it had depth and motion. I realized it could truly come to life if it was animated on the web, with realistic moving gears and pistons. If it worked on mobile web too, I could have it in my pocket at all times and easily share it with people.

Early mockup with some gears inside the logo

I started working on some concepts in Photoshop. This shape was my logo at the time, so I decided to make it into a glass window showing some animated details behind it. The layered gears seemed promising, but didn’t make enough sense on their own. Why were they spinning? What did the whole thing mean?

I started researching other things that had gears, and remembered some fancy watches I had seen with exposed gears. I decided to turn the page into a fun mechanical clock, which told different types of time and would make sense as a countdown page. If the elements had meaning instead of just being decorative, the page would have a believable story.

Most of the watches had lots of complex and mysterious components. I looked through hundreds of them to try to figure out which elements I liked most and what the common patterns were. They had small gears with many teeth, as opposed to my previous concept with huge, coarse ones. There was also an underlying structure, with screws and a thin frame to keep everything in place.

If elements weren’t just decorative, the page would have a believable story.

I wanted it to have a unique and iconic structure, but still be made of believable and classic components. The seconds hand was in the middle, doing one rotation every minute. The day of month went from 1 to 31 in the middle, but the hour was a separate dial at the top.

Since I wasn’t limited by physics or what was in real life, I added some new elements that looked interesting but never actually existed — like a magical pendulum inspired by old grandfather clocks, which was presumably the power source.

When creating the illusion of complexity, it is important not to get overwhelmed yourself. I started with 5 separate layers which would be stacked, each with gaps and perforations to reveal details below.

The bottom layers would be slightly blurred and out of focus. I knew that if I could accurately build the small details like blur, lighting, and shadows, then people’s brains would be tricked into seeing real objects rather than a bunch of DOM elements on screen.

Lunar Cycles

One subtle feature I wanted to add was a lunar cycle indicator. Some watches and clocks featured it, so I figured it should be possible to create a mechanical representation of that logic. It just needed to transition from the full moon to half, crescent, new and then back again.

It was accurate when I launched, but I think it has broken down since then. One day I will ask a swiss watchmaker how they do it, it was tricky enough with all the power of Javascript — I can’t imagine doing it with just some spinning gears.

The Prototype

Almost no one was using CSS animation at the time and the limits were very untested, so I started benchmarking things and figuring out the best way to get high performance. I used the FPS counter in Google Chrome’s about:flags to test various ideas and see what slowed things down. The Profile tab in Chrome’s Inspector was also helpful for diagnosing bottlenecks.

I quickly discovered a lot of patterns and tricks to maintain smooth performance. Maintaining 60fps wasn’t as important as never skipping or jumping — it was ok if it dropped to 50 or even 40 when a lot of things were happening. As I tested different moving elements — with varying amounts, sizes, speeds, etc — the limiting factor was more related to the size of the area being updated and not the complexity or number of polygons. This was great news for the design, because it meant I could make lots of tiny gears and extra shadows without worrying about the whole thing grinding to a halt.

It felt quite magical to not be using any Javascript to make it run.

The calculations for the gear ratios turned out to be quite straightforward since each element had an animation-duration property for one revolution. Each one was proportional to the number of teeth it had, and then I added a global multiplier to change the speed while all of the gears still interacted with each other perfectly.

Orange lines for easier visualization of gear ratios.

I put together a really quick proof of concept to see if it would actually work. It had directional highlights and shadows, which were a really subtle effect but really helped sell the illusion. It felt quite magical to not be using any Javascript to make it run, either. I kept the page open for an hour and it ran smoothly the whole time. When it even ran perfectly on my iPhone, I knew this was the start of something amazing.

Now I just had to figure out how to expand the same technique to my mockup, with hundreds of tiny components instead of 4 big gears.

The solution was quite simple — keep the animating area small.

I had tried to do immersive, fullscreen animations before and it typically ended in tears. We had spent a whole year designing a new company site with beautiful full-page transitions, only to realize that it slowed down too much once content was added.

Hardware-accelerated CSS transformations hinted at much better performance, but the math of stretching elements across big screens still didn’t look good. Exponential growth guaranteed that trying to grow to large windows on big monitors at some point just won’t be able to keep up, as the number of pixels being animated quickly increase beyond the rendering capacity of even the most powerful machines. Things like retina displays would further increase the load.

The size of the animation is more limiting than the complexity.

The clock was a fixed size (256x256) that wouldn’t stretch out of control even on a huge window or at the higher density of a retina display. It was tempting to make it bigger on a large screen to fill up the space, but restricting it to the small square meant the animations would be consistently smooth.

It was the big tradeoff that made everything possible. This is now one of my core principles for creating smooth animations: the size of the animation is more limiting than the complexity of the motion. In general, you can get away with a lot of crazy stuff if you just keep it in a small area.

The rest of the page would be filled with a really detailed but completely static texture. It would need a big image, but would perform well after the initial download. Even though there were lots of different gears and other pieces, I combined everything into just a few sprites so it would load as quickly as possible.

All of the gears and shadows in one sprite — gears.png

Having so many complex image assets loaded over the wire — even in sprites and on a decent connection — would take a few seconds the page to be ready. I had to have some sort of preloading stage, otherwise the clock would would start spinning with missing pieces.

The Shutter

The iPhone camera at the time had a cool shutter that opened and closed. They no longer have this feature — too skeumorphic and slow — but at the time it was a nice detail. After experimenting with some other options like shadows or a sliding cover, I realized this kind of shutter would be perfect.

iPhone camera app circa 2010 — Skeumorphic!

It matched the rest of the page, with finely tuned mechanical pieces. Until all the gears and pieces inside were ready and fully loaded, it would stay closed. Then everything would be smoothly revealed.

It seemed like a pretty simple idea but things quickly went wrong. It was nearly impossible to build the mechanism in CSS. A shutter is built with slightly tilted and overlapping blades, each one below the previous.

Those familiar with z-index will quickly realize the problem of getting the last one to go back under the first.

I had two options: do a different design that would be easier to build, or invent some really complicated way of making a CSS shutter. Of course I chose the latter.

After trying dozens of ideas that didn’t work, I ended up with a strange solution — splitting each piece into two halves that moved separately. It was extremely hacky, but got the job done. Some simple trigonometry would arrange them around the circle and once they were perfectly aligned the split was imperceptible.

Sometimes, magic is just someone spending more time on something than anyone else might reasonably expect — Teller, September 2012

It turned out to be more complicated and time consuming than the rest of the project combined, but worth it.

Two shutter components combined to look real

I also didn’t want to the gears to be constantly running and using CPU, especially open in multiple pages. When the browser window was blurred or another tab was selected, it would pause and the shutter would close. Not only was that a nice feature, it gave me a good way of testing the functionality without having to refresh the page thousands of times.

Shutter opening & closing

Sharing

I liked how the clock was looking, but also wanted there to be more interactivity and a natural way for it to spread if people liked it. I played with some buttons and text at the top or bottom, but they felt out of place and distracting. Obviously a like or tweet button would feel out of place directly on the clock, so I made them pop out from some simple buttons.

Inline sharing options

Throw a little hot-rod red in there

Changing and updating tons of PSD’s, sprites and site assets can get time consuming, so I had built a Javascript framework that used Photoshop as an asset pipeline. Did you know that Photoshop has 4 different scripting API’s?

Until about an hour before launch, the design was a bluish silver. I really liked the details and animations, but after staring at it for a month it was starting to feel a bit boring. Something was missing. I had just bought a red Ducati, so I thought maybe it should match.

There was a single file with global variables like background color and texture. With just a few clicks, I could update all the sprites and upload them to the site. In just a few minutes, I was able to try out some totally different colors schemes and textures.

I had just bought a red Ducati, so I thought maybe it should match.

Making everything into parameters that can be adjusted later is as an important workflow habit that I’m constantly trying to do more. Things like the speed of the gears, animation timings, and color of the elements were all stored as variables and easy to optimize at the end. This is important, because until the very end you often don’t have all the puzzle pieces needed to make the right decisions.

Everyone enjoyed the red and gold version, so I updated all the images and shipped that version instead. It’s important to not get too attached to a particular design, and realize that major improvements can be made at any point, even 5 minutes before launch.

You can still see the old CSS clock in action at old.aprilzero.com.

Stay tuned for my next article, which will have 10 principles for smooth animations on the web.

Want to push the limits of the web even further? We’re hiring at Gyroscope.

--

--