Use your mouse to discover what is beneath the mask of fire. Technical description can be found here: http://vimeo.com/35057708
eval("d=128;e=d*d;f=g=h=3;i=1/d;j=Math;k=j.floor;l=a.createImageData(d,d);m=l.data;n=[];for(o=0;o<e;++o)n[o]=j.random()*1.5-.5;c.width=c.height=d;c.innerHTML='<style>*{width:100%;height:100%;margin:0;overflow:hidden;background:#311}</style>';onmousemove=@(q){f=q.clientX/innerWidth;g=q.clientY/innerHeight};setInterval(@(){h+=i;for(o=1;o>=0;o-=i)for(p=1;p>=0;p-=i)r=4*d*(p*d+o),s=o-f,t=p-g,u=j.sqrt(s*s+t*t),v=K(o,p),w=K(o+2,p+h/3),x=K(o+u*1.3+v/2+1,p+w/2+4),y=K(o+v/2+h*3,p+w/2+2),z=K(o+x/3,p+y/2)*.8+.2,A=v*y/2,B=w*x/2,m[r]=C(z+A/4),m[r+1]=C(z/3+B/2+A),m[r+2]=C(A+B),m[r+3]=C(1-5*(.2<u?0:D(1,0,u*5))*(A+B));a.putImageData(l,0,0);a.globalCompositeOperation='destination-over';a.fillStyle='red';a.font=d+'px sans';a.fillText('\u2665',d/5,d*.8)},30);@C($){&255*j.min(j.max($,0),1)}@D(E,F,G){&E+(F-E)*G*G*G*(6*G*G-15*G+10)}@H(I,J){&n[j.abs(I*d+J)%e]}@K(L,M){&N(L*2.5,M*2.5)+N(L*5,M*5)/2}@N(O,P){Q=k(O);R=k(P);&D(D(H(Q,R),H(Q+1,R),O-Q),D(H(Q,R+1),H(Q+1,R+1),O-Q),P-R)}".replace(/@/g,'function ').replace(/&/g,'return '))
ZXZhbCgiZD0xMjg7ZT1kKmQ7Zj1nPWg9MztpPTEvZDtqPU1hdGg7az1qLmZsb29yO2w9YS5jcmVhdGVJbWFnZURhdGEoZCxkKTttPWwuZGF0YTtuPVtdO2ZvcihvPTA7bzxlOysrbyluW29dPWoucmFuZG9tKCkqMS41LS41O2Mud2lkdGg9Yy5oZWlnaHQ9ZDtjLmlubmVySFRNTD0nPHN0eWxlPip7d2lkdGg6MTAwJTtoZWlnaHQ6MTAwJTttYXJnaW46MDtvdmVyZmxvdzpoaWRkZW47YmFja2dyb3VuZDojMzExfTwvc3R5bGU+Jztvbm1vdXNlbW92ZT1AKHEpe2Y9cS5jbGllbnRYL2lubmVyV2lkdGg7Zz1xLmNsaWVudFkvaW5uZXJIZWlnaHR9O3NldEludGVydmFsKEAoKXtoKz1pO2ZvcihvPTE7bz49MDtvLT1pKWZvcihwPTE7cD49MDtwLT1pKXI9NCpkKihwKmQrbykscz1vLWYsdD1wLWcsdT1qLnNxcnQocypzK3QqdCksdj1LKG8scCksdz1LKG8rMixwK2gvMykseD1LKG8rdSoxLjMrdi8yKzEscCt3LzIrNCkseT1LKG8rdi8yK2gqMyxwK3cvMisyKSx6PUsobyt4LzMscCt5LzIpKi44Ky4yLEE9dip5LzIsQj13KngvMixtW3JdPUMoeitBLzQpLG1bcisxXT1DKHovMytCLzIrQSksbVtyKzJdPUMoQStCKSxtW3IrM109QygxLTUqKC4yPHU/MDpEKDEsMCx1KjUpKSooQStCKSk7YS5wdXRJbWFnZURhdGEobCwwLDApO2EuZ2xvYmFsQ29tcG9zaXRlT3BlcmF0aW9uPSdkZXN0aW5hdGlvbi1vdmVyJzthLmZpbGxTdHlsZT0ncmVkJzthLmZvbnQ9ZCsncHggc2Fucyc7YS5maWxsVGV4dCgnXHUyNjY1JyxkLzUsZCouOCl9LDMwKTtAQygkKXsmMjU1KmoubWluKGoubWF4KCQsMCksMSl9QEQoRSxGLEcpeyZFKyhGLUUpKkcqRypHKig2KkcqRy0xNSpHKzEwKX1ASChJLEopeyZuW2ouYWJzKEkqZCtKKSVlXX1ASyhMLE0peyZOKEwqMi41LE0qMi41KStOKEwqNSxNKjUpLzJ9QE4oTyxQKXtRPWsoTyk7Uj1rKFApOyZEKEQoSChRLFIpLEgoUSsxLFIpLE8tUSksRChIKFEsUisxKSxIKFErMSxSKzEpLE8tUSksUC1SKX0iLnJlcGxhY2UoL0AvZywnZnVuY3Rpb24gJykucmVwbGFjZSgvJi9nLCdyZXR1cm4gJykp
var size = 128;
var sizeSquared = size * size;
//take care of canvas size - make it take up the entire page,
//prevent the scrollbar from appearing and set the background colour
c.width = size;
c.height = size;
c.innerHTML= '<style>*{width:100%;height:100%;margin:0;overflow:hidden;background:#311}</style>';
//handle mouse movement
var mouseX = 0;
var mouseY = 0;
onmousemove = function(e) {
mouseX = e.clientX / innerWidth;
mouseY = e.clientY / innerHeight;
};
var image = a.createImageData(size, size);
var data = image.data;
var time = 0;
var step = 1 / size;
//initialise base noise map
var noiseMap = [];
for(var k = 0; k < sizeSquared; ++k)
noiseMap[k] = Math.random() * 1.5 - 0.5;
//the frame function
setInterval(function()
{
time += step;
//calculate pixels
for(var x = 1; x >= 0; x -= step) {
for(var y = 1; y >= 0; y -= step) {
var index = (y * size + x) * size * 4;
//distance from the mouse pointer
var dx = x - mouseX;
var dy = y - mouseY;
var distance = Math.sqrt(dx * dx + dy * dy);
//noise values
var qx = f(x, y);
var qy = f(x + 2, y + time / 3);
var rx = f(x + distance * 1.3 + qx / 2 + 0.7, y + qy / 2 + 4);
var ry = f(x + qx / 2 + 3 * time, y + qy / 2 + 2);
var noise = f(x + rx / 3, y + ry / 2) * 0.75 + 0.15;
var w = qx * ry / 2;
var z = qy * rx / 2;
//calculate colors based on the noise values and distance
data[index + 0] = color(noise + w / 4);
data[index + 1] = color(noise / 3 + z / 2 + w);
data[index + 2] = color(w + z);
data[index + 3] = color(1 - smoothStep(distance) * (z + w) * 5)
}
}
//paint the calculated image, and then paint a red heart under it
a.putImageData(image, 0, 0);
a.globalCompositeOperation = 'destination-over';
a.fillStyle = 'red';
a.font = size + 'px sans';
a.fillText('\u2665', size / 5, size * 0.75)
}, 30);
//just a clamp function
function color(a) {
return 255 * Math.min(Math.max(a, 0), 1);
}
//smooth step ramp function
function smoothStep(x) {
return (x > 0.2) ? 0 : i(1, 0, x * 5);
}
//interpolation function
//using a 5th order polynomial like this makes the resulting
//image smooth even when it's streched over the entire screen
//remember the original image is only 128 pixels wide (size variable)
function i(a, b, t) {
t = t * t * t * (6 * t * t - 15 * t + 10);
return a + (b - a) * t;
}
//noise function, uses base noise map in order to remain a pure function
function n(x, y) {
var i = Math.abs(x * size + y) % sizeSquared;
return noiseMap[i];
}
//fractal noise function, uses 2 octaces, has a lot of fixed parameters baked in
function f(x, y) {
var p1 = p(x * 2.5, y * 2.5);
var p2 = p(x * 5.0, y * 5.0);
return p1 + p2 * 0.5;
}
//perlin noise function reduced for shortest code
function p(x, y) {
var xf = Math.floor(x);
var yf = Math.floor(y);
return i(i(n(xf, yf), n(xf + 1, yf), x - xf), i(n(xf, yf + 1), n(xf + 1, yf + 1), x - xf), y - yf);
}