anchor.diff:  
   void AddInstanceData(MeshData md, int count) {
     final Float32List scales = Float32List(count * 1);
  -  final Float32List colors = Float32List(count * 3);
     final Float32List translations = Float32List(count * 3);
     final Float32List rotations = Float32List(count * 4);
     final Math.Random rand = Math.Random();
   
     for (int i = 0; i < count; i++) {
  -    final VM.Vector3 t = VM.Vector3(rand.nextDouble() * 40,
  -        rand.nextDouble() * 40.0, rand.nextDouble() * 40.0);
  +    final VM.Vector3 t = VM.Vector3.random(rand) - VM.Vector3(0.5, 0.5, 0.5);
  +    t.scale(60.0);
       translations.setAll(i * 3, t.storage);
       final VM.Vector3 u =
  -        VM.Vector3(rand.nextDouble(), rand.nextDouble(), rand.nextDouble());
  -    /*
  -    final VM.Quaternion q = VM.Quaternion(
  -        Math.sqrt(1 - u.x) * Math.sin(2.0 * Math.pi * u.y),
  -        Math.sqrt(1 - u.x) * Math.cos(2.0 * Math.pi * u.y),
  -        Math.sqrt(1 - u.x) * Math.sin(2.0 * Math.pi * u.z),
  -        Math.sqrt(1 - u.x) * Math.cos(2.0 * Math.pi * u.z));
  -    */
  -    VM.Quaternion q =
  +        VM.Vector3.random(rand);
  +    final VM.Quaternion q =
           VM.Quaternion.axisAngle(u, 2.0 * rand.nextDouble() * Math.pi);
       rotations.setAll(i * 4, q.storage);
  -    final VM.Vector c =
  -        VM.Vector3(rand.nextDouble(), rand.nextDouble(), rand.nextDouble());
  -    colors.setAll(i * 3, c.storage);
  -    scales.setAll(i, [rand.nextDouble() * 5.0]);
  +
  +    scales.setAll(i, [2.0 + rand.nextDouble() * 4.0]);
     }
   
     md.AddAttribute(iaRotation, rotations, 4);
  -  md.AddAttribute(iaColor, colors, 3);
     md.AddAttribute(iaTranslation, translations, 3);
     md.AddAttribute(iaScale, scales, 1);
  +}
  +
  +final VM.Vector3 dirLight = VM.Vector3(0.0, -50.0, 0.0);
  +
  +class Phase {
  +  Phase(this.program, this.md, this.fb);
  +
  +  final Framebuffer fb;
  +  final Material mat = Material("mat");
  +  final RenderProgram program;
  +  final MeshData md;
  +
  +  void Run(int width, int height, [List<UniformGroup> extra]) {
  +    fb.Activate(GL_CLEAR_ALL, 0, 0, width, height);
  +    List<UniformGroup> uniforms = [mat];
  +    if (extra != null) {
  +      uniforms.addAll(extra);
  +    }
  +    program.Draw(md, uniforms);
  +  }
  +}
  +
  +Framebuffer MakePrepareFb(ChronosGL cgl, int width, int height) {
  +  TypedTexture tex = TypedTexture(
  +      cgl, "float", width, height, GL_RGBA32F, TexturePropertiesFramebuffer);
  +  TypedTexture depthTexture = TypedTexture(cgl, "frame::depth", width, height,
  +      GL_DEPTH_COMPONENT24, TexturePropertiesShadowMap);
  +  return Framebuffer(cgl, tex, depthTexture);
   }
   
   void main() {
  
positive.code:   final ChronosGL cgl = ChronosGL(canvas, faceCulling: false)
      ..clearColor(0.5, 0.5, 0.5, 1.0);
  
    final dynamic ext = cgl.getExtension("EXT_color_buffer_float");
    if (ext == null) {
      HTML.window.alert("extension not available: EXT_color_buffer_float");
    }
    OrbitCamera orbit = OrbitCamera(100.0, 0.0, 0.0, canvas);
  
    Perspective perspective = Perspective(orbit, 0.1, 1000.0);
  
    final width = canvas.clientWidth;
    final height = canvas.clientHeight;
  
negative.code:   canvas.height = height;
    perspective.AdjustAspect(width, height);
  
    final RenderProgram progPreparation = RenderProgram(
        "preparation", cgl, preparationVertexShader, preparationFragmentShader);
  
    final RenderProgram progInstanced = RenderProgram(
        "instanced", cgl, instancedVertexShader, instancedFragmentShader);
  
    final MeshData cubes = ShapeCube(progInstanced, computeNormals: true);
    AddInstanceData(cubes, 80);
    print("instances: $cubes.GetNumInstances()}");
  
    final Phase prepare =
        Phase(progPreparation, cubes, MakePrepareFb(cgl, width, height))
          ..mat.SetUniform(uModelMatrix, VM.Matrix4.identity());
  
    final Phase render = Phase(progInstanced, cubes, Framebuffer.Screen(cgl))
      ..mat.SetUniform(uModelMatrix, VM.Matrix4.identity())
      ..mat.SetUniform(uShininess, 10.0)
      ..mat.SetUniform(uTexture, prepare.fb.colorTexture);
  
  /*
    // The lines show aliasing problems but the experiments below
    // did not help:
    final Phase render =
    Phase(progInstanced, cubes, Framebuffer.Default(cgl, width, height))
      ..mat.SetUniform(uModelMatrix, VM.Matrix4.identity())
      ..mat.SetUniform(uShininess, 10.0)
      ..mat.SetUniform(uTexture, prepare.fb.colorTexture);
  
  
    final RenderProgram blurProg =
    RenderProgram("blur", cgl, effectVertexShader, blur1DShader9);
    final MeshData unitQuad = ShapeQuad(blurProg, 1);
  
  
    final Phase horizontalBlur =
    Phase(blurProg, unitQuad, Framebuffer.Effect(cgl, width, height))
      ..mat.SetUniform(uTexture, render.fb.colorTexture)
      ..mat.SetUniform(uDirection, VM.Vector2(1.0, 0.0));
  
    final Phase verticalBlur = Phase(
        blurProg, unitQuad, Framebuffer.Screen(cgl))
      ..mat.SetUniform(uTexture, horizontalBlur.fb.colorTexture)
      ..mat.SetUniform(uDirection, VM.Vector2(0.0, 1.0));
  */
  
    double _lastTimeMs = 0.0;
    void animate(num timeMs) {
  