javascript demoscene
techniques

or
how to have fun in a constrained environment
(10/12/13)

Philippe Deschaseaux

history

demoscene

Dates back to the end of the 70's

cracked games + demos

constraint triggers creativity and ingenuity

recreational programming


  • code golf: shortest code that implements an algorithm
    (
    various languages)

  • obfuscation and language abuse: IOCCC


  • quines

javascript ?

  • historically constrained
  • ubiquitous: in every browser, and now on the server
  • easy: no preprocessing or compilation
  • multipurpose: graphics, sound, webGL, webRTC, asm.js, etc.

js particularities

C-like syntax


  • control structures (if, for, while, ...)
  • statements / expressions
  • ! variable scope (block / functions)
  • ! use of semicolon

dynamic


primitive types and objects
0, abc, true

{ a: 12, b: function() {...} }

Function, Date, Math
dynamic typing
var a = 1;
a = '1';

0, null, undefined, false, "", NaN

[] + [] = ""
[] + {} = [object Object]
{} + [] = 0
{} + {} = NaN
evaluation at run-time
eval('a = b+1') 

functional


functions are first-class citizens
var f = function() {};
n = f.length;
f.call();
button.onclick(f); 
higher-order functions
var adder = function(b) {
    return function(a) { return a+b }
} 

prototypal


prototypal inheritance
var parent = { prop: 'foo' };
var child = Object.create(parent);
enfant.prop; // 'foo'
method != function
obj.getProp = function() {
    return this.prop
}
obj.getProp();
obj.getProp.call(obj2); 

challenges/contests


140byt.es

  • must fit in a tweet
  • entry = javascript function
  • permanent challenge

js13kgames


  • game-oriented
  • entry = zipped package (index.html + assets)
  • no dependencies
  • september-august

js1k


  • loosely themed
  • entry = js code runnable inside the shim
  • no dependencies
  • march-april

demoparties

Assembly, Revision, demoJS, etc.


various techniques

demo types

(non-exhaustive)

engine


fractals / IFS
pseudo random generators
genetic algorithms

! Math skills required

algorithms & data structures
optimization


no recipe, but needs time & imagination

example:
color palette compression

fuzzy trigonometry


π/2 ≡ π/2+2π ≃ 8
π/3 ≡ π/3+28π ≃ 89
π ≡ π+6π ≃ 22
-π/2 ≡ -π/2+4π ≃ 11

sin(α) = cos(α-π/2) ≃ cos(α+11)

X=x*Math.cos(a)-y*Math.sin(a);
Y=x*Math.sin(a)+y*Math.cos(a); 
becomes
C=Math.cos;
X=x*C(a)-y*C(a+11);
Y=x*C(a+11)+y*C(a); 

js bytes saving techniques

heavily based on implicit type casting

examples
a = Math.floor(b);
a = 0 | b; 
if (a != 0) { b = 'on' }
a && b = 'on';
setInterval(function F(a) {
    if (a) { return ... }
    ...
    b = F(12);
    ...
}, 100); 

function names shortening


canvas (Martijn Haverbeke)
for(k in c)c[k[0]+[k[6]]]=c[k];

c.fc == c.fillRect
c.qt == c.quadraticCurveTo
c.da == c.drawImage
... 

WebGL (Mathieu 'p01' Henri)
for(k in g)g[k.match(/^..|[A-Z]|1f$/g).join('')]=g[k];

g.coS   == g.compileShader
g.enVAA == g.enableVertexArrayAttribute
g.veAP  == g.vertexAttributePointer
... 

Minification


  • parser-based
  • removes useless white-spaces, semicolons, brackets
  • removes unused code
  • obfuscates variable nouns

Crushing

(Aivo Paas)

1st pass: entropic compression of the source code
_="X=x*Math.cos(a)-y*Math.sin(a);Y=x*Math.sin(a)+y*Math.cos(a);" 
becomes
_="X=x2-y1;Y=x1+y2;4*Math.3(a)24cos314sin3" 
with self-extracting code
for(Y=0;$="tokens"[Y++];)Z=_.split($),_=Z.join(Z.pop());eval(_) 

2nd pass: compressed code optimization using regexps

PNG packing

(Jacob Seidelin / Alex Le)
Uses the browser's PNG decompressor (zlib)

1 .html file + 1 .png file
<script>
    var o=new Image();
    o.onload=function() {
        r="",t=document.createElement("canvas").getContext("2d");
        t.drawImage(o,0,0);d=t.getImageData(0,0,o.width,o.height).data;
        for(i=0;d[i];i+=4)r+=String.fromCharCode(d[i]);
        eval(r)
    };
    o.src=m.png";
</script> 
  • code is compressed into PNG beforehand
  • HTML code evaluation
  • PNG image is loaded into a canvas
  • levels of grey are converted into ASCII codes

PNG bootstrapping


(Cody 'Daeken' Brocious / Mathieu 'p01' Henri)
Same idea, but only 1 .html file !

...image data...
<canvas id=c>
    <img src=# onload="for(a=c.getContext('2d'),i=e='';a.drawImage(this,i--,0),t=a.getImageData(0,0,1,1).data[0];)e+=String.fromCharCode(t);eval(e)">
</canvas>

  • first pass: '.html' extension has priority
  • HTML code evaluation: canvas + img
  • file is reloaded as a PNG image
  • levels of grey are converted into ASCII codes

demos

js1k 2013
p01


demo tweaking


links






JS demoscene techniques

By Philippe Deschaseaux

JS demoscene techniques

  • 4,633