Moving the Cloud is an experiment in using HTML5 and CSS3 technologies and Node.js. It was also an experiment on using Node.js on the Cedar stack in Heroku, but that didn’t quite work out as expected (more on that later). It’s also an Easter egg on the Model Metrics Homepage. Click on the animated 1s and 0s down in the bottom left corner of the screen to get to it.
And… if you want, fork the source over on GitHub. The readme.md file there gives some information on how to get it set up.
I was asked to put together a temporary (it’ll probably be around for a few months) artsy installation piece for the Art of Code section on modelmetrics.com. Going into the project, I wanted to do a social media visualization because, well, I think they’re cool. Some of my favorite examples are Twistori.com and Vizeddit — they visualize Twitter and Reddit respectively.
Moving the Cloud uses Node.js to pull tweets containing some keywords like “Cloud”, “Salesforce”, “Social”, “Mobile”, or “Model Metrics” from the Twitter Streaming API and stream them to clients using websockets. They move across the screen right to left, sort of like a cloud — GET IT? (nudge nudge wink wink)?
Twitter Streaming API
The Twitter Streaming API (well, technically APIs) allows you to open up a long-running socket connection with Twitter, and stream tweets that match a certain criteria. For this, I used the Public Stream API with the /filter endpoint so that I could receive tweets that matched my keywords. Technically, you could do this directly from the client using HTML5 websockets, but you have to authenticate with Twitter. You can generate keys for a specific app at dev.twitter.com, so you don’t have to just hard-code your Twitter username and password into the app, but still, you don’t really want to embed that in client-side code. So, in this example, I’m using Node.js as a go-between. It authenticates with Twitter, sets up a socket connection with the Streaming API, and dispatches those tweets out to any clients (browsers) that connect to it.
The Node.js server script itself is pretty simple–it uses the node-twitter library to connect to Twitter, and Socket.io to handle the setting up the websocket connections with whatever client browser happens to connect to it. It also handles fallback to XHR long polling for browsers that don’t support websockets. Aside from an array to hold active connections and some error handling, that’s about it on the server side.
Like I said earlier, one of my goals for this project was to demonstrate some HTML5 and CSS3 technologies. Because of that, it does not work on IE. It would probably be possible to get it sort of working in IE by falling back from HTML5/CSS3 technologies to older ones, but it wouldnt’ work as well, and sometimes you just have to leave the old crappy browsers behind. It does work perfectly fine on current versions of Chrome, Safari, Firefox, Mobile Safari (iPhone/iPad), and the Android Browser, though the transitions are kind of choppy on Firefox. Anyway, here’s some of what’s going on:
Websockets are awesome. If you’re familiar with client/server programming, you’re probably familiar with the concept of sockets. If you’re not, you use them all the time anyway. With a typical HTTP request, for instance, a socket connection is opened with the server, a request is made (GET, POST, etc.), a response is given and the socket is closed. In order for the server to be able to push data down to the client, a socket connection needs to stay open.
There’s some hacks like XHR Long Polling (Comet) that work on older browsers, basically by opening a dummy request socket and delaying the response until something push-worthy happens, but it’s limited by the HTTP 1.1 spec that says a browser should have no more than 2 open sockets with a server, and, well, it’s hacky. Websockets, on the other hand, let you open up a bi-directional full-duplex socket between a web browser and a server. In Moving The Cloud, tweets are sent from the Node.js server to the each client using websockets. Socket.io handily fails back to XHR long polling if websockets aren’t available.
Show hardware acceleration in Safari CA_COLOR_OPAQUE=1
Show hardware acceleration in Chrome –show-composited-layer-borders
Firefox, best I can tell, does not have a similar mode. And CSS3 transitions are really slow in the current version of Firefox, too. So, I guess Mozilla has some work to do on that front.
CSS3 Web Fonts
Web Fonts use the @font-face rule to include font files that can be hosted on the web – they don’t have to be installed on the viewer’s computer. This has given rise to some great services like Google Web Fonts and fontsforweb.com. This is great, because the Model Metrics logo uses GothamLight, which isn’t a typical web font. In the olden-days, back when onions were worn on belts, logos that had to use a specific font would typically just be images, and the font for the rest of the site would just be a web-safe font that was close enough.
For instance, the rest of the modelmetrics.com site (except the logo) uses the Helvetica font family: “HelveticaNeue-Light”, “Helvetica Neue Light”, “Helvetica Neue”, Helvetica, Arial, “Lucida Grande”, sans-serif. My bit uses GothamLight:
src: local("Gotham-Light"), url('http://fontsforweb.com/public/fonts/1151/GothamLight.ttf') format("truetype");
CSS3 adds an opacity parameter, so any element can a specified level of opacity (or what most people would call transparency). It’s pretty simple to use – just add an opacity: attribute to an HTML element, and specify a value. The footer in Moving the Cloud, for instance, has an opacity value of 0.9. Just enough so that you can see tweets floating by underneath.
When starting a new web app, it’s often a good idea to start with a reset.css to normalize your app across browsers. HTML5 Boilerplate gives you that and more. It’s is a “”professional front-end template that helps you build fast, robust, adaptable, and future-proof websites”. It’s a great starting point for an HTMl5 app that handles many of the idiosyncrasies between various browsers.
Moving the Cloud works quite well in most modern browsers, but there are some known issues:
Speaking of which, it’s kind of slow and crappy on Firefox. I think this is just because CSS3 transitions are slow and crappy on Firefox. Mozilla really needs to step it up – it runs great on my iPhone but not Firefox on a new MacBook Pro.
I really wanted to get this working in Heroku. Really really really did. And, technically it does work – on one dyno. I think the issue is that the Cedar stack doesn’t support websockets from Node.js, so it has to use XHR Long Polling, and even though it should work with a RedisStore as a man in the middle, it works sort of intermitently if you try to scale the app up to use more than one dyno. So, it’s running in EC2. I’ll try again when Cedar supports websockets. More information here on stackoverflow.com.