Instructions: Move the mouse. Catch the hearts. Reload if the hearts are distorted. Full screen recommended.
c.innerHTML='<style>*{width:100%;height:100%;margin:0;overflow:hidden}</style>';A=Math.abs,R=Math.random;s=.06;h=256;W=innerWidth,H=innerHeight;w=h*W/H;c.width=w*2,c.height=h*2;o=[];m='MISS0HIT0NICE0CATCHY0GOOD0LOVELY0GREAT0HEARTY0AWESOME0SUPER0BRILLIANT0PERFECT'.split(L=M=p=0);J=K=.5;onmousemove=function(e){J=e.clientX/W,K=e.clientY/H};function T(x,y,z){return{x:(x*99+L)/z+w,y:(y*99+M)/z+h}}with(a){strokeStyle='#F41',lineJoin='round',font='bold 7em serif',textAlign='center',textBaseline='middle';setInterval(function(){i=30;L-=J*60-i,M-=K*60-i;if(!o[0])for(s/=.8;i--;)o.push({x:R()*18-9,y:R()*18-9,z:i/3});fillStyle='rgba(99,9,9,.2)',fillRect(0,0,w*2,h*2);for(i in o){i=o[i],z=i.z+=.003;e=T(i.x+1,i.y-1,z),f=T(i.x,i.y+2,z),g=T(i.x-1,i.y-1,z);globalAlpha=1-z/13,beginPath(lineWidth=(j=150/z)/2),moveTo(f.x,f.y),arc(g.x,g.y,j,2.4,5),stroke(fill(closePath(arc(e.x,e.y,j,4,.8))))}globalAlpha=1;i=o[0];if((i.z-=s)<0)fillStyle='#FFF',fillText((m[p=A(i.x*99+L)>150||A(i.y*99+M)>150?0:p+1]||m[--p])+'!',w,h),o=o.slice(1)},33)}
Yy5pbm5lckhUTUw9JzxzdHlsZT4qe3dpZHRoOjEwMCU7aGVpZ2h0OjEwMCU7bWFyZ2luOjA7b3ZlcmZsb3c6aGlkZGVufTwvc3R5bGU+JztBPU1hdGguYWJzLFI9TWF0aC5yYW5kb207cz0uMDY7aD0yNTY7Vz1pbm5lcldpZHRoLEg9aW5uZXJIZWlnaHQ7dz1oKlcvSDtjLndpZHRoPXcqMixjLmhlaWdodD1oKjI7bz1bXTttPSdNSVNTMEhJVDBOSUNFMENBVENIWTBHT09EMExPVkVMWTBHUkVBVDBIRUFSVFkwQVdFU09NRTBTVVBFUjBCUklMTElBTlQwUEVSRkVDVCcuc3BsaXQoTD1NPXA9MCk7Sj1LPS41O29ubW91c2Vtb3ZlPWZ1bmN0aW9uKGUpe0o9ZS5jbGllbnRYL1csSz1lLmNsaWVudFkvSH07ZnVuY3Rpb24gVCh4LHkseil7cmV0dXJue3g6KHgqOTkrTCkveit3LHk6KHkqOTkrTSkveitofX13aXRoKGEpe3N0cm9rZVN0eWxlPScjRjQxJyxsaW5lSm9pbj0ncm91bmQnLGZvbnQ9J2JvbGQgN2VtIHNlcmlmJyx0ZXh0QWxpZ249J2NlbnRlcicsdGV4dEJhc2VsaW5lPSdtaWRkbGUnO3NldEludGVydmFsKGZ1bmN0aW9uKCl7aT0zMDtMLT1KKjYwLWksTS09Syo2MC1pO2lmKCFvWzBdKWZvcihzLz0uODtpLS07KW8ucHVzaCh7eDpSKCkqMTgtOSx5OlIoKSoxOC05LHo6aS8zfSk7ZmlsbFN0eWxlPSdyZ2JhKDk5LDksOSwuMiknLGZpbGxSZWN0KDAsMCx3KjIsaCoyKTtmb3IoaSBpbiBvKXtpPW9baV0sej1pLnorPS4wMDM7ZT1UKGkueCsxLGkueS0xLHopLGY9VChpLngsaS55KzIseiksZz1UKGkueC0xLGkueS0xLHopO2dsb2JhbEFscGhhPTEtei8xMyxiZWdpblBhdGgobGluZVdpZHRoPShqPTE1MC96KS8yKSxtb3ZlVG8oZi54LGYueSksYXJjKGcueCxnLnksaiwyLjQsNSksc3Ryb2tlKGZpbGwoY2xvc2VQYXRoKGFyYyhlLngsZS55LGosNCwuOCkpKSl9Z2xvYmFsQWxwaGE9MTtpPW9bMF07aWYoKGkuei09cyk8MClmaWxsU3R5bGU9JyNGRkYnLGZpbGxUZXh0KChtW3A9QShpLngqOTkrTCk+MTUwfHxBKGkueSo5OStNKT4xNTA/MDpwKzFdfHxtWy0tcF0pKychJyx3LGgpLG89by5zbGljZSgxKX0sMzMpfQ==
// Maximize canvas. This line is borrowed from "Particle carriage" by @p01, see http://js1k.com/2011-dysentery/demo/993
c.innerHTML = '<style>*{width:100%;height:100%;margin:0;overflow:hidden}</style>';
// Create shortcuts for some static functions.
A = Math.abs, R = Math.random;
// Initialize speed. How fast do the hearts travel to the camera.
s = .06;
// The canvas has a fixed height of 512 pixels, stretched to fill the window height.
h = 256;
// The width of the canvas is calculated once when the page loads, hopefully nobody resizes the window to much.
W = innerWidth, H = innerHeight;
w = h * W / H;
// Set pixel dimensions of the canvas.
c.width = w * 2, c.height = h * 2;
// Initialize the array of heart objects.
o = [];
// Initialize the array of messages, curent camera position and current points.
m = 'MISS0HIT0NICE0CATCHY0GOOD0LOVELY0GREAT0HEARTY0AWESOME0SUPER0BRILLIANT0PERFECT'.split(L = M = p = 0);
// Initialize relative mouse position on the canvas, ranging from 0 to 1.
J = K = .5;
onmousemove = function(e)
{
// Store mouse position relative to the window, ranging from 0 to 1.
J = e.clientX / W, K = e.clientY / H
};
// Helper function to translate all 3D coordinates to 2D.
function T(x, y, z)
{
// Instead of moving all objects around we are moving the camera only.
return { x: (x * 99 + L) / z + w, y: (y * 99 + M) / z + h }
}
with (a)
{
strokeStyle = '#F41',
lineJoin = 'round',
// For whatever reason Firefox does not default to "sans-serif" but to "serif".
font = 'bold 7em serif',
textAlign = 'center',
textBaseline = 'middle';
// Replacing the function with a string does not work because of the with.
setInterval(function()
{
// Number of hearts.
i = 30;
// The camera position always changes depending on the mouse position.
L -= J * 60 - i, M -= K * 60 - i;
// If the array of heart objects is empty, increase speed and initialize array.
if (!o[0])
for (s /= .8; i--; )
o.push({ x: R() * 18 - 9, y: R() * 18 - 9, z: i / 3 });
// Clear the canvas with a transparent color, this creates the motion blur effect.
fillStyle = 'rgba(99,9,9,.2)',
fillRect(0, 0, w * 2, h * 2);
for (i in o)
{
i = o[i], z = i.z += .003;
// Translate all 3D coordinates to 2D.
e = T(i.x + 1, i.y - 1, z),
f = T(i.x , i.y + 2, z),
g = T(i.x - 1, i.y - 1, z);
// Hearts in the background are transparent.
globalAlpha = 1 - z / 11,
// beginPath is required in Opera, else the performance is very bad.
beginPath(lineWidth = (j = 150 / z) / 2),
moveTo(f.x, f.y),
arc(g.x, g.y, j, 2.4, 5),
// Abusing some empty function calls, executed from the inner to the outer bracket.
stroke(fill(closePath(arc(e.x, e.y, j, 4, .8))))
}
// Required for fillText and fillRect.
globalAlpha = 1;
i = o[0];
// Move the current heart and check if it hit the camera.
if ((i.z -= s) < 0)
fillStyle = '#FFF',
// Increase the points, if there are enough messages, and display the message.
fillText((m[p = A(i.x * 99 + L) > 150 || A(i.y * 99 + M) > 150 ? 0 : p + 1] || m[--p]) + '!', w, h),
// Delete the current heart object.
o = o.slice(1)
}, 33)
}