Just One File with Cappuccino 0.8

The entire 280 crew just got back from an awesome time at JSConf EU in Berlin, where we got to show off some of the cool new developments coming with Cappuccino 0.8. I wanted to take the time to share one in particular in more depth here: image spriting.

The Problem with Spriting

Image spriting is the act of taking all the images in your app (or framework, or library, or whatever) and combining them down to one single image. This has the advantages of being smaller (since each individual image has overhead associated with the format), as well as allowing you to grab it from your server with one request:

Traditional Spriting

This is faster in an absolute sense, but even more so psychologically since it allows you to show the contents of your app faster without having all the images “flash in” later. Cappuccino currently uses a similar technique with the source code in your application: concatenating it all together and minifying it, but up until now we’ve had no automatic, or built-in, support for spriting, you’ve instead had to do it entirely yourself. And truthfully, no framework has really good support for this.

This is because the fundamental problem with spriting today is that the process isn’t really automated and the results are thus subpar. Sure, there are scripts which will put images together for you, but they all require you to configure them first and to update them as your use of the images in question changes. This is because traditional spriting is dependent on how you use your images. Whether you choose to repeat, stretch, scale, or even draw to a canvas affects which images can be sprited together, and even which can’t be sprited at all. This has a number of unfortunate side effects:

  • Rarely do you actually end up with just one image: Instead, you can end up with 2, 3, or even more. This is because images have to be “grouped” by their use. For example, vertically repeating images can be sprited together, but not with horizontally repeating images.
  • You may have to actually change your code: Since images are being mutated, the code you write needs to take into account these new images. If you are lucky you have a system that is relatively good at doing this for you. However, if you decide to use an image in a new way (such as drawing it to a canvas), you either have to update your configuration files or choose to code it differently. This is easy to forget.
  • Your images are still shipped separately from your code: Even in the best case where you are lucky enough to successfully sprite all your images together, you still have to wait for them separately from when your code is ready, potentially leading to noticeable delays from latency, or a “flash in” effect.
  • Inflexible due to loss of data: There exist cases where your code is meant to be used by others, such as with libraries and frameworks. In this case, images can’t be used in any way other than how you intended them to if they are sprited, because the original images are gone or would require a redundant second download.

So unfortunately there is currently no good one-size-fits-all solution for image spriting the way there is with “code spriting”. All of them require the user to actually become involved in the optimization process, and even still can produce less than stellar results. This is clearly not a solution that can scale, and most everyone agrees to this.

But we’re hoping to change this with the release of Cappuccino 0.8, as we’re introducing a whole new, completely cross-platform, way to sprite: base64 images. By encoding images as base64, we create a lossless text representation of images, allowing us not only to use them in whatever way we please, but to actually ship them with the code:

There are many advantages to this:

  • One file, guaranteed: All images can always be sprited together regardless of how you plan to use them, and can be included with the actual source code. This has the added benefit that gzip can work its magic on the entirety of your web app as one, producing better results.
  • No need to ever modify code or configuration files: Since we’ve eliminated the ambiguous part of spriting images, the Cappuccino build tools are able to perform this optimization on your code automatically without tedious configuration files or having to “learn” how to sprite.

Yes, This Works in IE 6 and 7.

I’m sure most people are wondering how we are pulling this off in versions of IE before 8, since they do not support data URLs. Notice that earlier I didn’t specifically mention data URLs though, I instead only referred to the more broad technology of base64 images. As it turns out, IE has had support for base64 images since version 6 (!) with a little-known technology called MHTML. MHTML allows you place all your resources in one “resources” file, which incidentally can be any file in your website… including the same file that contains all your code.

Cappuccino is already smart enough to be able to automatically download and use different code depending on what browser is being used (and with no server configuration), so we now simply ship data URL versions of this technique to modern browsers, and MHTML versions to older copies of IE:

Cappuccino Spriting

This is a very exciting feature for us. This has been a weak point in Cappuccino and its nice to finally have a solution that not only works, but is drop dead simple to use. Our tests have been proven incredibly promising, giving us the fastest load times we’ve ever seen with Cappuccino, and absolutely fantastic perceived speed as well. Our tools have all been honed to use this at every level: Apps, frameworks, and themes will automatically sprite your images for you.

