3 Weekends, 3 Projects

In this post, I would like to share 3 projects that I managed to work on 3 recently weekends. For a variety of reasons and excuses I haven’t spent as much time as I would love working on my side projects this year. You might even notice that I’ve been way less active on twitter and on my blog (last post was a year ago?!). Anyways let’s start.

#3 – Slow Fast Slow in JS

TLDR: A web app that adjusts the video speed however you want.

Demo: https://zz85.github.io/chop-chop-video/slowfast.html#[[0,0],[0.329,-0.35],[0.642,0.24],[1,0]]

The first small project is an implementation of an IOS app that I love called Slow Fast Slow. Not only it is slick looking, it helps adjust the speed of videos in a intutive manner, not just for the entirity but in sections while interpolating playback rates. Typically to do so you might use a feature called Time Remapping in After Effects that creates hollywood style bullet time scenes, and if you tried that before you know it’s not so simple to use. That’s a reason why I love the app is that you can easily do that, and it became a challenge for me to reimplement it in JS in the browser.

One of the interesting parts of the implementation is figuring out how the curves work. (Thankfully I had some experience playing with curves and splines). An initial approach was to use catmull rom splines however on observation it was ruled out since moving a point never affects more than 2 segments in the original app. Using an approach of rendering bezier curve lines between 2 blocks in a diagram such as mind maps, (using mid points for the bezier control points), I had voila moment that the behaviour match that of the original app. It’s simple, yet it’s really neat that it can work.

Next was integrating the UI with the video in the browser. Thankfully the html video element handles the speedup / slowdown with playback rate. It works well despite some limitations – for example not being able to play in reverse and buffering.

This was an interesting project, and apart from some technical bits I appreciated the UI/UX quality of the Slow Fast app (and wish I find more apps like this). What’s next would be to think about videos could potential be exported as a real video (eg. using ffmpeg.js, server side, or using the new MediaRecorder).

For those interested, check out related source code here.

#2 – Terminal Rendering for Three.js

TLDR: A Three.js Renderer that runs in the terminal.

Project: https://github.com/zz85/threejs-term

3 years ago, I wrote ASCII Effect Adapter for three.js. That was a fun project, it was such an idea so simple I wondered why no one else did that (maybe it was because it wasn’t useful, but at least I’m glad I get to do it). However I believe it wasn’t a totally new idea because if you were to look up some old demoscenes videos, you might just find some 3D rendering in ASCII.

This year I learnt about a really cool nodejs module call blessed. It is a pure js library that helps build terminal applications, abstracting lower level details like terminal encodings. I first learnt about it reading about the webpack dashboard and subsequently tried it at work to build some terminal based tools. And for those curious why the name blessed, it is with constrast the commonly known (n)curses library used for terminal apps.

Running threejs with node.js (& npm/browserify) turns out to be something looked at before. Many class (eg Vector*) in threejs are pretty generic and have little problems running in nodejs. Classes like Renderers that touches the DOM are the more tricky parts.

The straight forward approach would be to mock the dom (as done as by others) using jsdom (quite a cool library too). However, I decided to mock the minimal parts needed (to avoid emulating the entire dom emulation, and lessen dependenices and overheads).

The first polyfill I did was to emulate the 2d canvas and for that I used node-canvas (that uses cario internally) need. The nice thing was that blessed has an AsciiImage widget, and to convert the canvas to the terminal screen all needed was to add this line icon.setImage(canvas.toBuffer()). As I continued working on the lib, I did refactor that code to do manual conversion of pixel to ascii, that gave me more control but strangely slightly slower.

Other challenges include figuring out what canvas size to use. I used a combination of using the number of columns and rows that the terminal reports, and the actual pixel size (if the terminal supports the command), together with some ratios calculations.

The next interesting challenge was to get TrackballControls to work. The trick to emulate the window, converting terminal mouse and keyboard events to DOM like events, which I thought was pretty cool it was possible.

Another idea I had was to eliminate native bindings for threejs-term. One approach was use Arrays instead of Cario to mock SoftwareRenderer. That managed to work but performance wasn’t too great.

The last idea I should mention before I should stop talking about this project is using Braille for rendering. Turns out some brilliant people have figured out how to abuse unicode braille characters to give you 8 subdivisions in a terminal character. Turn out it is not difficult to implement it, and it gives an interesting effect in threejs-term, the only limitation being you can’t get different colours for each “sub-pixel”. I even got a little side-track to reimplement the XKCD braille comics in js.

In closing, I think had fun with threejs-term. Terminal seems to be such old and limited technology yet I’ve learnt different cool stuff doing this. Going forward, I think I would love to explore node-gl or headless-gl for threejs-term, as well as rendering more (CJK and emoticons) unicodes. As for the blessed library, I think there are so much more use cases for it, and I would love to see someone implement Vim or Tmux using it one day.

#1 – Mr.doob’s Code Style™

TLDR: MDCS is now available as an ESLint rule (and npm module). MrDoob approves Editor now supports ES6 and also powered by Eslint now.

Checkout: https://github.com/zz85/mrdoobapproves

It’s been almost more than a year since I’ve updated Mr Doob approves. Once a while, it might be used by a threejs contributor using it to format code in PRs, and sometimes for the fun, I like to toggle between code styles. On another weekend while trying to update the JSCS formatting rules, I realized that JSCS have sunseted and I took the opportunity to migrate the rules to EsLint.

Not a bad timing. The contributors of JSCS have now joined Eslint, and given the popularity of EsLint (I guess in addition to wider spread use of ES6), ESLint has became more matured too. The JSCS editor was fairly mature, so I think it was good for it to have some usage in real life before another migration.

It was also good that there were a couple of test cases for mdcs in JSCS, so after adding a couple more test case, the migration to ESLint became easier. What’s funny was that only after I hand migrated the rules, did I realize there was a migration guide from JSCS to EsLint though.

Apart from using EsLint to power “mrdoob approves”, the fact that Eslint is supported by many editors and project led me to question why not expose the eslint rule as an npm module instead? Therefore to now use the rule, one can simply run

npm install –save-dev eslint-config-mdcs

And add a line `{ “extends”: “mdcs” }` to .eslintrc.

After adding .eslintrc to the three.js project, I learnt a rule can also be added via package.json.

Closing:
This is a good milestone with my experiences with code formatting, something that seems so trivial yet in many ways complex and subjective. We started with an itch, a vision, till executing that the vision.

Code formatting has also brought me down the route playing with, experimenting, learning about tools like sed, code painter, jscs, autoformatting patches, esprima till eslint. Despite the journey, it’s nice to see tools like npm and eslint in action. One recent related interesting article I was reading, was the journey behind Feross’s standard style.

Next steps: Getting more code styles to run in the editor (mainly figuring how to browserify the plugins) and more exploring more funky code styles (semi-colons style indentations).

Final thoughts: I’m not sure if I jabbering down this what might be quite lengthy post, but it’s always nice getting a blog post of out my system. It’s about time for me to write less and more often, and continue working on interesting stuff that matters.