LayerVault Simple version control for designers. Try it free.

Making a New Type of Activity Feed

Although it’s just shy of a week old, customers can’t get enough of our new Activity Feed. We couldn’t get the Activity Feed perfect in time for the LayerVault 2 release, so we had tabled it. For the last month, we’ve been sweating over every detail. We pushed the limits of the browser to deliver the absolute best experience. This blog post will talk about how Activity Feed works and some of the tech behind it.


It was important for us to have a truly infinite scrolling experience. We took a look at the way iOS handles scrolling through long lists and emulated that experience on the web. Hitting the end of available data should not cause an abrupt stop; you should be able to scroll gracefully with the flick of a finger.

With this in mind, we need to know how long the Activity Feed will be once populated. Most of the time spent creating the Activity Feed is spent building the HTML. Building the outline of the feed is a pretty speedy task, though. Before any story makes it to the feed, we load what we call our “skeleton.”

The skeleton is the full Activity Feed, sans the stories themselves. We do include IDs and timestamps of stories though. This helps our caching efforts and our delimiter placement. The skeleton is always at the ready in memcached for each user. Although it is large, the skeleton data is uniform which means it gzip’s extremely well.

Once the skeleton is loaded, we move on to loading the stories themselves.


If we weren’t careful, Activity Feed could saturate user’s connections solely with activity data. We wanted to keep the data traded to a minimum while keeping our scrolling experience truly infinite. We wanted to have our cake and eat it too.

To do this, we had to make liberal use of the localStorage API. localStorage allows us to keep data client-side then expire it as necessary.

Cache expiration is hard, so we replicated exactly how Rails generates cache keys. Once something expires on the server end, it also expires in the user’s browser. We know when something expires by looking at its id and updated_at, found in our skeleton.

Our requests to populate the Activity Feed reach through localStorage to get an answer. The result is an impossibly fast experience. Here’s a little pseudo-code of this in action:

// ...
loadStory: function (id, updatedAt, callback) {
    cacheKey = Utils.cacheKey(id, updatedAt),

  story = localStorage.getItem(cacheKey);

  if (!!story) {

  $.get('/activity_items/load', {
    id: id
// ...


We got everything done with the Activity Feed, but using it against production data still didn’t feel right to us. As you can imagine, the LayerVault project alone on Allan’s account has thousands upon thousands of revisions. We needed something to move quickly through a big feed. We needed to make the jump to Warp Speed.

Warp Speed gets activated when a user starts scrolling quickly through a large feed. As they move, a readout updates the user where in time they are. It’s a great way to move through large chunks of the Activity Feed quickly.

But Warp Speed would just be another thing if it weren’t for the clock Allan whipped up. Taking a note from the Path iPhone app, he put together a hyper-active clock entirely in CSS. The result is something that makes me smile every time I use it.


We tend to be very conservative with how our JavaScript is written. I still maintain that the LayerVault JavaScript is cleaner than most CoffeeScript you will see. Early versions of Activity Feed would cause even the best browsers to cry under the strain of intense repaints. We were hitting limits left and right.

One library that we found especially helpful in keeping our resources in line is Underscore.js, maintained by DocumentCloud. We particularly make use of their defer() and throttle() methods. When writing methods that need to execute while a user is scrolling, these are a lifesaver.

One punch pulled

Activity Feed is great and it’s something we’re proud to include in LayerVault. Unfortunately, we had to make one sacrifice: Activity Feed is not available in Firefox or Snow Leopard. While they could still function in such environments, the experience delivered is not up to our standards. Thankfully, almost all of our customers run Lion (with a few on Mountain Lion!) and a Webkit browser.

That’s the Activity Feed in a nutshell. We’ll answer any questions on Hacker News.