Source: math/Bezier.js

/**
 *  @class Bezier
 *  @memberof SQR
 *
 *  @description Represents a cubic bezier curve. All paramaters can be either {@link SQR.V3} or {@link SQR.V2}.
 *
 *  @param _p0 start position
 *  @param _c0 first control point
 *  @param _c1 last control point
 *  @param _c1 end position
 *
 */
SQR.Bezier = function(_p0, _c0, _c1, _p1) {

    var that = this;

    /**
     *  @var p0 
     *  @memberof SQR.Bezier.prototype
     *  @descripton The start position, can be either {@link SQR.V3} or {@link SQR.V2}.
     */
    this.p0 = _p0;

    /**
     *  @var c0 
     *  @memberof SQR.Bezier.prototype
     *  @descripton First control point. Can be either {@link SQR.V3} or {@link SQR.V2}.
     */
    this.c0 = _c0;

    /**
     *  @var c1 
     *  @memberof SQR.Bezier.prototype
     *  @descripton Second control point. Can be either {@link SQR.V3} or {@link SQR.V2}.
     */
    this.c1 = _c1;

    /**
     *  @var p1 
     *  @memberof SQR.Bezier.prototype
     *  @descripton End position. Can be either {@link SQR.V3} or {@link SQR.V2}.
     */
    this.p1 = _p1;

    var interpolatedValue, interpolatedVelocity, interpolatedMatrix;

    var pfunc = SQR.Interpolation.bezierPosition;
    var vfunc = SQR.Interpolation.bezierVelocity;

    /**
     *  @method velocityAt 
     *  @memberof SQR.Bezier.prototype
     *  @description Returns the velocity on a curve. 
     *  @param t interpolation value [0-1]
     *  @param v vector to write the value to. If omitted, returns a temporary value, that will be overwritten on next call so do not store this object.
     */
    this.velocityAt = function(t, v) {
        interpolatedVelocity = interpolatedVelocity || this.p0.clone().set();
        v = v || interpolatedVelocity;
        v.x = vfunc(t, this.p0.x, this.c0.x, this.c1.x, this.p1.x);
        v.y = vfunc(t, this.p0.y, this.c0.y, this.c1.y, this.p1.y);

        if(v.z !== null && this.p0.z !== null) {
            v.z = vfunc(t, this.p0.z, this.c0.z, this.c1.z, this.p1.z);
        }

        return v;
    }

    /**
     *  @method valueAt 
     *  @memberof SQR.Bezier.prototype
     *  @description Returns the position on a curve.
     *  @param t interpolation value [0-1]
     *  @param v vector to write the value to. If omitted, returns a temporary value, that will be overwritten on next call so do not store this object.
     */
    this.valueAt = function(t, v) {
        interpolatedValue = interpolatedValue || this.p0.clone().set();
        v = v || interpolatedValue;
        v.x = pfunc(t, this.p0.x, this.c0.x, this.c1.x, this.p1.x);
        v.y = pfunc(t, this.p0.y, this.c0.y, this.c1.y, this.p1.y);

        if(v.z !== null && this.p0.z !== null) {
            v.z = pfunc(t, this.p0.z, this.c0.z, this.c1.z, this.p1.z);
        }
        
        return v;
    }

    /** 
     *  @method matrixAt 
     *  @memberof SQR.Bezier.prototype
     *  @description Returns the transformation matrix that can be used to align an object to the curve at a given point.
     *  Not tested in 2D but shoud work fine.
     *  @param t interpolation value [0-1]
     *  @param m {@link SQR.Matrix44} to write the matrix to. If omitted, returns a temporary value, that will be overwritten on next call so do not store this object.
     */
    this.matrixAt = function(t, m) {
        interpolatedMatrix = interpolatedMatrix || new SQR.Matrix44();
        m = m || interpolatedMatrix;
        m.identity();

        var va = that.valueAt(t);
        var vc = that.velocityAt(t).norm();
        var vl = SQR.V3.__tv1.set().cross(vc, SQR.V3.up);//.norm();
        var vn = SQR.V3.__tv2.set().cross(vc, vl);//.norm()

        m.data[0] = vl.x, m.data[4] = vn.x, m.data[8] = vc.x;
        m.data[1] = vl.y, m.data[5] = vn.y, m.data[9] = vc.y;
        m.data[2] = vl.z, m.data[6] = vn.z, m.data[10] = vc.z;
        m.setTranslation(va.x, va.y, va.z);

        return m;
    }
}