anchor.diff:      });
       canvas.onMouseOut.listen((MouseEvent e) {
         if (_startDrag != null) {
  -        Matrix4 rotation = dragRotation(_startDrag, e.client, planeDistance);
  +        Multivector rotation =
  +            dragRotation(_startDrag, e.client, planeDistance);
           for (int i = 0; i < ROTATION_POWER; i++) {
  -          _rotation = _rotation.multiply(rotation);
  +          _rotation = rotation * _rotation;
           }
   
           _startDrag = null;
  
positive.code:     });
  
      canvas.onTouchStart.listen((TouchEvent e) {
        _startDrag = e.touches.first.client;      
        e.preventDefault();
      });
      canvas.onTouchMove.listen((TouchEvent e) {
        if (_startDrag != null) {
          Matrix4 rotation = dragRotation(_startDrag, e.touches.first.client, planeDistance);
          for (int i = 0; i < ROTATION_POWER; i++) {
            _rotation = _rotation.multiply(rotation);
          }
  
          _startDrag = e.touches.first.client;
  
negative.code:   Vector3 _center;
    double _scale;
    Point _startDrag;
    Multivector _rotation;
    static const ROTATION_POWER = 3;
  
    Vector3 rotateVector(Vector3 a, Vector3 b, Vector3 x) {
      return x.reflect(a.normalized()).reflect((a + b).normalized());
    }
    Multivector makeRotation(Vector3 a, Vector3 b) {
      /*Matrix3 rot;
      rot = new Matrix3.columns(rotateVector(a, b, new Vector3(1.0, 0.0, 0.0)),
          rotateVector(a, b, new Vector3(0.0, 1.0, 0.0)),
          rotateVector(a, b, new Vector3(0.0, 0.0, 1.0)));
      return new Quaternion.fromRotation(rot);*/
  
      /* (a1*e1 + e2*a2 + a3*e3)*(b1*e1 + b2*e2 + b3*e3) =
       * a1*e1*(b1*e1 + b2*e2 + b3*e3) +
       * a2*e2*(b1*e1 + b2*e2 + b3*e3) +
       * a3*e3*(b1*e1 + b2*e2 + b3*e3) =
       * a1*b1       + a1*b2*e1^e2 + a1*b3*e1^e3 +
       * a2*b1*e2^e1 + a2*b2       + a2*b3*e2^e3 +
       * a3*b1*e3^e1 + a3*b2*e3^e2 + a3*b3 =
       *   a1*b1       + a1*b2*e1^e2 + a1*b3*e1^e3 +
       * - a2*b1*e1^e2 + a2*b2       + a2*b3*e2^e3 +
       * - a3*b1*e1^e3 - a3*b2*e2^e3 + a3*b3 =
       * (a1*b1+a2*b2+a3*b3) +
       * (a1*b2-a2*b1)*e1^e2 +
       * (a1*b3-a3*b1)*e1^e3 +
       * (a2*b3-a3*b2)*e2^e3
       */
      /* (a1*e1 + a2*e2 + a3*e3)*(e1*e2*e3) =
       * a1*e2*e3 + a2*e2*e1*e2*e3 + a3*e3*e1*e2*e3 =
       * a1*e2*e3 - a2*e1*e2*e2*e3 - a3*e1*e3*e2*e3 =
       * a1*e2*e3 - a2*e1*e2*e2*e3 + a3*e1*e2*e3*e3 =
       * a1*e2*e3 - a2*e1*e3 + a3*e1*e2 =
       */
  
      Vector3 bn = b.normalized();
      Vector3 an = a.normalized();
      Vector3 cn = (an + bn).normalized();
      /*Quaternion out = new Quaternion(an.dot(cn), (an.x * cn.y - an.y * cn.x),
          (an.x * cn.z - an.z * cn.x), (an.y * cn.z - an.y * cn.z));
      out.normalize();*/
  
      Multivector aq = new Multivector(an);
      Multivector cq = new Multivector(cn);
  
      Multivector out = aq / cq;
      //Multivector out = new Multivector.one();
  
      return out;
    }
    Multivector dragRotation(Point start, Point end,
        [double planeDistance = 1.0]) {
      Vector2 startDrag =
          new Vector2(start.x / _viewportWidth, 1.0 - start.y / _viewportHeight);
      Vector2 endDrag =
  