# MATRAKA Lessons learnt in 4 weeks and 1kb --- # Mathieu *P01* Henri JavaScript freak, *@p01*, Demo maker, JS1k runner up --- # MATRAKA & DemoJS One month of preparation for a Demo-ish result --- M=[R=Math.random,Q=Math.cos,c.style.cssText='position:fixed;top:0;left:0;width:100%;height:100%;background:#000',e='data:audio/wav;base64,UklGRiQAAABXQVZFZm10IBAAAAABAAEAwF0AAMBdAAABAAgAZGF0YQAA'];for(t=2560;t--;)M[t]={t:t,u:t%48/7.64,v:t/366.7,x:128-R()*256,y:64-R()*256,z:128-R()*256};for(t=0;t++<8e5;)e+=btoa(S('13107103135701314204'[(t>>10&15)+(t>>13&4)]*t&96,R()*127*(Math.pow(t/144000%1,16)/4+Math.pow(1-t/144000%1,64)),t>>10&7^5||R()*127));Z=new Audio(e);Z.play(setInterval(function b(v,w){if(v)return w.W-v.W;M.sort(b);h=c.height=0|300*innerHeight/innerWidth;C=Q(r=Z.currentTime/2);S=Q(r-8);a.rotate((r&13)/64-.1);B=r/9;A=Math.pow(B%1,64);d=[1-A,0,A][0|B++%3];f=[1-A,0,A][0|B++%3];e=[1-A,0,A][0|B++%3];for(t=2560;t--;){v=M[t];if(v.W>0)a.fillRect(150-v.W*v.U,v.W*(v.y+Math.max(16*Q(r),150-r*42))+h/2,v.W*7,v.W*7,a.fillStyle='hsl('+[r*17-v.y+R()*48,(16+R()*48)+'%',v.W*7+32-32*Q(v.u*2-8)*Q(v.v*3-8)]+'%)');if(v.t<2304)Y=96-30*v.v,D=32+8*Q(v.u*2)*Q(v.v*3),v.x=(96-30*v.u)*d+D*(Q(v.u)*e+Q(v.u)*Q(v.v/2-8)*f),v.z=Y*d+D*(Q(v.u-8)*e+Q(v.u-8)*Q(v.v/2-8)*f),v.y=D*d+Y*e+D*Q(v.v/2)*f;v.W=128/(v.z*C-v.x*S+96);v.U=v.x*C+v.z*S}a.fillText(['P01 4MAT','MATRAKA'][B&1].substr(a.drawImage(c,0,r*h%h,32,h/8*(3+A+Q(B+A)),0,r*h%h,300,h/8*(3+A+Q(B+A))),r*8-48)+'|',32,h/2)},Z.loop=9)) --- # [This is **MATRAKA**](assets/matraka.webm) --- # Getting the basics right ## *week #1* --- ## Voxels vs particles ![](assets/comanche.png) ![Oregon Trail Carriage Point Cloud by p01](assets/particles.png) --- ## DOM vs Canvas ![](assets/3dtomb2.gif) ![](assets/wolf1k.gif) -- # Viewport, animation loop & rendering Compact with full control of the resolution and aspect ratio -- # Viewport // the classic viewport setup/update c.width=innerWidth-20;c.height=innerHeight-10; --- # Matraka's viewport // setup c.style.cssText='position:fixed;top:0;left:0;width:100%;height:100%;background:#000'; // update h=c.height=0|300*innerHeight/innerWidth; --- # Animation loop Particle engines go this way * compute new positions * sort * display * compute new positions * sort * display * ... -- # Matraka's animation loop * sort * display * compute new positions * sort * display * compute new positions * ... --- # Shadowed sort method setInterval ( function b(v,w) { if(v) return w.W-v.W; M.sort(b); /* Display particles & compute new positions */ }, 9 ); --- # Combined display & compute new positions for(t=2560;t--;) { v=M[t]; // render if the particle is in front of the camera if(v.W>0) a.fillRect(150-v.W*v.U,v.W*v.y+h/2,v.W*7,v.W*7,a.fillStyle=v.color); // compute new position // Rotation against one axis is enough v.W=128/(v.z*C-v.x*S+96); v.U=v.x*C+v.z*S } --- ## *Week #1* over A point cloud spinning around with full control of the viewport. --- # Designing the objects ## *week #2* --- # The heightmap To produce a bumpy plane, cylinder and sphere --- # The heightmap The source code is the data! ![](assets/sourcecode.png) h = _.charCodeAt((x+y*w)&1023) -- # The heightmap cos(x) * cos(y) to the rescue ![](assets/cosxcosy.png) h = Math.cos(x)*Math.cos(y) --- # Bumpy Plane, Cylinder, Sphere See the heightmap as normal vector, projected on these surfaces --- # Plane ![](assets/plane.png) X = x Y = y + h Z = z --- # Cylinder ![](assets/cylindrical.png) X = (x + h) * cos(a) Y = y Z = (z + h) * sin(a) -- # Sphere ![](assets/spherical.png) X = (x + h) * cos(a) * sin(b) Y = (y + h) * cos(b) Z = (z + h) * sin(a) * sin(b) --- # Morphing objects Special cases of the spherical coordinate conversion d=[1-A,0,A][0|B++%3]; f=[1-A,0,A][0|B++%3]; e=[1-A,0,A][0|B++%3]; /* ... */ Y=96-30*v.v, D=32+8*Q(v.u*2)*Q(v.v*3), v.x=(96-30*v.u)*d+D*(Q(v.u)*e+Q(v.u)*Q(v.v/2-8)*f), v.z=Y*d+D*(Q(v.u-8)*e+Q(v.u-8)*Q(v.v/2-8)*f), v.y=D*d+Y*e+D*Q(v.v/2)*f --- ## *Week #2* over Morphing objects spinning around. --- # Packing & music ## *week #3* --- # JS Packer for($="packed code";t=$.match(/[tokens]/);$=t.join(t.shift()))t=$.split(t);eval($) ## *1000+ bytes* --- # PNG bootstrap <canvas id=c><img src=# onload=for(a=c.getContext('2d'),i=e='',S=String.fromCharCode;a.drawImage(this,i--,0),t=a.getImageData(0,0,1,1).data[0];)e+=S(t);(1,eval)(e)> ## *~850 bytes* --- # Music Something phat and glitchy! --- # Music ## *Take 1* Ambient tune by playing the source code slowly --- # Music ## *Take 2* Dubstep using the source code and *playbackRate* --- # Music ## *Take 3* Experimental music from very short programs (t<<3)*[8/9,1,9/8,6/5,4/3,3/2,0][[0xd2d2c8,0xce4088,0xca32c8,0x8e4009][t>>14&3]>>(0x3dbe4688>>((t>>10&15)>9?18:t>>10&15)*3&7)*3&7] --- # Music ## *Take 4* Experimental music composed by a chiptune superstar # *4mat* ![](assets/music_tool.png) --- # Music synth and replay e='data:audio/wav;base64,UklGRiQAAABXQVZFZm10IBAAAAABAAEAwF0AAMBdAAABAAgAZGF0YQAA';/* ... */for(t=0;t++<8e5;)e+=btoa(S('13107103135701314204'[(t>>10&15)+(t>>13&4)]*t&96,R()*127*(Math.pow(t/144000%1,16)/4+Math.pow(1-t/144000%1,64)),t>>10&7^5||R()*127));Z=new Audio(e);Z.play(/* ... */,Z.loop=9) 275 bytes, over 1 minute of 8bits music with three channels at 8khz --- ## *Week #3* over Morphing objects spinning around with kick ass glithcy music around 1k. Still dull. --- # The final touches ## *week #4* --- # Text writer ![](assets/text.png) a.fillText(['P01 4MAT','MATRAKA'][B&1].substr(0,r*8-48)+'|',32,h/2) --- # Glitches ![](assets/glitches.png) a.drawImage(c,0,r*h%h,32,h/8*(3+A+Q(B+A)),0,r*h%h,300,h/8*(3+A+Q(B+A))) Stretch a sliding window of 32px --- # The Crash cymbal R()*127*(Math.pow(t/144000%1,16)/4+Math.pow(1-t/144000%1,64)) --- # Tilted camera a.rotate((r&13)/64-.1) --- # Shifting hue a.fillStyle='hsl('+[r*17-v.y+R()*48,(16+R()*48)+'%',v.W*7+32-32*Q(v.u*2-8)*Q(v.v*3-8)]+'%)' --- # And a million more things * Panning at the beginning * synchronization betweem music and visuals * Channels mixing * Ligthing of the object * ... --- ## *Week #4* over Morphing objects spinning around with kick ass glithcy music, a text writer, different camera angles, introduction panning to not give away the effect, a crazy crash cymbal in synch with the morphing, ... --- # Take away ## Plan, *test*, *test*, *test*, go with the flow, keep some time to polish! --- # Thank you ## [That was **MATRAKA**](assets/matraka.webm) By *@p01* and *@4mat_scenemusic* See you tonight at the 1K competition.