anchor.diff:        (rng.nextDouble() - 0.5) * d, (rng.nextDouble() - 0.5) * d);
   }
   
  +List<Pole> MakeRowOfPoles(List<double> xx, double y, double z, double scale) {
  +  List<Pole> out = [];
  +  for (double x in xx) {
  +    out.add(new Pole(new VM.Vector3(x, y, z) * scale)..Update(1.0));
  +  }
  +  return out;
  +}
  +
   void main() {
     StatsFps fps =
         new StatsFps(HTML.document.getElementById("stats"), "blue", "gray");
   
  +  final Math.Random rng = new Math.Random(0);
  +
     HTML.CanvasElement canvas = HTML.document.querySelector('#webgl-canvas');
     final int width = canvas.clientWidth;
     final int height = canvas.clientHeight;
  +  canvas.width = width;
  +  canvas.height = height;
  +
     ChronosGL chronosGL = new ChronosGL(canvas);
     OrbitCamera orbit = new OrbitCamera(15.0, 0.5, 0.5, canvas);
  -
     Perspective perspective = new Perspective(orbit, 0.1, 1000.0)
       ..AdjustAspect(width, height);
  -
     RenderPhase phase = new RenderPhase("main", chronosGL)
       ..viewPortW = width
       ..viewPortH = height;
  -
  -  Math.Random rng = new Math.Random(0);
  -  List<Pole> srcPoles = [];
  -  double p = 3.0;
  -  srcPoles.add(new Pole(new VM.Vector3(2.0 * p, 0.0, 2.0 * p))..Update(1.0));
  -  srcPoles.add(new Pole(new VM.Vector3(1.0 * p, 0.0, 2.0 * p))..Update(1.0));
  -  srcPoles.add(new Pole(new VM.Vector3(0.0 * p, 0.0, 2.0 * p))..Update(1.0));
  -  srcPoles.add(new Pole(new VM.Vector3(-1.0 * p, 0.0, 2.0 * p))..Update(1.0));
  -  srcPoles.add(new Pole(new VM.Vector3(-2.0 * p, 0.0, 2.0 * p))..Update(1.0));
  -
  -  List<Pole> dstPoles = [];
  -  dstPoles.add(new Pole(new VM.Vector3(2.0 * p, 0.0, -2.0 * p))..Update(1.0));
  -  dstPoles.add(new Pole(new VM.Vector3(1.0 * p, 0.0, -2.0 * p))..Update(1.0));
  -  dstPoles.add(new Pole(new VM.Vector3(0.0 * p, 0.0, -2.0 * p))..Update(1.0));
  -  dstPoles.add(new Pole(new VM.Vector3(-1.0 * p, 0.0, -2.0 * p))..Update(1.0));
  -  dstPoles.add(new Pole(new VM.Vector3(-2.0 * p, 0.0, -2.0 * p))..Update(1.0));
  +  List<Pole> srcPoles =
  +      MakeRowOfPoles([2.0, 1.0, 0.0, -1.0, -2.0], 0.0, 2.0, 3.0);
  +  List<Pole> dstPoles =
  +      MakeRowOfPoles([2.0, 1.0, 0.0, -1.0, -2.0], 0.0, -2.0, 3.0);
   
     VM.Vector3 outOfBounds = new VM.Vector3.all(kMaxDistance * 100.0);
     List<Ion> ions = [];
  
positive.code: 
  const double kMaxDistance = 100.1;
  const double kMinDistance = 0.2;
  
  List<ShaderObject> createFireWorksShader() {
    return [
  
negative.code:     _lastTimeMs = timeMs;
      orbit.azimuth += 0.001;
  
      if (programSprites.enabled && elapsed > 0.0) {
        int n = 0;
        for (Ion ion in ions) {
          ion.Update(srcPoles, dstPoles, rng, elapsed / 1000.0);
          vertices[n + 0] = ion.Pos().x;
          vertices[n + 1] = ion.Pos().y;
          vertices[n + 2] = ion.Pos().z;
          n += 3;
        }
        md.ChangeVertices(vertices);
      }
      orbit.animate(elapsed);
  
      phase.draw([perspective]);
  
      HTML.window.animationFrame.then(animate);
      fps.UpdateFrameCount(timeMs);
      if (pssp.enabled) {
        chronosGL.bindBuffer(GL_ARRAY_BUFFER, md1.GetBuffer(aVertexPosition));
        chronosGL.bindBuffer(
            GL_TRANSFORM_FEEDBACK_BUFFER, md2.GetBuffer(aVertexPosition));
        chronosGL.copyBufferSubData(
            GL_TRANSFORM_FEEDBACK_BUFFER, GL_ARRAY_BUFFER, 0, 0, kIons * 3);
      }
    }
  
    animate(0.0);
  