Tuesday, March 11, 2014

Zethos - $3.5 million in 1kb


Zethos is my $3.5 million dollar entry to js1k 2014. It's a speed reading tool, allowing almost anyone to read at 500 words per minute (the average person reading 250wpm [1]). By keeping the text centered within the readers view, the reader is able to reduce costly eye movements and increase their reading speed.

Zethos was inspired by Spritz, who recently raised a $3.5 million seed round for their speed-reading technology. However their software is closed and their system is not developer friendly so I decided to make my own. Without further ado, here is what $3.5 million code looks like:

parse = function(str) {
  // Logic
  // strings will be broken out into words
  // find the focus point of the word
  // if, when the word is shifted to its focus point
  //   one end prodtrudes from either end more than 7 chars
  //   re-run parser after hyphenating the words
  
  // focus point
  // start in middle of word (default focus point)
  // move left until you hit a vowel, then stop
  
  // hyphenating
  //    if <= 7 chars
  //      return self
  //    if <= 10
  //    return x, {3}
  //    if <= 14 chars
  //    return {7},{7}
  //    else
  //    return {7},hyphenated{x}
  
  hyphenate = function(str) {
    with(str)
    return length <= 7 ? str : length <= 10 ? slice(0,length - 3)+'- '+slice(length-3) : slice(0,7)+'- '+hyphenate(slice(7))
  }
  
  // return 2d array with word and focus point
  return str.trim().split(/[\s\n]+/).reduce(function(words, str) {
    with(str) {
      // focus point
      focus = (length-1)/2|0
      
      for(j=focus;j>=0;j--)
        if (/[aeiou]/.test(str[j])) {
          focus = j
          break
        }
      
      t = 60000/500 // 500 wpm
        
      if (length > 6)
        t+=t/4
        
      if (~indexOf(','))
        t+=t/2
        
      if(/[\.!\?;]$/.test(str))
        t+= t*1.5
      
      return length >= 15 || length - focus > 7 ? words.concat(parse(hyphenate(str))) : words.concat([[str, focus, t]])
    }
  }, [])
}

p = function() {
  index = 0
  input = parse(i.textContent);
  playing = !playing
  playing && loop()
}

loop = function() {
  w = input[index++] || p()
  o.innerHTML = Array(8 - w[1]).join('&nbsp;')+w[0].slice(0,w[1])+'<v>'+w[0][w[1]]+'</v>'+w[0].slice(w[1]+1)
  playing && setTimeout(loop, w[2])
}

p()

I've done Javascript Golfing before, so getting this code to fit in at less than 1kb was trivial. With the help of Grunt, I was easily able to compile my code by running it through the Google Closure Compiler and then JSCrush. They key to the code however is it's recursive nature. The self-calling methods allow the code to be extremely concise and not reliant on a buffer or global variables. The Hyphenate method for example will recursively hyphenate the word it's given based on length for arbitrarily sized words using recursion.

As far as implementation goes, the part that could be most improved for production applications would be to add proper hyphenation. There's a paper written about algorithmic hyphenation, and even a npm library to do this, however fitting it in 1kb was not feasible.

Lastly, my first js1k attempt this year did not work out. It was intended to be a neural network handwriting recognition engine (TinyNet), but unfortunately the weights of the network proved to be highly non-compressible.

Tuesday, March 4, 2014

The Pond at Mobile World Congress with Firefox OS


Last week I attended Mobile World Congress in Barcelona, Spain after being invited by Mozilla to show off The Pond (blog post). Originally Mozilla found me through my blog, and asked me to write a post about The Pond on Mozilla Hacks. For Mobile World Congress they were looking for app developers to help showcase Firefox OS, which is where I came in.

Before heading out though, I decided to update the app in a few areas:

Memory Management Update

The first thing I looked at was memory management, and attempted to achieve static memory via object pooling. Unfortunately things didn't go smoothly, though decreasing allocations inside core inner loops aided greatly in reducing the rate at which the garbage collector ran.


Device Scaling via devicePixelRatio

If you're not familiar with mobile web, the following meta tag is used to properly scale websites:
<meta name="viewport" content="width=device-width,user-scalable=no">

However, the problem with this approach is that it scales the canvas as well, causing the rendering to be low resolution. The solution is to scale the canvas size relative to the device pixel ratio, increasing the rendering resolution without changing the physical size of the canvas:
devPixelRatio = window.devicePixelRatio || 1
$canvas.width = window.innerWidth * devPixelRatio
$canvas.height = window.innerHeight * devPixelRatio
ctx = $canv.getContext('2d')

Background Music

A while back I created a game called Avabranch, wherein I used a background sound track I found on Sound Cloud. The author of that track, Chrissi Jackson, got in touch with me and offered to create an audio track for The Pond. She did a fantastic job, and got it to me just in time, with the commit going in less than 3 hours before the conference.



Mobile World Congress

Surprisingly, the vast majority (I'd say ~90%) of attendees were business people and not developers. Even more surprising was the crazy world of meetings which manifested itself at the conference by means of physical meeting rooms. The first hall was entirely dedicated to meeting rooms, and more were spread out throughout the rest of the halls. That being said, I personally got to speak with some amazing people, including the guy behind js13k games (for which I wrote Senshi), someone from Aviary, and a few people from Line.

Many people were interested in The Pond, which I demoed for those that came to the Firefox OS booth. Additionally, I got to show a few people Zoggle, and got some great responses (Spanish Zoggle might be coming soon!). Overall most people seemed to enjoy the games and were really interested in the technology behind them.

There were also a few interesting products at MWC, including some Tizen and Ubuntu mobile devices and a handful of smart watches which were fun to play with. However, both were trumped by the recently announced $25 Firefox OS phone (which I tested out). The potential impact of the phone is huge, and look forward to the challenge of developing for such a low-end device.

Barcelona


And finally I also got to spend some time exploring the beautiful city of Barcelona (drinking age 18):