# 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.