thingsinjars

  • 8 Aug 2010

    The quest for Extreme JavaScript Minification

    As described in detail previously, I've recently taken part in the JS1K competition where you have to squeeze something cool and clever into 1024 bytes of JavaScript. The quest to condense has become quite addictive and I found myself obsessing over every byte. This is the kind of stuff that the Closure Compiler does quite well automatically but there are some cases where you just need to get in there and manually tweak.

    Here are some of the tricks I've picked up in my struggle for extreme minification:

    Basic improvements

    Use short variable names.

    This one's fairly obvious. A more useful addition to this is:

    Shorten long variable names.

    If you're going to be accessing an element more than once, especially if it's a built-in element like 'document', you'll save a few bytes every time you reference it if you create a shortened reference to it.

      document.body.style.overflow="hidden"
      document.body.style.background="red"
      (74 characters)
    

    can shorten to

      d=document;b=d.body;s=b.style;
      s.overflow="hidden";
      s.background="red"
      (69 characters)
    

    and any references to s after are going to save 19 characters every time.

    Remove whitespace

    This one's so obvious, I don't need to mention it.

    Set Interval

    The extremely handy setInterval function can take either a function or a string. If you give it an anonymous function declaration:

      setInterval(function(){x++;y--},10);
    

    You will use up more characters than if you give it just the inside of the function as a string:

      setInterval('x++;y--',10);
    

    But the outcome will be the same.

    Little-used aspects

    Not many people use JavScript's scientific notation unless they're doing scientific stuff but it can be a great byte saver. The number 100 is equivalent to 1 * 10^2 which is represented in JavaScript as 1E2. That's not a great saving for 100 but 1000 is 1E3, 10000 is 1E4. Every time you go up a factor of 10, you save 1 byte.

    Fight your good style tendencies

    In the war against space, you have to bite the bullet and accept that you may need to sacrifice some of your hard-earned practices. But only this once. Don't get in to the habit, okay?

    No zeroes

      0.5  = .5
    

    Yeah, it looks ugly but it works and saves a byte.

    Naked clauses

      if {
        :
        :
      } else y
    

    The y looks so naked out there. No braces to keep it warm. But if you only have one statement in your else clause, you don't need them...

    No semi-final. . . final-semi. . . Semi-colon. No final colon.

    You don't need a semi-colon on your last line, even if it does make it look as though you've stunted its growth.

    The final few bytes

    Operator precedence

    You don't need brackets. Brackets are handy for you as the programmer to remember what's going on when and to reduce ambiguity but if you plan correctly, most of the time you won't need brackets to get your arithmetic to work out.

      b.getMilliseconds()/(a*250) 
          is the same as
      b.getMilliseconds()/a/250 
    

    Shorthand notation

      l=l+1;l=l%14;
      l++;l%=14;
      l=++l%14;
    

    The three lines above are equivalent and in order of bytes saved.

    Shorthand CSS

    If you need to set some CSS values in your script, remember to pick the most appropriate short form. Instead of s.background='black', use s.background='#000' but instead of s.background='#F00', use s.background='red'. In the same vein, the statements margin="0px" and margin=0 mean the same but the latter saves bytes.

    Don't be generic

    One final thing to mention is that these little challenges are not the norm. If you find yourself trying to squeeze code down like this you're probably working on a very specific project. Use that to your advantage and see if there are any savings to be made by discarding your usual policies on code reuse. In the JS1K challenge, we're provided with a specific HTML page and an empty script tag. One good saving made here (and mentioned in my previous post) was the way I grabbed the reference to the canvas element. The standard method is to use the id assigned to the canvas.

      d.getElementById('c')
    

    Which is a good generic solution. No matter what else was on the page, no matter what order stuff was in, this would return the canvas. However, we have a very specific case here and the canvas is always going to be in the same place - the first child of the body element. That means we can do this instead:

      b.children[0]
    

    This makes use of the reference we grabbed to the body earlier. If the page were rearranged, this would stop working but as it won't, we've saved 8 bytes.

    In conclusion

    Yes, this is all quite silly but it's also fun and tricky. Attempting these kinds of challenges keep us developers mindful of what it is we actually do and that makes it an extremely productive silly hobby.

    Development, Javascript, Geek, Guides

  • 4 Aug 2010

    Elementally, my dear JavaScript

    The Angry Robot Zombie Factory launched its second iPhone/iPad app this week. I haven't mentioned it much yet because I spotted a minor typo in the final version after it had been approved so I submitted an update immediately. To get an early copy (like those misprinted stamps where the plane is upside down), go check out The Elementals. It's free, too. It's a simple, cartoonish periodic table.

    Yesterday, the 1k JavaScript demo contest (#js1k) caught my eye. The idea is to create something cool using 1024bytes of JavaScript or less. I rootled around in the middle of The Elementals, grabbed the drawing function and 20 minutes later had made my entry.

    The code I submitted is quite minified but isn't obfuscated. When it's unfolded, you can follow the flow fairly easily.

    var d = document,
    b = d.body,
    s = b.style,
    w = innerWidth,
    h = innerHeight,
    v = b.children[0],
    p = 2 * Math.PI,
    Z = 3,
    x = tx = w / 2,
    y = ty = h / 2;
    

    The above is a bunch of declarations. Using things like d = document and b = d.body allows reuse later on without having to resort to the full document.body.style and saves a bunch of characters. When you've got such a small amount of space to play with, every character counts (mind you, the ZX81 only had 1k of RAM and look what you could do with that). Now that I'm looking at it, I think I could have tidied this a bit more. Darn. The sneaky bit about this code is the way we grab the reference to the canvas. The code d.getElementById('c') uses 21 characters but if we look at the provided HTML, we can use the fact that the canvas is the first child of the body element. The code b.children[0] uses 13 characters instead.

    s.margin = "0px";
    s.background = "black";
    s.overflow = "hidden";
    v.width = w;
    v.height = h;
    t = v.getContext("2d");
    

    This sets the provided canvas to be the full width and height of the window then grabs the drawing context of it so we can make pretty pictures.

    zi = function () {
     Z++;
     Z %= 14
    };
    m = function (X) {
     return (X * 200) % 255
    };
    

    Functions to be reused later. zi increases the number of spinning circles and is used by onmousedown and ontouchstart (oh yes, it works on the iPad, too). m is a mapping of the index of the circle to a colour. The 200 is arbitrary. I played about a bit until I found some colour combinations I liked.

     d.ontouchstart = function (e) {
     zi();
     tx = e.touches[0].pageX;
     ty = e.touches[0].pageY
    };
    d.onmousemove = function (e) {
     tx = e.clientX;
     ty = e.clientY
    };
    d.onmousedown = zi;
    

    Setting the event handlers.

    function r() {
     t.globalCompositeOperation = 'lighter';
    

    I played about with the various composite operations. Lighter seemed the nicest.

     t.clearRect(0, 0, w, h);
     t.save();
     x = x + (tx - x) / 20;
     y = y + (ty - y) / 20;
     t.translate(x, y);
    

    Originally, the circles followed the mouse pointer exactly but it lacked any life. By adding in this bit where the movement is delayed as if pulling against friction, it suddenly became a lot more fun and dynamic.

     var c = new Date();
     for (var i = 1; i <= Z; i++) {
      t.fillStyle = 'rgba(' + m(i) * (i % 3) + ', ' + m(i) * ((i + 1) % 3) + ',' + m(i) * ((i + 2) % 3) + ', 0.5)';
      t.beginPath();
      t.rotate((c.getSeconds() + i) / (i / 4) + (c.getMilliseconds()) / ((i / 4) * 1000));
      t.translate(i, 0);
      t.arc(-10 - (Z / 5), -10 - +(Z / 5), 100 - (Z * 3), 0, p, false);
      t.fill()
     }
    

    Erm. Yeah. In essence, all this does is figure out where to draw the circles, how big and what colour. It looks worse than it is. Line-by-line, it translates to:

    1. Find out the current time
    2. For each circle we want to draw,
    3. Pick a colour based on the index of the circle
    4. Start drawing
    5. Turn by some amount based on the time and the index
    6. Move by a small amount based on the index
    7. Actually draw, making the circles smaller if there are more of them.
    8. Fill in the circle with the colour.
    9. Right curly bracket.
     t.save();
     t.fillStyle = "white";
     for (var i = 1; i <= Z; i++) {
      t.beginPath();
      t.rotate(2);
      t.translate(0, 28.5);
      t.arc(-120, -120, 5, 0, p, false);
      t.fill()
     }
     t.restore();
     t.restore()
    }
    

    This does pretty much the same as the one above but always the same size and always the same colour. The t.save and t.restore operations throughout mean we can add the transformations onto each other and move stuff relative to other stuff without messing up everything. Goshdarn, that was technical.

    setInterval(r, 10);
    

    Kick it all off.

    That make sense? Good. Now go make your own js1k entry and submit it. Then download The Elementals. Or Harmonious.

    Geek, Javascript, Development

  • 17 Jun 2010

    PhoneGap - The Drupal of App development

    I'm a fan of Drupal even though I don't use it that often. I like that I can see exactly what's going on. I can easily follow the execution from URL request to page serve.

    What I usually end up doing on any Drupal project is:

    1. build the majority of the site in a few hours
    2. find one small piece of functionality missing that's absolutely essential
    3. dig into the core to make it happen
    4. find a simpler way of doing it and step out of the core a bit
    5. find an even simpler way and step back a bit more
    6. figure out how to do it in a single module file and put the core back the way it was.

    That probably seems utterly inefficient but it has served me well since Drupal 4 and it means I've got a really good picture in my head of the internal workflow.

    This is in stark comparison to other systems, particularly some .NET CMSs where a request comes in, something happens and the page is served. There are even some PHP frameworks and CMSs where everything is so abstracted, the only way you can get an accurate picture of what is happening is to already have an accurate picture of what is happening.

    I've used several different ones and I keep coming back to Drupal (also, recently, Perch, but that's besides the point here).

    “What on earth does this have to do with PhoneGap?” I hear you ask. Quite rightly, too.

    When I was planning Harmonious, I looked at various frameworks for turning a combination of HTML, CSS & JavaScript into an app - PhoneGap, Appcelerator Titanium, Rhomobile. Rhomobile (or the Rhodes Framework) is built on Ruby so I didn't investigate too far. That's not to say it's not a good framework, I couldn't say either way. The idea behind using one of these frameworks is to save you the time of having to learn Objective-C and seeing as I've only done very minimal amounts of Ruby, I'd be replacing 'learn Objective-C' with 'learn Ruby'. That said, I've always thought Ruby developers opinion of themselves was slightly too high.

    The first framework I properly spent some time with was Appcelerator. It seemed quite shiny and I liked having single interface access to compilation for iPhone and Android but I wasn't so keen on having to sign up for an account with them for no obvious reason. Some further investigation suggested that this was so you could send your project to their servers for proprietary cross-platform compilation of your desktop app. This is less useful, however, if you're developing just for iPhone and Android as for both, you need the SDK installed locally and the compilation is done on your own machine.

    The main thing that I wasn't comfortable with in Appcelerator was that there seemed to be a lot happening behind the scenes. This is not necessarily a bad thing, of course, but it started that little buzz in the back of my head that I get when working on .NET. When I press 'compile', I want to know exactly what it's doing. I want to know exactly how it takes my JavaScript and embeds it, when does it include its own API files and what do I change to make it do stuff it doesn't do by default?

    After that, I moved to PhoneGap (version 0.8.3) and found myself immediately falling into my Drupal workflow. The app fell into place in less than an hour (with a liberal sprinkling of jQTouch and the Glyphish icons). I then needed to take a screenshot and couldn't see an obvious way to do it but, due to the nature of PhoneGap being completely open-source, it was easy to spot where to jump into the code. I hacked in a screenshot function in another hour, spent another half hour making it better and another making it simpler. Just to complete the cycle, I have now wrapped up all my code into a plugin and removed my hacking from the core. Hmmm... that all seemed eerily familiar.

    That's not to say PhoneGap is perfect. All the benefits of a completely open-source project referred to previously also come with all the drawbacks. The current version (0.9.0) is fiendishly difficult to download and get started with. It has been split into one parent project and several child projects (one per mobile platform) and it's no longer obvious what you do. It's easy enough if you're already set up but actually getting there is tricky. The most common failing of any open-source project is also true: poor documentation. There's a wiki but it's mostly out-of-date. There's a section on phonegap.com called 'docs' but they're also out-of-date. There's an API reference but it's autogenerated from comments and is also out-of-date. The only place to get accurate information is the Google group but that's not documentation, that's solutions to problems.

    There have also been some claims that PhoneGap is unstable and crashes but personally, I haven't seen that. It's possible that the crashes and performance issues are the result of memory leaks in the JavaScript. Appcelerator automatically runs JSLint on your code before compilation so it will highlight any problems. If you can fit that into your standard workflow, you might be able to avoid some of the instability.

    Additional comments

    It seems that Disqus (the commenting system I'm using below) has some problems with Safari 5 & Chrome so this comment was sent via gist (I knew I shouldn't have stopped using Noodle).

    I'll respond later. I've just got back from the Apple store and have toys to play with.

    Comment from Jeff Haynie (@jhaynie)

    A few comments about Appcelerator.

    1. We're completely open source and you can see all our active development every single commit on github.com/appcelerator. We have plenty of outside core open source contributors.

    2. Yeah, to do what we're doing, it's complicated - much more than Phonegap - so it does mean with complexity it's hard to grok. however, the source is all there. Also, it's full extensible through our SDKs and we this SDK as the way we build Titanium itself.

    3. For Desktop, we _only_ upload to our build servers as a convenience to cross-platform packaging. Nothing mysterious and all the scripts we run are included (and open source) so you can run them on your own. Plenty of our customers do this behind the firewall. When you're developing locally (say on a OSX machine), it's all local during dev. Only cross-platform packaging is done as a convenience to developers. We have to pay for this bandwidth and storage and we do it to make it easier. And it's free.

    Hope this clarifies some of the above. Phonegap's a great project and we love the team - but I think we're trying to do different things and come at it from different approaches. In the end, this is good for developers as it gives everyone more choice based on their needs.

    Geek, iOS, Development

  • 10 Apr 2010

    List of Touch UI gestures

    Just now, I'm trying to improve the UI for the Factory's first iPhone app. While doing this, I've come up with a list of available areas and gestures in a touch-driven app that you can use for actions. I thought I'd put them here so other people could point out where I've gone wrong and what I've forgotten:

    • Menus
      • Permanent on-screen menu
      • Transient on-screen menu (requires trigger)
      • Different screen menu (any number of them, requires trigger)
    • Static (can be overloaded with function based on position)
      • Single-tap
        • Single-tap 1 touch
        • Single-tap 2 touches
        • Single-tap 3 touches
      • Double-tap
        • Double-tap 1 touch
        • Double-tap 2 touches
        • Double-tap 3 touches
      • Touch and Hold
        • Touch and Hold 1 touch
        • Touch and Hold 2 touches
        • Touch and Hold 3 touches
    • Dynamic (Gestures)
      • Touch and Move 1 touch
        • Up
        • Down
        • Left
        • Right
      • Touch and Move 2 touches
        • Up
        • Down
        • Left
        • Right
        • Apart (Zoom)
        • Together (Pinch)
        • Rotate clockwise
        • Rotate anticlockwise
      • Touch and Move 3 touches
        • Up (Swipe)
        • Down (Swipe)
        • Left (Swipe)
        • Right (Swipe)
        • Apart (Spread)
        • Together (Gather)
        • Rotate clockwise
        • Rotate anticlockwise

    Geek, iOS, Design

  • newer posts
  • older posts

Categories

Toys, Guides, Opinion, Geek, Non-geek, Development, Design, CSS, JS, Open-source Ideas, Cartoons, Photos

Shop

Colourful clothes for colourful kids

I'm currently reading

Projects

  • Awsm Street – Kid's clothing
  • Stickture
  • Explanating
  • Open Source Snacks
  • My life in sans-serif
  • My life in monospace
Simon Madine (thingsinjars)

@thingsinjars.com

Hi, I’m Simon Madine and I make music, write books and code.

I’m the Engineering Lead for komment.

© 2025 Simon Madine