docs: function(bodyA, bodyB, normal, point, mtrans, contact){
  
              var fixedA = bodyA.treatment === 'static' || bodyA.treatment === 'kinematic'
                  ,fixedB = bodyB.treatment === 'static' || bodyB.treatment === 'kinematic'
                  ,scratch = Physics.scratchpad()
                  // minimum transit vector for each body
                  ,mtv = scratch.vector().clone( mtrans )
                  ;
  
              // do nothing if both are fixed
              if ( fixedA && fixedB ){
                  scratch.done();
                  return;
              }
  
              // inverse masses and moments of inertia.
              // give fixed bodies infinite mass and moi
              var invMoiA = fixedA ? 0 : 1 / bodyA.moi
                  ,invMoiB = fixedB ? 0 : 1 / bodyB.moi
                  ,invMassA = fixedA ? 0 : 1 / bodyA.mass
                  ,invMassB = fixedB ? 0 : 1 / bodyB.mass
                  // coefficient of restitution between bodies
                  ,cor = bodyA.restitution * bodyB.restitution
                  // coefficient of friction between bodies
                  ,cof = bodyA.cof * bodyB.cof
                  // normal vector
                  ,n = scratch.vector().clone( normal )
                  // vector perpendicular to n
                  ,perp = scratch.vector().clone( n ).perp()
                  ,tmp = scratch.vector()
                  // collision point from A's center
                  ,rA = scratch.vector().clone( point )
                  // collision point from B's center
                  ,rB = scratch.vector().clone( point )
                      .vadd( bodyA.state.pos )
                      .vsub( bodyB.state.pos )
                  ,angVelA = bodyA.state.angular.vel
                  ,angVelB = bodyB.state.angular.vel
                  // relative velocity towards B at collision point
                  ,vAB = scratch.vector().clone( bodyB.state.vel )
                          .vadd( tmp.clone(rB).perp().mult( angVelB ) )
                          .vsub( bodyA.state.vel )
                          .vsub( tmp.clone(rA).perp().mult( angVelA ) )
                  // break up components along normal and perp-normal directions
                  ,rAproj = rA.proj( n )
                  ,rAreg = rA.proj( perp )
                  ,rBproj = rB.proj( n )
                  ,rBreg = rB.proj( perp )
                  ,vproj = vAB.proj( n ) // projection of vAB along n
                  ,vreg = vAB.proj( perp ) // rejection of vAB along n (perp of proj)
                  ,impulse
                  ,sign
                  ,max
                  ,ratio
                  ,inContact = contact
                  ;
  
              if ( contact ){
  
                  if ( fixedA ){
  
                      clampMTV( bodyB._mtvTotal, mtv, tmp );
                      bodyB._mtvTotal.vadd( tmp );
  
                  } else if ( fixedB ){
  
                      clampMTV( bodyA._mtvTotal, mtv.negate(), tmp );
                      bodyA._mtvTotal.vadd( tmp );
                      mtv.negate();
  
                  } else {
  
                      ratio = 0.5; //bodyA.mass / ( bodyA.mass + bodyB.mass );
                      mtv.mult( ratio );
                      clampMTV( bodyB._mtvTotal, mtv, tmp );
                      bodyB._mtvTotal.vadd( tmp );
  
                      mtv.clone( mtrans ).mult( ratio - 1 );
                      clampMTV( bodyA._mtvTotal, mtv, tmp );
                      bodyA._mtvTotal.vadd( tmp );
  
                  }
              }
  
              // if moving away from each other... don't bother.
              if (vproj >= 0){
                  scratch.done();
                  return;
              }
  
              invMoiA = invMoiA === Infinity ? 0 : invMoiA;
              invMoiB = invMoiB === Infinity ? 0 : invMoiB;
  
              impulse =  - ((1 + cor) * vproj) / ( invMassA + invMassB + (invMoiA * rAreg * rAreg) + (invMoiB * rBreg * rBreg) );
              // vproj += impulse * ( invMass + (invMoi * rreg * rreg) );
              // angVel -= impulse * rreg * invMoi;
  
  
              if ( fixedA ){
  
                  // apply impulse
                  bodyB.state.vel.vadd( n.mult( impulse * invMassB ) );
                  bodyB.state.angular.vel -= impulse * invMoiB * rBreg;
  
              } else if ( fixedB ){
  
                  // apply impulse
                  bodyA.state.vel.vsub( n.mult( impulse * invMassA ) );
                  bodyA.state.angular.vel += impulse * invMoiA * rAreg;
  
              } else {
  
                  // apply impulse
                  bodyB.state.vel.vadd( n.mult( impulse * invMassB ) );
                  bodyB.state.angular.vel -= impulse * invMoiB * rBreg;
                  bodyA.state.vel.vsub( n.mult( invMassA * bodyB.mass ) );
                  bodyA.state.angular.vel += impulse * invMoiA * rAreg;
              }
  
              // inContact = (impulse < 0.004);
  
              // if we have friction and a relative velocity perpendicular to the normal
              if ( cof && vreg ){
  
  
                  // TODO: here, we could first assume static friction applies
                  // and that the tangential relative velocity is zero.
                  // Then we could calculate the impulse and check if the
                  // tangential impulse is less than that allowed by static
                  // friction. If not, _then_ apply kinetic friction.
  
                  // instead we're just applying kinetic friction and making
                  // sure the impulse we apply is less than the maximum
                  // allowed amount
  
                  // maximum impulse allowed by kinetic friction
                  max = Math.abs(vreg) / ( invMassA + invMassB + (invMoiA * rAproj * rAproj) + (invMoiB * rBproj * rBproj) );
                  // the sign of vreg ( plus or minus 1 )
                  sign = vreg < 0 ? -1 : 1;
  
                  // get impulse due to friction
                  impulse = cof * Math.abs( impulse );
                  // constrain the impulse within the "friction cone" ( max < mu * impulse)
                  impulse = Math.min( impulse, max );
                  impulse *= sign;
  
                  if ( fixedA ){
  
                      // apply frictional impulse
                      bodyB.state.vel.vsub( perp.mult( impulse * invMassB ) );
                      bodyB.state.angular.vel -= impulse * invMoiB * rBproj;
  
                  } else if ( fixedB ){
  
                      // apply frictional impulse
                      bodyA.state.vel.vadd( perp.mult( impulse * invMassA ) );
                      bodyA.state.angular.vel += impulse * invMoiA * rAproj;
  
                  } else {
  
                      // apply frictional impulse
                      bodyB.state.vel.vsub( perp.mult( impulse * invMassB ) );
                      bodyB.state.angular.vel -= impulse * invMoiB * rBproj;
                      bodyA.state.vel.vadd( perp.mult( invMassA * bodyB.mass ) );
                      bodyA.state.angular.vel += impulse * invMoiA * rAproj;
                  }
              }
  
              // wake up bodies if necessary
              if ( bodyA.sleep() ){
                  bodyA.sleepCheck();
              }
              if ( bodyB.sleep() ){
                  bodyB.sleepCheck();
              }
  
              scratch.done();
          }