anchor.diff:      ..AddVertices(ionsPos);
     MeshData mdIn = programGPU.MakeMeshData("ionsIn", GL_POINTS)
       ..AddVertices(ionsPos);
  -  programGPU.add(new Node("ionsGPU", mdIn, matGPU));
  -
  -  void SelectRenderer(HTML.Event ev) {
  - programJS.enabled = gCpuCompute.checked;
  -  programGPU.enabled = !programJS.enabled;
  - }
   
     void ResizeIons(HTML.Event ev) {
       int n = int.parse(gParticles.value);
  
positive.code: final HTML.InputElement gCpuCompute =
      HTML.document.querySelector('#cpucompute');
  
  List<ShaderObject> createParticleShader() {
    return [
      new ShaderObject("ParticleV")
        ..AddAttributeVars([aVertexPosition])
        ..AddUniformVars(
            [uPerspectiveViewMatrix, uModelMatrix, uPointSize, uSources, uSinks])
        ..AddTransformVars([tPosition])
        ..SetBody([
          """
  const float kMaxDistance = ${kMaxDistance};
  const float kMinDistance = ${kMinDistance};
  const float dt = 0.06;  
  
negative.code:   chronosGL.bindTransformFeedback(transform);
  
    ResizeIons(null);
  
    void animate(timeMs) {
      orbit.azimuth += 0.002;
      orbit.animate(0.0); // argument is not used
  
      if (gCpuCompute.checked) {
        UpdateIonsJS(0.06);
        programJS.Draw(mdJS, [perspective, matJS]);
      } else {
        programGPU.Draw(mdIn, [perspective, matGPU]);
        // use vertex shader output as input for next round
        chronosGL.bindBuffer(GL_ARRAY_BUFFER, mdIn.GetBuffer(aVertexPosition));
        chronosGL.bindBuffer(
            GL_TRANSFORM_FEEDBACK_BUFFER, mdOut.GetBuffer(aVertexPosition));
        chronosGL.copyBufferSubData(
            GL_TRANSFORM_FEEDBACK_BUFFER, GL_ARRAY_BUFFER, 0, 0, ions.length * 3);
      }
      HTML.window.animationFrame.then(animate);
      fps.UpdateFrameCount(timeMs);
    }
  
    gParticles.onChange.listen(ResizeIons);
    animate(0.0);
  }
  