js1K Entry – Grass

TwitterGoogle+FacebookShare

This application requires a (fast) HTML5 compliant browser.
Visit my jsdo.it account for the original sourcecode.
You can find it at js1k here: Grass.
and updated here: Grass.

20100807 Updated: now starry heaven moves, and in only 1002 bytes.
20100810 Updated: added more control on grass creation. Stars move in different motion speed. 1007 bytes.
20100816 Updated: added a swarm of fireflies (tried to). I thought black grass looked better than green one. Finally, I decided it did not. 1023 bytes.

Some of the optimizations i’ve used are:

1.- Redefine math functions. Instead of using Math.sin, Math.random, Math.floor, I’ve used the following;
m=Math;
c=m.cos;
s=m.sin;
_=m.floor;
$=m.random
$$=Math.PI
thus, you can use more compact calls, so that something like var x= Math.floor(Math.random()*Math.sin(timer*.00005)) can be expressed as: var x=_($()*s(timer*.00005));. And since I’ve been using these functions extensively, I can obtain big bytes savings.

2.- Use closure compiler to give the source code a big crunch as well as a neat obfuscation. However, closure compiler tries to write numbers in a more human readable manner than needed. In example, it writes 0.5 and 3.0E4, while just .5 and 3E4 are needed. You can save a few more scarce bytes with this trick.

3.- Optimized declaration of function() and removed them at all, by issuing a change from
setInterval( my_function, 30 ) to setInterval(function(){…}, 30);

4.- I’m using a gradient in the background with four components. Color components are:
[“#000000″,”#002f7f”,”#002850″,”#001f3f”], so I changed them to [“0000″,”2f7f”,”2850″,”1f3f”] and appended ‘#00′ in the gradient loop setup.

5.- Stars.
5.1 Changed the stars set up loop from:
for(i=0; i<1500; i++ ) {
stars[i*2 ]= Math.random()*width;
stars[i*2+1]= Math.random()*height;
}

to

for(i=3E3;i–;) {
stars[i]= $()*width;
}

in fact, I was not bothered by the fact that some stars got out of the screen.

5.2 Drawing stars:
instead of
for( var i=0; i<1500; i++ ) {
context.fillRect(stars[i*2], stars[i*2+1], 1, 1);
}

I use

for(i=0;i<3E3;) {
context.fillRect(k[i++],k[i++],1,1);
}

6.- Optimize numbers.
change numbers such at 3000 to 3E4, and .0005 to 5E-4, and thus save one more byte by number declaration.

7.- Changed loops with array.length limit to the exact numbers of elements. In stars, changed for( var i=0; i<3E3; i++). Another small saving.

8.- If using colors, you could use color names instead of rgb(r,g,b) or ‘#rrggbb’ declarations. I.E. ‘white’ is two bytes shorter than ‘#ffffff’.

9.- Access context2D functions via the associative feature. I’m using bezierCurveTo as well as fillRect and fillStyle functions in more than one place. So I changed ctx.bezierCurveTo(…) to the following:
B=’bezierCurveTo'; ctx[B](…) which saved some bytes.

10.- I also had to prune some features, like background transition of gradient colors :].

There’re plenty more optimizations which are over my knowledge.

And here it is the obfuscated script itself:

M=Math;_=M.floor;$=M.random;P=M.PI;var d,j,k,T=1E3,Y=600,U=250;this.addEventListener("load",function(){var f=document.body.children[0];a=f.getContext("2d");f.width=T;f.height=Y;d=a.createLinearGradient(0,0,0,Y);x=["0000","2f7f","2850","1f3f"];for(i=0;i<4;)d.addColorStop(i*.33,"#00"+x[i++]);j=[];for(i=U;i--;){f=$()*T/2,l=Y-f/2;l=[$()*T,Y,l];j.push([f,$()*.3,$()*($()<.5?.7:-.7),l,"rgb(0,"+_($()*32)+",0)"])}k=[];for(i=3E3;i--;)k.push(_($()*T));setInterval(function(){F="fillStyle";a[F]=d;K="fillRect";a[K](0,0,T,Y);var b=(new Date).getTime();a[F]="gray";for(i=80;i<3E3;){k[i]+=.1*(i%3+1);k[i]%=T;a[K](k[i++],k[i++],1.5,1.5)}s=M.sin;c=M.cos;Q=b*3E-4;z=s(Q);x=c(Q);i=0;for(a[F]="yellow";i<80;){b=P*2*z+i*P/50;var e=50*x;a[K](U+.5*k[i++]+150*x+e*c(b),U+.5*k[i++]+20*z+e*s(b),3,3)}i=U;for(B="beginPath";--i;){h=j[i];e=h[2]+P/2+z*h[1]*x;g=h[3];b=g[0]+3+h[0]*c(e);e=g[1]-h[0]*s(e);a[B]();a.moveTo(g[0],g[1]);R="bezierCurveTo";a[R](g[0],g[1],g[0]-2,g[2],b,e);a[R](b,e,g[0]-2,g[2],g[0]+6,g[1]);a[F]=h[4];a.fill()}},30)}(),false);

It started to be a 2048 bytes class-based readable javascript file, and after some feature pruning, it turned up into what you see. a pile of unuseful code.

  • Joel

    awesome!

  • kUKEN

    Amazing!! Truly amazing!

  • mekanik proje

    thanks for sharing

  • Pingback: mobi.fm | JS Grass | HyperAndroid()

  • John D’Orazio

    you can also Math floor using “0|” or using “~~”. For example, “Math.floor(Math.random()*100))” becomes “0|Math.random()*100″ or “~~Math.random()*100″

  • Mehmet Fatih

    Hi, how can i remove background ? i want make other background. Thanks

  • anubiran

    Is it possible to change it to a wheat field? if so how would i start? I doubt its possible to use a wheat svg or anything similar or?

  • siddik assegaf

    Thanks Master….
    Awesommee