<!-- PLAYA · part 12 -->
bserver(resize).observe(vp);

/* ---------- LOOP ---------- */
var clock = new THREE.Clock(), secPlane = new THREE.Vector3();
function loop(){
  requestAnimationFrame(loop);
  var dt = Math.min(0.05, clock.getDelta()), t = clock.elapsedTime;
  blocks.forEach(function(b){
    if(b.userData.spin) b.rotation.y += b.userData.spin * dt;
    if(b.userData.bob) b.position.y = b.userData.bobBase + (Math.sin(t * 2) + 1) * 0.6;
    if(b.userData.section){
      if(!b.userData.plane) b.userData.plane = new THREE.Plane(new THREE.Vector3(0, -1, 0), 0);
      boxOf(b).getCenter(secPlane); b.userData.plane.constant = secPlane.y;
      meshesOf(b).forEach(function(m){ if(!m.material.clippingPlanes || m.material.clippingPlanes[0] !== b.userData.plane){ m.material.clippingPlanes = [b.userData.plane]; m.material.side = THREE.DoubleSide; m.material.needsUpdate = true; } });
    } else {
      meshesOf(b).forEach(function(m){ if(m.material.clippingPlanes && m.material.clippingPlanes.length){ m.material.clippingPlanes = null; m.material.side = THREE.FrontSide; m.material.needsUpdate = true; } });
    }
  });
  if(selected && selBox.visible) selBox.setFromObject(selected);
  updateCamera();
  renderer.render(scene, camera);
}

/* ---------- START ---------- */
applyLayout();
setEnv('golden');
updateCamera(); placeSun();
showWheel(); renderLib();
spawn('hourglass', 0, 0, true);
undoStack.length = 0;   /* the starter block is not an undo step */
ACT.tool('select');
say('THE CREATOR v1 ready — drag to look, pinch / wheel to zoom. Tap a block to select it.');
loop();
window.THE_CREATOR = {version: 'v1', blocks: blocks, scene: scene, camera: camera};
})();


===== FILE: public/playa/index.html =====
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="theme-color" content="#07070c">
<title>THE CREATOR v1</title>
<style>
/* THE CREATOR v1 — dark glass, gold trim (TACTICAL / REGALIA). One page, two layouts:
   .phone  (< 820px or coarse pointer): vertical rail, slide-up sheets, actions shelf, big export.
   .studio (>= 820px, fine pointer):    tabs, left / right / bottom panels, gold export bar. */
*{box-sizing:border-box;-webkit-tap-highlight-color:transparent;}
html,body{margin:0;padding:0;height:100%;overflow:hidden;background:#07070c;color:#f3dfa2;
  font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,system-ui,sans-serif;font-size:14px;
  -webkit-user-select:none;user-select:none;-webkit-touch-callout:none;}
:root{--shelfH:150px;--gold:#d8a920;--gold2:#ffd76a;--glass:rgba(14,12,9,0.86);--glass2:rgba(26,21,12,0.92);--line:rgba(216,169,32,0.55);}
button{font:inherit;color:inherit;}
.btn{min-width:48px;min-height:48px;padding:6px 8px;border-radius:10px;border:1px solid var(--line);
  background:linear-gradient(180deg,rgba(40,32,16,0.95),rgba(16,13,8,0.95));color:#f6e3a8;cursor:pointer;
  display:flex;flex-direction:column;align-items:center;justify-content:center;text-align:center;line-height:1.15;
  touch-action:manipulation;font-size:12px;letter-spacing:0.3px;}
.btn .ic{font-size:20px;line-height:1;margin-bottom:3px;color:var(--gold2);}
.btn:active{background:var(--gold);color:#111;}
.btn.on{background:linear-gradient(180deg,#f0c540,#b8860b);color:#111;border-color:#ffe28a;}
.btn.on .ic{color:#111;}
.btn.wide{flex-direction:row;justify-content:flex-start;padding:6px 12px;font-size:14px;}
.btn.wide .ic{margin:0 10px 0 0;}
.btn.gold{background:linear-gradient(180deg,#f3cd55,#b8860b);color:#140f04;font-weight:700;border-color:#ffe28a;}
.grid{display:grid;grid-gap:8px;}
.g2{grid-template-columns:repeat(2,minmax(48px,1fr));}
.g3{grid-template-columns:repeat(3,minmax(48px,1fr));}
.g4{grid-template-columns:repeat(4,minmax(48px,1fr));}
.gauto{grid-template-columns:repeat(auto-fill,minmax(72px,1fr));}
.sec{padding:10px;border-bottom:1px solid rgba(216,169,32,0.25);}
.sec h3{margin:0 0 8px 0;font-size:12px;letter-spacing:2px;color:var(--gold2);font-weight:700;text-transform:uppercase;}
.sec h4{margin:10px 0 6px 0;font-size:11px;letter-spacing:1.5px;color:#c9a64a;font-weight:600;text-transform:uppercase;}
.note{font-size:12px;color:#bfa66a;margin:6px 0 0 0;line-height:1.35;}
.row{display:grid;grid-template-columns:minmax(60px,86px) minmax(90px,1fr);align-items:center;grid-gap:8px;margin:4px 0;min-height:48px;}
.row label{font-size:12px;color:#d9c07a;}
input[type=range]{width:100%;height:48px;margin:0;background:transparent;-webkit-appearance:none;appearance:none;touch-action:pan-y;}
input[type=range]::-webkit-slider-runnable-track{height:6px;border-radius:3px;background:linear-gradient(90deg,#5a4512,#d8a920);}
input[type=range]::-webkit-slider-thumb{-webkit-appearance:none;width:28px;height:28px;margin-top:-11px;border-radius:50%;background:#ffd76a;border:2px solid #6b4f0a;}
input[type=range]::-moz-range-track{height:6px;bord