 
          
        
        simulation of collisions of 700 balls with conservation of momentum. The radius of the ball is it's mass.
g=window,u=Math,v=u.sqrt,h=u.random,f=document.getElementById("c"),i=f.getContext("2d"),j=g.innerWidth,k=g.innerHeight,w=[],C=(new Date).getTime();f.width=j;f.height=k;i.fillStyle="rgb(122,0,25)";for(n=0;n<700;n++){f=-0.075+2*h()*0.075;g=v(0.005625-f*f);w[n]={a:1+h()*10,d:h()*j,e:h()*k,b:f,c:-g+2*h()*g}}window.setInterval(function(){x=(new Date).getTime()-C;C+=x;i.clearRect(0,0,j,k);for(n=0;n<700;n++){y=x;a=w[n];a.d+=a.b*y;a.e+=a.c*y;if(a.d<a.a||a.d>j-a.a){a.b=-a.b;a.d=a.d<a.a?a.a:j-a.a}if(a.e<a.a||a.e>k-a.a){a.c=-a.c;a.e=a.e<a.a?a.a:k-a.a}for(m=n+1;m<700;m++){b=w[m];D=a.a+b.a;p=b.d-a.d;q=b.e-a.e;E=p*p+q*q;r=v(E);if(r<D){c=p/r;d=q/r;l=a.b*c+a.c*d;z=a.c*c-a.b*d;s=b.b*c+b.c*d;A=b.c*c-b.b*d;e=b.a/a.a;o=(l+e*s)/(1+e);t=o-v(o*o-((1-e)*l+2*e*s)*l/(1+e));B=l/e+s-t/e;a.b=t*c-z*d;a.c=z*c+t*d;b.b=B*c-A*d;b.c=A*c+B*d}}i.beginPath();i.arc(a.d,a.e,a.a,0,2*u.PI,true);i.fill()}},33)Zz13aW5kb3csdT1NYXRoLHY9dS5zcXJ0LGg9dS5yYW5kb20sZj1kb2N1bWVudC5nZXRFbGVtZW50QnlJZCgiYyIpLGk9Zi5nZXRDb250ZXh0KCIyZCIpLGo9Zy5pbm5lcldpZHRoLGs9Zy5pbm5lckhlaWdodCx3PVtdLEM9KG5ldyBEYXRlKS5nZXRUaW1lKCk7Zi53aWR0aD1qO2YuaGVpZ2h0PWs7aS5maWxsU3R5bGU9InJnYigxMjIsMCwyNSkiO2ZvcihuPTA7bjw3MDA7bisrKXtmPS0wLjA3NSsyKmgoKSowLjA3NTtnPXYoMC4wMDU2MjUtZipmKTt3W25dPXthOjEraCgpKjEwLGQ6aCgpKmosZTpoKCkqayxiOmYsYzotZysyKmgoKSpnfX13aW5kb3cuc2V0SW50ZXJ2YWwoZnVuY3Rpb24oKXt4PShuZXcgRGF0ZSkuZ2V0VGltZSgpLUM7Qys9eDtpLmNsZWFyUmVjdCgwLDAsaixrKTtmb3Iobj0wO248NzAwO24rKyl7eT14O2E9d1tuXTthLmQrPWEuYip5O2EuZSs9YS5jKnk7aWYoYS5kPGEuYXx8YS5kPmotYS5hKXthLmI9LWEuYjthLmQ9YS5kPGEuYT9hLmE6ai1hLmF9aWYoYS5lPGEuYXx8YS5lPmstYS5hKXthLmM9LWEuYzthLmU9YS5lPGEuYT9hLmE6ay1hLmF9Zm9yKG09bisxO208NzAwO20rKyl7Yj13W21dO0Q9YS5hK2IuYTtwPWIuZC1hLmQ7cT1iLmUtYS5lO0U9cCpwK3EqcTtyPXYoRSk7aWYocjxEKXtjPXAvcjtkPXEvcjtsPWEuYipjK2EuYypkO3o9YS5jKmMtYS5iKmQ7cz1iLmIqYytiLmMqZDtBPWIuYypjLWIuYipkO2U9Yi5hL2EuYTtvPShsK2UqcykvKDErZSk7dD1vLXYobypvLSgoMS1lKSpsKzIqZSpzKSpsLygxK2UpKTtCPWwvZStzLXQvZTthLmI9dCpjLXoqZDthLmM9eipjK3QqZDtiLmI9QipjLUEqZDtiLmM9QSpjK0IqZH19aS5iZWdpblBhdGgoKTtpLmFyYyhhLmQsYS5lLGEuYSwwLDIqdS5QSSx0cnVlKTtpLmZpbGwoKX19LDMzKQ==(function() {                                            // Removed after compression
    var win             = window,
        math            = Math,                            // My shortcut globals:
        s               = math.sqrt,
        r               = math.random,
        c               = document.getElementById("c"),
        cx              = c.getContext("2d"),
        w               = win.innerWidth,
        h               = win.innerHeight,
        MAX_PARTICLES   = 700,                            // Application globals
        MAX_VELOCITY    = 75/1000,                        //(px/ms)
        states          = [],
        time            = new Date().getTime(),
        vv,vx,dt,tt,V,p1,                                // For compressor tool
        p2,R,dx,dy,dd,d,dvx,dvy,dvdv,cos1,
        sin1,dv_para,t,cos2,sin2,
        v1x_,v1y_,v2x_,v2y_,v1x,v1y,v2x,v2y,
        mr,v1x_prime,v2x_prime;
    
    //////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    // Initialization:                                                                                                //
    //////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    c.width         = w;
    c.height        = h;
    cx.fillStyle    = "rgb(122,0,25)";
    for(n=0; n<MAX_PARTICLES; n++) {
        vx        = -MAX_VELOCITY + 2*r()*MAX_VELOCITY;
        vv        = s(MAX_VELOCITY*MAX_VELOCITY - vx*vx);
        states[n] = {
            r:    1+r()*10,
            px:   r()*w,
            py:   r()*h,
            vx:   vx,
            vy:   -vv+2*r()*vv
        };
    }
    //////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    // The main loop:                                                                                                //
    //////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    window.setInterval(function() {
        dt      = new Date().getTime() - time;
        time   += dt;                            // Ha-ha! #Desperation [time + dt = time + new time - time = new time] 
        
        cx.clearRect(0, 0, w, h);
        
        for(n=0; n<MAX_PARTICLES; n++) {
            tt       = dt;
            p1       = states[n];
            p1.px   += p1.vx*tt;
            p1.py   += p1.vy*tt;
            // Check boundaries first
            if(p1.px<p1.r||p1.px>w-p1.r){p1.vx=-p1.vx;p1.px=p1.px<p1.r?p1.r:w-p1.r;}
            if(p1.py<p1.r||p1.py>h-p1.r){p1.vy=-p1.vy;p1.py=p1.py<p1.r?p1.r:h-p1.r;}
            
            // Could it hit another particle?
            for(m=n+1; m<MAX_PARTICLES; m++) {
                p2           = states[m];
                R            = p1.r+p2.r;
                dx           = p2.px-p1.px;
                dy           = p2.py-p1.py;
                dd           = dx*dx+dy*dy;
                d            = s(dd);
                
                // Removed a lot of unnecessary checks here to make this smaller but less accurate.
                if(d<R) {
                    dvx          = p2.vx-p1.vx;
                    dvy          = p2.vy-p1.vy;
                    dvdv         = dvx*dvx+dvy*dvy;
                    cos1         = dx/d;
                    sin1         = dy/d;
                    dv_para      = dvx*cos1+dvy*sin1;
                    v1x          = p1.vx*cos1+p1.vy*sin1;
                    v1y          = p1.vy*cos1-p1.vx*sin1;
                    v2x          = p2.vx*cos1+p2.vy*sin1;
                    v2y          = p2.vy*cos1-p2.vx*sin1;
                    mr           = p2.r/p1.r;
                    V            = (v1x+mr*v2x)/(1+mr);
                    v1x_prime    = V-s(V*V-((1-mr)*v1x+2*mr*v2x)*v1x/(1+mr));
                    v2x_prime    = v1x/mr+v2x-v1x_prime/mr;
                    p1.vx        = v1x_prime*cos1-v1y*sin1;
                    p1.vy        = v1y*cos1+v1x_prime*sin1;
                
                    p2.vx        = v2x_prime*cos1-v2y*sin1;
                    p2.vy        = v2y*cos1+v2x_prime*sin1;
                }
            }
            
            // New all time low: draw inside collision method! >ugh<
            cx.beginPath();
            cx.arc(p1.px, p1.py, p1.r, 0, 2*math.PI, true);
            cx.fill();
        }
    }, 33);
})();