<!-- RUBY-BACKUP · part 230 -->
andardMaterial({color: 0x888899, metalness: 0.7, roughness: 0.4}));
  ladder.position.y = 1;
  g.add(ladder);
  /* slide — curved */
  var slideCurve = new THREE.CatmullRomCurve3([
    new THREE.Vector3(0, 2, 0),
    new THREE.Vector3(0, 1.2, 0.8),
    new THREE.Vector3(0, 0.3, 1.8)
  ]);
  var slide = new THREE.Mesh(
    new THREE.TubeGeometry(slideCurve, 16, 0.3, 8, false),
    new THREE.MeshStandardMaterial({
      color: colorHex, emissive: colorHex, emissiveIntensity: 0.3,
      roughness: 0.3, metalness: 0.2
    })
  );
  /* flatten the tube to make it slide-shaped */
  slide.scale.x = 1.5;
  g.add(slide);
  g.position.set(x, y, z);
  return g;
}
function buildSwingSet(x, y, z){
  var g = new THREE.Group();
  var frameMat = new THREE.MeshStandardMaterial({color: 0xff66cc, metalness: 0.6, roughness: 0.4});
  /* A-frame */
  [-1,1].forEach(function(s){
    var leg1 = new THREE.Mesh(new THREE.CylinderGeometry(0.06, 0.06, 2.5, 8), frameMat);
    leg1.position.set(0, 1.25, s*0.8); leg1.rotation.x = s*0.25;
    g.add(leg1);
  });
  var bar = new THREE.Mesh(new THREE.CylinderGeometry(0.06, 0.06, 2.5, 8), frameMat);
  bar.rotation.z = Math.PI/2; bar.position.y = 2.4;
  g.add(bar);
  /* swings */
  [-0.6, 0.6].forEach(function(sx){
    var swingG = new THREE.Group();
    [-1,1].forEach(function(s){
      var chain = new THREE.Mesh(new THREE.CylinderGeometry(0.015, 0.015, 1.2, 6),
        new THREE.MeshStandardMaterial({color: 0xcccccc, metalness: 0.8, roughness: 0.3}));
      chain.position.set(0, -0.6, s*0.2);
      swingG.add(chain);
    });
    var seat = new THREE.Mesh(new THREE.BoxGeometry(0.4, 0.06, 0.5),
      new THREE.MeshStandardMaterial({color: 0x00ccff, roughness: 0.5}));
    seat.position.y = -1.2;
    swingG.add(seat);
    swingG.position.set(sx, 2.4, 0);
    g.add(swingG);
    /* swing animation */
    var t = Math.random()*10;
    var anim = setInterval(function(){
      t += 0.03;
      swingG.rotation.x = Math.sin(t)*0.4;
    }, 50);
    swingG.userData.anim = anim;
  });
  g.position.set(x, y, z);
  return g;
}
function buildMerryGoRound(x, y, z){
  var g = new THREE.Group();
  /* platform */
  var platform = new THREE.Mesh(new THREE.CylinderGeometry(2, 2.2, 0.2, 20),
    new THREE.MeshStandardMaterial({color: 0xffcc00, roughness: 0.5}));
  platform.position.y = 0.3;
  g.add(platform);
  /* center pole */
  var pole = new THREE.Mesh(new THREE.CylinderGeometry(0.15, 0.15, 3, 12),
    new THREE.MeshStandardMaterial({color: 0xff66cc, metalness: 0.5, roughness: 0.4}));
  pole.position.y = 1.8;
  g.add(pole);
  /* canopy */
  var canopy = new THREE.Mesh(new THREE.ConeGeometry(2.5, 1.2, 16),
    new THREE.MeshStandardMaterial({
      color: 0xff3399, emissive: 0xff3399, emissiveIntensity: 0.2,
      roughness: 0.6, side: THREE.DoubleSide
    }));
  canopy.position.y = 3.5;
  g.add(canopy);
  /* lights around canopy */
  for(var i=0; i<12; i++){
    var ang = i*(Math.PI*2/12);
    var light = new THREE.Mesh(new THREE.SphereGeometry(0.08, 8, 8),
      new THREE.MeshStandardMaterial({
        color: [0xff0000,0x00ff00,0x0000ff,0xffff00][i%4],
        emissive: [0xff0000,0x00ff00,0x0000ff,0xffff00][i%4],
        emissiveIntensity: 2
      }));
    light.position.set(Math.cos(ang)*2.3, 3.0, Math.sin(ang)*2.3);
    g.add(light);
  }
  /* seats */
  for(var s=0; s<6; s++){
    var sa = s*(Math.PI*2/6);
    var seat = new THREE.Mesh(new THREE.BoxGeometry(0.5, 0.4, 0.5),
      new THREE.MeshStandardMaterial({color: 0x00ccff, roughness: 0.5}));
    seat.position.set(Math.cos(sa)*1.5, 0.6, Math.sin(sa)*1.5);
    g.add(seat);
  }
  g.position.set(x, y, z);
  /* spin */
  var spinAnim = setInterval(function(){
    g.rotation.y += 0.01;
  }, 50);
  g.userData.anim = spinAnim;
  return g;
}
function buildPlaygrounds(){
  if(typeof scene==='undefined' || typeof mePos==='undefined') return;
  if(PLAYGROUNDS){
    PLAYGROUNDS.forEach(function(p){
      try{ scene.remove(p); }catch(e){}
      p.traverse(function(o){ if(o.userData.anim) clearInterval(o.userData.anim); });
    });
  }
  PLAYGROUNDS = [];
  var px = mePos.x*0.13, pz = mePos.z*0.13;
  /* playground 1 — near the plaza */
  var pg1 = new THREE.Group();
  var ground1 = new THREE.Mesh(new THREE.CylinderGeometry(8, 8.5, 0.2, 24),
    new THREE.MeshStandardMaterial({color: 0x66cc66, roughness: 0.9}));
  ground1.position.y = 0.1;
  pg1.add(ground1);
  var slide1 = buildSlide(-3, 0.2, -2, 0xff6600);
  pg1.add(slide1);
  var swings1 = buildSwingSet(3, 0.2, 2);
  pg1.add(swings1);
  var merry1 = buildMerryGoRound(0, 0.2, -4);
  pg1.add(merry1);
  pg1.position.set(px+25, 0, pz+15);
  scene.add(pg1);
  PLAYGROUNDS.push(pg1);
  /* playground 2 — rainbow theme */
  var pg2 = new THREE.Group();
  var ground2 = new THREE.Mesh(new THREE.CylinderGeometry(8, 8.5, 0.2, 24),
    new THREE.MeshStandardMaterial({color: 0x88dd88, roughness: 0.9}));
  ground2.position.y = 0.1;
  pg2.add(ground2);
  var colors = [0xff0000, 0xff8800, 0xffff00, 0x