<!-- RUBY-BACKUP · part 290 -->
, z);
    var hd = Math.sqrt(x*x+z*z);
    var h = hd < 2 ? hb : Math.max(0.02, hb);
    pa.setY(i, FLOOR_Y + 0.02 + h);
    var t = Math.min(1, h/1.2);
    tmp.copy(cA).lerp(t<0.5?cB:cC, t<0.5? t*2 : (t-0.5)*2);
    var n = 0.5+0.5*Math.sin(x*0.9+z*0.7)*Math.sin(x*0.23-z*0.51);
    tmp.lerp(cD, n*0.22);
    colors.push(tmp.r, tmp.g, tmp.b);
  }
  g.setAttribute('color', new T.Float32BufferAttribute(colors, 3));
  g.computeVertexNormals();
  /* one whole — the top flows into the sides into the bottom, a single solid, like one babystep */
  var pos = g.attributes.position, idx = g.index;
  var vCount = pos.count, iCount = idx.count;
  var edge = [];
  for(var ei=0; ei<vCount; ei++){
    var ex = pos.getX(ei), ez = pos.getZ(ei);
    if(Math.abs(Math.abs(ex)-49)<0.01 || Math.abs(Math.abs(ez)-49)<0.01) edge.push(ei);
  }
  var nV = vCount + edge.length;
  var nPos = new Float32Array(nV*3), nCol = new Float32Array(nV*3);
  var earth = new T.Color(0x2e2620);
  for(var vi=0; vi<vCount; vi++){
    nPos[vi*3]=pos.getX(vi); nPos[vi*3+1]=pos.getY(vi); nPos[vi*3+2]=pos.getZ(vi);
    nCol[vi*3]=colors[vi*3]; nCol[vi*3+1]=colors[vi*3+1]; nCol[vi*3+2]=colors[vi*3+2];
  }
  var eMap = {};
  for(var qi=0; qi<edge.length; qi++){
    var ti = edge[qi], bi2 = vCount+qi;
    eMap[ti] = bi2;
    nPos[bi2*3]=pos.getX(ti); nPos[bi2*3+1]=-2; nPos[bi2*3+2]=pos.getZ(ti);
    nCol[bi2*3]=earth.r; nCol[bi2*3+1]=earth.g; nCol[bi2*3+2]=earth.b;
  }
  var nIdx = [];
  for(var ii=0; ii<iCount; ii++) nIdx.push(idx.getX(ii));
  /* sides — each edge vertex pairs with its neighbor along the rim */
  var rim = edge.slice().sort(function(a,b){
    var ax=pos.getX(a), az=pos.getZ(a), bx=pos.getX(b), bz=pos.getZ(b);
    return (Math.atan2(az,ax)-Math.atan2(bz,bx));
  });
  for(var ri2=0; ri2<rim.length; ri2++){
    var t0=rim[ri2], t1=rim[(ri2+1)%rim.length];
    var b0=eMap[t0], b1=eMap[t1];
    nIdx.push(t0,b0,b1, t0,b1,t1);
  }
  var sg = new T.BufferGeometry();
  sg.setAttribute('position', new T.BufferAttribute(nPos,3));
  sg.setAttribute('color', new T.BufferAttribute(nCol,3));
  sg.setIndex(nIdx);
  sg.userData.topCount = vCount;
  sg.computeVertexNormals();
  landMesh = new T.Mesh(sg, new T.MeshStandardMaterial({vertexColors:true, roughness:0.95, metalness:0, side:T.DoubleSide}));
  scene.add(landMesh);
}
function layLand(){
  if(typeof mePos!=='undefined' && WALK && typeof groundY==='function' && landMesh){
    mePos.y = groundY(mePos.x, mePos.z)+0.1; meVel.y = 0; onGround = true;
  }
  if(landMesh){ codeStatus('the landscape already rests beneath us — feet on it'); return; }
  if(!floorMesh){ buildFloorMesh(); try{ localStorage.setItem(FLOOR_KEY,'1'); }catch(e){} }
  buildLandMesh();
  try{ localStorage.setItem(LAND_KEY, '1'); }catch(e){}
  if(typeof mePos!=='undefined' && WALK && typeof groundY==='function'){
    mePos.y = groundY(mePos.x, mePos.z)+0.1; meVel.y = 0; onGround = true;
  }
  codeStatus('the landscape — our feet rest upon it');
}
function layFloor(){
  if(typeof mePos!=='undefined' && WALK && typeof groundY==='function' && floorMesh){
    mePos.y = groundY(mePos.x, mePos.z)+0.1; meVel.y = 0; onGround = true;
  }
  if(floorMesh){ codeStatus('the stone layer already stands — feet on it'); return; }
  buildFloorMesh();
  try{ localStorage.setItem(FLOOR_KEY, '1'); }catch(e){}
  if(typeof mePos!=='undefined' && WALK && typeof groundY==='function'){
    mePos.y = groundY(mePos.x, mePos.z)+0.1; meVel.y = 0; onGround = true;
  }
  codeStatus('the stone layer — one whole, our shoes upon it');
}
function fireBolt(twin){
      var bx0 = Math.random()*80-40, bz0 = Math.random()*80-40;
      /* white out first — then the blue lines after (frame-loop flash, cannot stick) */
      flashT = 0.15;
      setTimeout(function(){
        var across = Math.random() < 0.5;
        var bp = boltLine.geometry.attributes.position, bxx = bx0, bzz = bz0;
        if(across){
          /* across the sky — long travel over the cloud tops */
          var hd = Math.random()*Math.PI*2, hy = 32+Math.random()*8;
          bxx = bx0 - Math.cos(hd)*70; bzz = bz0 - Math.sin(hd)*70;
          for(var bi2=0; bi2<16; bi2++){
            bp.setXYZ(bi2, bxx, hy + (Math.random()-0.5)*7, bzz);
            bxx += Math.cos(hd)*10; bzz += Math.sin(hd)*10;
          }
        }else{
          /* down to the ground — taller */
          for(var bi2=0; bi2<16; bi2++){
            bp.setXYZ(bi2, bxx, 46 - bi2*3.1, bzz);
            bxx += (Math.random()-0.5)*10; bzz += (Math.random()-0.5)*10;
          }
        }
        bp.needsUpdate = true;
        /* blue glow sleeve around the white core */
        var gpts = [];
        for(var gpi=0; gpi<16; gpi++){ gpts.push(new T.Vector3(bp.getX(gpi), bp.getY(gpi), bp.getZ(gpi))); }
        var gcurve = new T.CatmullRomCurve3(gpts);
        var ng = new T.TubeGeometry(gcurve, 48, 0.35, 6, false);
        boltGlow.geometry.dispose();
        boltGlow.geometry = ng;
        /* a fork off the middle *