C=document.body.children[0];C.innerHTML='<style>*{margin:0;width:100%;height:100%;overflow:hidden;background:#000}</style>';C.width=w=(D=40)*(N=10);h=C.height=w*innerHeight/innerWidth|0;M=Math;F=M.floor;R=M.random;W="#fff";B="#000";J="fillStyle";b=15;I=60;G=-6*(E=-(x=w/2));for($ in g=C.getContext("2d"))g[$[S=0]+($[6]||'')]=g[$];H=[];for(i=0;i<4E4;i+=4){H[i+1]=(H[i]=F(R()*N)*D)+D;H[i+3]=(H[i+2]=H[i]+(F(R()*8)+2)*D)+D}y=z=-h/2;k=[];v=2;setInterval('with(g){globalCompositeOperation="lighter";shadowBlur=7;font="99pt S";ce(0,0,w,h);i=4;do{$=i*I/4-z;shadowColor="hsl("+i+",100%,50%)";fc(E,$,H[i]-E,7);fc(H[i+1],$,H[i+2]-H[i+1],7);fc(H[i+3],$,G-H[i+3],7);i+=4}while($<h)x+=S=k[37]?-11:k[39]?11:S*.85;x=x<b?b:x>w-b?w-b:x;y-z>h?y=z+h:0;ba();a(x,y-z,b,0,2*M.PI,1);ca();g[J]=W;f();g[J]=B;z+=v;V=(v+=v<6?1E-3:0)+8;if((y+b)%I>=I-V){L=(F(y/I)+1)*4;y=L/4*I-b-1;y+=x<H[L]+7||x>H[L+1]-7&&x<H[L+2]+7||x>H[L+3]-7?0:V}else{y+=V}if(y+b<z){g[J]=W;fx(F(y),35,h/2);g[J]=B}}',33);onkeydown=onkeyup=function(e){k[e.keyCode]=e.type[5]?1:0}
C=document.body.children[0];
// Reset the page layout
C.innerHTML='<style>*{margin:0; width:100%; height:100%; overflow:hidden; background:#000}</style>';
w = C.width = (holeSize = 40) * (nbSlots = 10);
h = C.height = w * innerHeight / innerWidth | 0;
white = "#fff";
black = "#000";
ballRadius = 15;
interval = 1.5 * holeSize;
left = -w/2; right = 3*w;
g = C.getContext("2d");
with (g) {
// "lighter" alpha blend mode, which adds overlapping colors up to #FFFFFF white
// The 'glow' effect is achieved by rendering blurred shadows over black rectangles
globalCompositeOperation = "lighter";
shadowBlur = 7;
font = "99pt S";
fillStyle = "#000";
holes = [];
// Holes are stored in an array. There are two holes per line,
// holes[i] is the left edge of the first hole, holes[i+1] its right edge
// and holes[i+2] and holes[i+3] hold the second hole.
//
// The second hole is always to the right of the first hole,
// to avoid tests during the drawing phase.
for (i=0; i<2E4; i+=4) {
holes[i+1] = (holes[i] = Math.floor(Math.random()*nbSlots) * holeSize) + holeSize;
holes[i+3] = (holes[i+2] = holes[i] + (Math.floor(Math.random()*8) + 2) * holeSize) + holeSize;
}
yBall = yView = - h/2; xBall = w/2; ballSpeed=0; keys=[]; viewSpeed = 2.8;
yRow =0; i=4;
setInterval(function () {
// Clear the screen
clearRect(0,0,w,h);
i=4;
do {
yRow = i*interval/4 - yView;
shadowColor = "hsl("+ i +",100%,50%)";
fillRect(left, yRow, holes[i] - left, 7);
fillRect(holes[i+1], yRow, holes[i+2] - holes[i+1], 7);
fillRect(holes[i+3], yRow, right - holes[i+3], 7);
i+=4;
} while (yRow < h)
// Ease out the speed of the ball when it stops, to give it a more natural movement
xBall += ballSpeed = keys[37] ? - 11 : keys[39] ? 11 : ballSpeed * .85;
// Check if the ball is within the canvas limits
xBall = xBall < ballRadius ? ballRadius : xBall > w - ballRadius ? w - ballRadius : xBall;
yBall - yView > h ? yBall = yView + h : 0;
// Draw the ball using a 2*PI arc. No fillCircle unfortunately...
beginPath();
arc(xBall,yBall-yView, ballRadius, 0, 2*Math.PI,1);
closePath();
fillStyle = white;
fill();
fillStyle = black;
yView += viewSpeed;
ballVerticalSpeed = (viewSpeed += viewSpeed < 6 ? 1E-3 : 0) + 8;
// Test whether the ball has hit a line
if ((yBall+ballRadius) % interval >= interval - ballVerticalSpeed) {
lineBelowBall = (Math.floor(yBall / interval) + 1) * 4;
yBall = lineBelowBall / 4 * interval - ballRadius - 1;
yBall += xBall < holes[lineBelowBall] + 7 || xBall > holes[lineBelowBall+1] - 7 && xBall < holes[lineBelowBall+2] + 7 || xBall > holes[lineBelowBall+3] - 7 ? 0 : ballVerticalSpeed
} else { yBall += ballVerticalSpeed }
if (yBall+ballRadius < yView) {fillStyle = white; fillText(yBall, 35, h/2); fillStyle = black;}
}, 33);
}
// Maintain a lookup array with the status of all the keys, to improve responsiveness
onkeydown = onkeyup = function (e) {
keys[e.keyCode] = e.type[5] ? 1 : 0;
}