Pirana: feeds for the reader

  • 9/18/2011

When the announcement of the “Responsive Edition” of An Event Apart’s 10k Apart showcase coincided with a little bit of free time on my calendar at the end of August, I figured: “Why not?”

One of the concepts I’ve had floating around in the big-box-of-ideas-that-will-probably-never-happen was the idea of a kindle-inspired RSS feed reader that would emphasize content before headlines. RSS is a great format for skimming the day’s news, but sometimes I just want to read. No ads, no digests—just me and a few thousand words with nothing but sound typography between us. It seemed like a good fit for the challenge.

Defining the problem

Build a responsive feed reader in under 10k? Piece of cake. But device compatibility and a weight limit alone can’t make an app. At least, not anything that anyone would want to use. So After a little bit of brainstorming, I settled on the key features I would want to see in any kind of reader:

  1. A focus on reading. Given the enormous volume of communications vying for our attention on a daily basis, it can be hard to take the time to just…read. To actually read. Not just to skim the surface of a few dozen articles or to flip quickly the day’s headlines, but to actually digest the words of writers practicing their craft.
  2. Offline support. A good story can’t help pass the time on the metro if it blacks out in the tunnel, so storage of stories for offline browsing was a must.
  3. Maintainability. 10k isn’t much, and I wanted to be sure it would be easy to build on the application down the line. Just in case.


To keep size down, Pirana ended up growing around a home-brewed microframework that implements only the barest bones of MVC development. Controllers and views are functions grouped into two hashes, and the basic model is little more than a collection bound to a basic localStorage adapter with a few essential methods:

  • set(key, object) – add or update an object in the collection
  • get(key) – retrieve an object from the collection
  • remove(key) – remove an object from the collection
  • each(callback) – call a function for all objects in the collection
  • keys() – retrieve an array of all keys in the collection
  • values() – retrieve an array of all objects in the collection

Routing is minimal, and a stripped-down event system limited to a few predefined callbacks rounds out the core of the framework:

var events = function(){
    var callbacks = {
    return {
        listen: function(evt, callback ) {  
        fire: function(evt, param){
            var i = 0,
            while(fx = callbacks[evt][i++]) {

A good excuse

Like most projects, Pirana offered a great opportunity to gain practice with some up-and-coming goodies. Besides the usual HTML5 semantics and some snappy CSS3 transitions, Pirana also takes advantage of:

  • Application caching to ensure offline support
  • localStorage for storing models
  • history for managing app state
  • canvas for drawing backgrounds


No, it isn’t spelled wrong. Grunge-rock afficianados will remember Chris Ballew’s lyrics on “Lump”, from the Presidents of the United States’ eponymous 1995 album:

mud flowed up into Lump’s pajamas,
she totally confused all the passing piranhas

That slant-rhyme has bugged me for a decade and a half, but with the Presidents unlikely to take it back the only reasonable option was to just adjust the pronounciation to match. Right?

Hey, it's RJ—thanks for reading! If you enjoyed this post, would you be willing to share it on Twitter, Facebook, or LinkedIn?