This is just one of the many enhancements coming with Cappuccino 0.8, and the best part is as usual you won’t have to change a single line of code to get all the benefits.

  • pabloponsbordes

    As each post and improve you add, I became amazing.
    excellent work. I'm thrilled waiting for your new release and all the improves you will add, and also for the Atlas App that I hope to see you soon.

    Congratulation for your excellent work.

  • marijnhuizendveld

    Would you consider putting this into a separate project? This spriting solution could profit a whole lot more projects…

    Anyway, nice solution!

  • omygawshkenas

    Seconding what marijnhuizendveld said. It would be wonderful if you could highlight the portions of Cappuccino that implement image spriting, perhaps in a blog post that delves more into the code. I'd love to add it to our asset packager.

  • screenshotscores

    Ah this looks very promising! Might give it a try on one of our sites. But i doubt if gzipping images again will have nay benefit and doesnt eat cpu power on server end. Will try and see! :)

  • Calvin Lough

    The only problem with this solution is that images will never be cached. In most cases, this won't be a deal breaker. It's not idea though.

  • Calvin Lough

    I meant to say “It's not ideal though.”

  • boucher

    It's trivial to either include code and images in one file, or beak them into two. More importantly, for most Cappuccino apps, it's easiest to cache and version the entire app, including images. But yeah, there's definitely a tradeoff between granularity of updates and reduction of HTTP requests.

  • boucher

    The code is all part of Objective-J and the tools, which don't require the framework itself. You could always use those in your project without using Cappuccino.

  • slex

    “This has the added benefit that gzip can work its magic on the entirety of your web app as one, producing better results.”

    In my experience, I found that gzipping a base64 string showed little to no improvement in size, and often times made my files _bigger_. What were your results, as far as file-size is concerned, when running gzip on a base64 string?

  • pmuellr

    I see someone else is curious about how you're dealing with the base64 33% expansion. I did a quick test on a fairly standard image used in a web app, base64'd it then gzip'd that:

    - 3968 bytes for original image
    - 5361 bytes for original image converted to base64
    - 4108 bytes for original image converted to base64 then gzip'd

    Seems like gzip'ing base64'd content puts you back in a reasonable range w/r/t the expansion. But wonder how this scales in general, and with lots of images, and how you'd arrange to pre-gzip the base64'd content.

  • WebReflection

    I have served via a single file both JavaScript and CSS with packed.it project and MyMin, both dead due missed interest from Web Community. Now that we have images as well, I guess the day we can serve a single file including everything is close. Just a hint, put a minified CSS properly escaped if where necessary into a string and push it into the DOM before the JavaScript code will be evaluated. Add base64 encoded sprites, and a Web Site will automatically become a single request with a single external file which can be served with a quick 304 and a managed via a proper ETag ;-)

    Good stuff and nice technique, the scary part is how many “secrets” we can discover about IE, discovering it could have been a better browser if forced properly during these 2.0 era – Documentation Failure?

    Regards

  • boucher

    Testing the images in one of our projects, it works out like this:

    - 377 KB raw for all images
    - 520 KB for base64 representations combined
    - 303 KB for combined base64 plus gzipping

    So, it actually saves a significant amount. Plus the savings of the HTTP request overhead.

  • boucher

    Also worth noting that it would probably still be worth it even if the size did increase by 10%, for the perceived speed benefit, and likely the actual speed benefit of reducing the http requests. It's harder to be exact about such things, but because of the parallel download limit, downloading 100 images individually becomes incredibly slow.

  • boucher

    See my reply a little lower. The benefits come because we compress lots of images in a single text file, increasing the amount of redundancy between them. It's like zipping up a folder of images versus zipping up one individually. The former is much more efficient.

  • robmcm

    I was just recently thinking that image (pre)loading was a bit of an elephant in the room with Cappuccino apps.

    This looks like a really good solution, not only in preloading or having required images by the time the app launches, but also by speeding it up with Gzip and reduced HTTP overhead on multiple files.

    Good work guys ;)

  • godavemon

    Incredibly awesome! Great work yet again guys!

  • ManOfTheNorth

    The other advantage to base64, that kind of makes up for the size issues, is that they process at a more native level, with half the chip-level instructions per cycle set. This makes for cleaner, faster transitions.

  • http://draconianoverlord.com shaberman

    Just coincidentally saw this commit into gwt after reading your post. Might be worth pinging them about their experience with MHTML.

    http://code.google.com/p/google-web-toolkit/sou…

  • kevinpan

    Hi, I'm very impressed by the Cappuccino framework. I'm considering to use it to develop a finance application which includes streaming live ticks of stock prices and forex rates updating dynamic charts (line charts, Japanese candlestick charts, etc.). For this type of application, the client (ie. web browser using JavaScript) has to simultaneously open *MANY* concurrent connections to a server and possible use of http response forever method (ie. Comet) to process the live ticks and update the charts. The burning question is: does the Cappucino framework support this many concurrent connections to a server? If anyone could let me know and possible point me to some code I would appreciate it very much. Thanks! Kevin.

  • http://www.creativecode.nl/ Redmar Kerkhoff

    >The burning question is: does the Cappucino framework support this many concurrent connections to a server?

    This is not really a question for the cappuccino framework, it's more related to the user's browser capability. (so you can lookup general limits of concurrent connections for generic browsers) Another idea could be to multiplex the needed concurrent connections through your server which then acts as a kind of proxy resulting in only one connection for the comet stream. (And added advantages that you can cache the data stream for all your users and that you don't suffer from cross domain connection pains)

  • Mateo

    First, I would like to thank you for this amazing framework!

    I've got a couple questions.

    SproutCore has a really interesting framework called DataStore. It allows to manage structured data and it is often used to implement the model layer, read/write data from/to the server, manage relationship between obects and other cool stuff (like managing for you cache). It is designed with cloud computing in mind.
    Do you plan to add a similar framework in Cappuccino?

    Do you plan to write a tutorial covering client-server communication?

    More generaly, do you plan to make client-server communication easier with Cappuccino?

  • kevinpan

    Dear Redmar (and other Cappucino fans, as well):

    Thanks for your answer! The reason for my worry is my colleage said Google Web Toolkit has problems supporting more than 2 concurrent/simultaneous connections. For GWT, it is possible but requires some major workarounds.

    So, I'm wondering how easy to do this with Cappuccino framework? I mean, a stock/forex analysis charting has streams of continuous data feeding to in and updating charts and price display. How reliable would such an application be written using Cappucino?

    Thanks!

    Kevin Pan

  • boucher

    Cappuccino doesn't do anything with the server itself. So how reliable
    those portions will be is completely dependent on how you code them.
    It can be made exactly as reliable as any other web app, since
    everything is using the same set of fundamental technologies. More
    than likely you'd use an existing Comet library of some kind.

  • http://tlrobinson.net tlrobinson

    The 2 concurrent connections is a limitation of the web browser, not any particular framework. There are Comet libraries that let you multiplex multiple streams over a single connection.

    Check out Orbited, js.io, and many others. These libraries can be used in a Cappuccino application.

  • marcuswestin

    Nice work guys.

    I was browsing around your github repo for the relevant code – would you mind giving a pointer for where to start looking?

    Cheers,
    Marcus

  • Cédric

    Great job.
    I was thinking such a feature for a while for the CMS SPIP i'm contributing to.
    But having found a way to get it working for ie6&7 is a major step.

  • kevinpan

    Thanks, boucher and tlrobinson, for your reply! Could anyone give me some pointers on how to draw a chart (or more specifically, a finance chart such as line or candlestick) using the Cappucino framework? What methods do I call or library do I use? (While I am an Objective-C developer, I have not studied the Cappucino framework or Objective-J language. Any starting tips would be appreciated). Thanks!

  • http://tlrobinson.net tlrobinson

    Just like in Cocoa you can implement the drawRect method on a view using the Cocoa or CoreGraphics drawing APIs. Check out some of the tutorials: http://cappuccino.org/learn/tutorials/ (“An introduction to Cappuccino Graphics” in particular)

    Contact us on the mailing list or IRC if you need more help.

  • sirus

    Look at alternative tool – online generator of data:uri css sprites
    http://duris.ru/lang/en/
    Supports MHTML for IE < 8 & data:uri for others modern browsers

  • http://blog.woodylabs.com/ Woody

    This makes so much sense when its put forward so well…Cant believe I missed this!

  • http://cappuccino.org/discuss/2010/04/07/cappuccino-0-8/ Cappuccino Blog » Blog Archive » Cappuccino 0.8

    [...] We alluded to this feature a little while ago when we first announced it at JSConf EU, and now you can finally take it for a spin: automatic image spriting. Yes you read correctly, no more having to manually decide which images to sprite, or how to sprite. The brand new Cappuccino build tools are smart enough to sprite all your images together into one file (not several based on orientation), and of course works in all browsers including IE. You can find out more about thinking behind this feature here. [...]

  • http://www.wallst.com/ Tim

    How do you handle HTTPS/SSL requests in IE*? I've observed this not working with MHTML.

  • http://cappuccino.org/discuss/2010/04/28/introducing-jake-a-build-tool-for-javascript/ Cappuccino Blog » Blog Archive » Introducing Jake: A Build Tool for JavaScript

    [...] (similar to the gem tasks in Rake). These tasks implement some pretty cool optimizations, like our automagic image spriting. If you’re having any trouble, feel free to jump in our IRC room so we can answer your [...]

  • http://www.rpmservicetoronto.com Rental Property Management

    I am here to say something. I support some of the commenter. But not all. Good impression. Thanks

blog comments powered by Disqus

Download

Cappuccino and Objective-J are licensed under the LGPL. For more information, see our licensing page.

Copyright © 2009 - 280 North, Inc. Cappuccino and Objective-J are registered Trademarks of 280 North. Logo by Sofa. Hosting by Slicehost.