← Back to Articles Directory
AI Models August 21, 2026 6 min read

Ox Alpha Released: Specs, Benchmarks & Interactive Coding Tests

Ox Alpha released today, August 21, 2026. Featuring advanced spatial reasoning and ultra-long context comprehension, we run hands-on photorealistic SVG, 3D procedural globe, and 3D WebGL wizard adventure game benchmarks.

Mohid Mirza

Co-Founder & Lead Programmer of AcceleratedLogic AI

Ox Alpha has officially dropped today, and as one of the newest experimental frontier reasoning models, there’s been substantial buzz around its capabilities. Today, we’re putting it straight to the test on our interactive benchmark suite.

Architecture, Specs & Capabilities

Ox Alpha introduces an architecture centered on high-density reasoning with deep procedural synthesis. Built with native support for ultra-long context and complex multi-step spatial and mathematical reasoning, it aims directly at challenging the frontier coding standards set by Claude 3.7 / 5 Opus and Gemini 3.7.
Let’s run it through our standard rigorous frontend and 3D graphics benchmarks to see if the hype holds up in practice.

Test 1: Photorealistic 3D Glass Sphere with Origami Crane

First, our classic visual vector graphics challenge — generating a complex, self-contained SVG illustration of a folded origami crane suspended inside an optical glass sphere with realistic lighting, caustics, and reflections:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1"/>
<title>Folded Light — a paper crane in glass</title>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Fraunces:ital,opsz,wght@0,9..144,300..600;1,9..144,300..600&display=swap" rel="stylesheet">
<style>
  *{margin:0;padding:0;box-sizing:border-box}
  html,body{height:100%}
  body{background:#0b0a08;display:flex;align-items:center;justify-content:center;overflow:hidden;
       font-family:'Fraunces',Georgia,serif;color:#ece3cf}
  .stage{position:relative;width:min(100vw,calc(100vh*1.3953));aspect-ratio:1200/860;
         animation:rise 1.3s cubic-bezier(.22,.61,.21,1) both}
  @keyframes rise{from{opacity:0;transform:translateY(12px)}to{opacity:1;transform:none}}
  svg{width:100%;height:100%;display:block;cursor:grab;touch-action:none;outline:none}
  svg.dragging{cursor:grabbing}
  .plate{position:absolute;left:0;right:0;bottom:2.8%;text-align:center;pointer-events:none}
  .rule{width:26px;height:1px;background:#4a4437;margin:0 auto 13px}
  .over{font-size:10px;letter-spacing:.34em;text-transform:uppercase;color:#877f6d;margin-bottom:11px}
  h1{font-style:italic;font-weight:450;font-size:clamp(22px,3vw,34px);letter-spacing:.01em;color:#ece3cf}
  .hint{margin-top:11px;display:flex;align-items:center;justify-content:center;gap:7px;font-size:10px;
        letter-spacing:.22em;text-transform:uppercase;color:#6f6858;transition:opacity 1.2s ease}
  .stage.dragged .hint{opacity:0}
  .corner{position:absolute;font-size:9px;letter-spacing:.26em;text-transform:uppercase;color:#57513f}
  .tl{top:3.6%;left:3.4%}.tr{top:3.6%;right:3.4%}
  @media (prefers-reduced-motion:reduce){.stage{animation:none}}
</style>
</head>
<body>
<div class="stage" id="stage">
<svg id="scene" viewBox="0 0 1200 860" tabindex="0" role="img"
     aria-label="A glass sphere with an origami crane suspended inside. Drag to rotate the crane.">
  <title>Folded Light — a paper crane in glass</title>

  <defs>
    <!-- environment -->
    <linearGradient id="gBg" x1="0" y1="0" x2="0" y2="1">
      <stop offset="0" stop-color="#16130f"/><stop offset="1" stop-color="#0b0a08"/>
    </linearGradient>
    <radialGradient id="gGlow">
      <stop offset="0" stop-color="#ffd9a8" stop-opacity="0.11"/>
      <stop offset="0.6" stop-color="#ffd9a8" stop-opacity="0.04"/>
      <stop offset="1" stop-color="#ffd9a8" stop-opacity="0"/>
    </radialGradient>
    <linearGradient id="gGround" x1="0" y1="0" x2="0" y2="1">
      <stop offset="0" stop-color="#e8cf9f" stop-opacity="0.06"/>
      <stop offset="1" stop-color="#e8cf9f" stop-opacity="0"/>
    </linearGradient>

    <!-- drop shadow & caustic -->
    <radialGradient id="gShadow">
      <stop offset="0" stop-color="#000" stop-opacity="0.62"/>
      <stop offset="0.5" stop-color="#000" stop-opacity="0.28"/>
      <stop offset="1" stop-color="#000" stop-opacity="0"/>
    </radialGradient>
    <radialGradient id="gCaustic">
      <stop offset="0" stop-color="#ffdfae" stop-opacity="0.8"/><stop offset="1" stop-color="#ffdfae" stop-opacity="0"/>
    </radialGradient>
    <radialGradient id="gCausticC">
      <stop offset="0" stop-color="#fff4de" stop-opacity="0.95"/><stop offset="1" stop-color="#fff4de" stop-opacity="0"/>
    </radialGradient>

    <!-- floor reflection -->
    <radialGradient id="gRefl">
      <stop offset="0" stop-color="#a9c4cc" stop-opacity="0.16"/>
      <stop offset="0.7" stop-color="#a9c4cc" stop-opacity="0.05"/>
      <stop offset="1" stop-color="#a9c4cc" stop-opacity="0"/>
    </radialGradient>
    <linearGradient id="gReflFade" gradientUnits="userSpaceOnUse" x1="0" y1="746" x2="0" y2="1000">
      <stop offset="0" stop-color="#fff" stop-opacity="0.75"/><stop offset="1" stop-color="#fff" stop-opacity="0"/>
    </linearGradient>
    <mask id="mRefl" maskUnits="userSpaceOnUse" x="0" y="740" width="1200" height="280">
      <rect x="0" y="740" width="1200" height="280" fill="url(#gReflFade)"/>
    </mask>

    <!-- interior light -->
    <radialGradient id="gSheen">
      <stop offset="0" stop-color="#fff" stop-opacity="0.07"/><stop offset="1" stop-color="#fff" stop-opacity="0"/>
    </radialGradient>
    <radialGradient id="gTrans">
      <stop offset="0" stop-color="#ffdfae" stop-opacity="0.14"/><stop offset="1" stop-color="#ffdfae" stop-opacity="0"/>
    </radialGradient>
    <radialGradient id="gTransC">
      <stop offset="0" stop-color="#fff1da" stop-opacity="0.20"/><stop offset="1" stop-color="#fff1da" stop-opacity="0"/>
    </radialGradient>
    <radialGradient id="gInSh">
      <stop offset="0" stop-color="#000" stop-opacity="0.30"/><stop offset="1" stop-color="#000" stop-opacity="0"/>
    </radialGradient>
    <radialGradient id="gInSh2">
      <stop offset="0" stop-color="#000" stop-opacity="0.15"/><stop offset="1" stop-color="#000" stop-opacity="0"/>
    </radialGradient>

    <!-- glass body: transparent core, thick cool rim -->
    <radialGradient id="gTint">
      <stop offset="0" stop-color="#cfe8ea" stop-opacity="0.02"/>
      <stop offset="0.55" stop-color="#c2e0e4" stop-opacity="0.045"/>
      <stop offset="0.8" stop-color="#a8d2d8" stop-opacity="0.11"/>
      <stop offset="0.94" stop-color="#8fc4cf" stop-opacity="0.22"/>
      <stop offset="1" stop-color="#7fb9c8" stop-opacity="0.32"/>
    </radialGradient>
    <linearGradient id="gRim" x1="0" y1="0" x2="1" y2="1">
      <stop offset="0" stop-color="#ffffff" stop-opacity="0.95"/>
      <stop offset="0.42" stop-color="#d8ecee" stop-opacity="0.30"/>
      <stop offset="0.74" stop-color="#ffffff" stop-opacity="0.08"/>
      <stop offset="1" stop-color="#ffdfb0" stop-opacity="0.40"/>
    </linearGradient>

    <!-- film grain fades before the frame edge -->
    <radialGradient id="gMaskGrain" gradientUnits="userSpaceOnUse" cx="600" cy="420" r="680">
      <stop offset="0" stop-color="#fff"/><stop offset="0.62" stop-color="#fff"/><stop offset="1" stop-color="#000"/>
    </radialGradient>
    <mask id="mGrain" maskUnits="userSpaceOnUse" x="0" y="0" width="1200" height="860">
      <rect width="1200" height="860" fill="url(#gMaskGrain)"/>
    </mask>

    <!-- refraction: ray-bent displacement map (href baked in by JS) + softening -->
    <filter id="fRefract" filterUnits="userSpaceOnUse" x="330" y="142" width="540" height="540"
            color-interpolation-filters="sRGB">
      <feImage id="refrMap" x="330" y="142" width="540" height="540" preserveAspectRatio="none" result="map"/>
      <feDisplacementMap in="SourceGraphic" in2="map" scale="64" xChannelSelector="R" yChannelSelector="G"/>
      <feGaussianBlur stdDeviation="0.35"/>
    </filter>

    <!-- static paper tooth inside the sphere -->
    <filter id="fPaper" color-interpolation-filters="sRGB">
      <feTurbulence type="fractalNoise" baseFrequency="0.7" numOctaves="2" seed="8"/>
      <feColorMatrix type="matrix"
        values="0 0 0 0 0.35  0 0 0 0 0.30  0 0 0 0 0.24  0.35 0.35 0.35 0 -0.42"/>
    </filter>
    <!-- scene-wide film grain -->
    <filter id="fGrain" color-interpolation-filters="sRGB">
      <feTurbulence type="fractalNoise" baseFrequency="0.8" numOctaves="2" seed="4"/>
      <feColorMatrix type="matrix"
        values="0 0 0 0 0.90  0 0 0 0 0.87  0 0 0 0 0.80  0.35 0.35 0.35 0 -0.42"/>
    </filter>

    <filter id="b1" x="-60%" y="-60%" width="220%" height="220%"><feGaussianBlur stdDeviation="0.7"/></filter>
    <filter id="b2" x="-60%" y="-60%" width="220%" height="220%"><feGaussianBlur stdDeviation="1.6"/></filter>
    <filter id="b3" x="-60%" y="-60%" width="220%" height="220%"><feGaussianBlur stdDeviation="3"/></filter>
    <filter id="b4" x="-60%" y="-60%" width="220%" height="220%"><feGaussianBlur stdDeviation="4.5"/></filter>
    <filter id="b5" x="-60%" y="-60%" width="220%" height="220%"><feGaussianBlur stdDeviation="6"/></filter>
    <filter id="b6" x="-60%" y="-60%" width="220%" height="220%"><feGaussianBlur stdDeviation="8"/></filter>
    <filter id="b8" x="-60%" y="-60%" width="220%" height="220%"><feGaussianBlur stdDeviation="12"/></filter>

    <clipPath id="clipSphere"><circle cx="600" cy="412" r="270"/></clipPath>
    <rect id="specPill" x="-78" y="-27" width="156" height="54" rx="27"/>
  </defs>

  <!-- ======== environment ======== -->
  <rect width="1200" height="860" fill="url(#gBg)"/>
  <circle cx="545" cy="330" r="440" fill="url(#gGlow)"/>
  <rect x="0" y="744" width="1200" height="116" fill="url(#gGround)"/>
  <rect x="0" y="743.6" width="1200" height="1" fill="#ffe8c8" opacity="0.05"/>

  <!-- drop shadow, then caustic focused through the ball -->
  <ellipse cx="600" cy="752" rx="305" ry="42" fill="url(#gShadow)" opacity="0.85"/>
  <ellipse cx="600" cy="746" rx="150" ry="18" fill="url(#gShadow)"/>
  <ellipse cx="614" cy="743" rx="118" ry="14" fill="url(#gCaustic)" opacity="0.8"/>
  <ellipse cx="616" cy="742.5" rx="44" ry="6.5" fill="url(#gCausticC)" opacity="0.9"/>
  <ellipse cx="618" cy="742" rx="16" ry="3" fill="#fff6e6" opacity="0.9" filter="url(#b1)"/>

  <!-- floor reflection (mirrored, blurred, fading) -->
  <g mask="url(#mRefl)" opacity="0.55">
    <g transform="translate(0,1488) scale(1,-1)" filter="url(#b3)">
      <circle cx="600" cy="412" r="270" fill="url(#gRefl)"/>
      <use href="#specPill" transform="translate(487,290) rotate(-17)" fill="#ffffff" opacity="0.14"/>
      <circle cx="463" cy="267" r="10" fill="#fff" opacity="0.16"/>
    </g>
  </g>

  <!-- ======== glass interior ======== -->
  <circle cx="520" cy="345" r="235" fill="url(#gSheen)"/>
  <circle cx="676" cy="497" r="205" fill="url(#gTrans)"/>
  <circle cx="690" cy="508" r="48" fill="url(#gTransC)"/>

  <!-- crane (refracted) with its inner cast shadow -->
  <g clip-path="url(#clipSphere)">
    <ellipse cx="656" cy="476" rx="185" ry="72" fill="url(#gInSh2)"/>
    <ellipse cx="638" cy="470" rx="128" ry="50" fill="url(#gInSh)"/>
    <g id="crane" filter="url(#fRefract)"></g>
    <circle cx="600" cy="412" r="268" filter="url(#fPaper)" opacity="0.4"/>
  </g>

  <!-- ======== glass surface ======== -->
  <g clip-path="url(#clipSphere)">
    <circle cx="600" cy="412" r="270" fill="url(#gTint)"/>
    <circle cx="600" cy="412" r="251" fill="none" stroke="#07161a" stroke-opacity="0.30" stroke-width="16" filter="url(#b6)"/>
    <circle cx="600" cy="412" r="243" fill="none" stroke="#cfeef2" stroke-opacity="0.10" stroke-width="1.6"/>

    <path id="aRing"   fill="none" stroke="#ffe6bd" stroke-opacity="0.30" stroke-width="9"  filter="url(#b6)"/>
    <path id="aStUR"   fill="none" stroke="#ffffff" stroke-opacity="0.07" stroke-width="16" filter="url(#b8)"/>
    <path id="aStLL"   fill="none" stroke="#ffc98f" stroke-opacity="0.06" stroke-width="18" filter="url(#b8)"/>
    <path id="aCntSoft" fill="none" stroke="#ffd9a6" stroke-opacity="0.20" stroke-width="6" filter="url(#b5)"/>
    <path id="aCnt"    fill="none" stroke="#ffe2b8" stroke-opacity="0.55" stroke-width="1.6" stroke-linecap="round" filter="url(#b1)"/>
    <path id="aRimSoft" fill="none" stroke="#ffffff" stroke-opacity="0.30" stroke-width="8" filter="url(#b5)"/>
    <path id="aFrW"    fill="none" stroke="#ff8a50" stroke-opacity="0.26" stroke-width="1.1" filter="url(#b1)"/>
    <path id="aFrC"    fill="none" stroke="#7fd8ff" stroke-opacity="0.20" stroke-width="1"   filter="url(#b1)"/>

    <g id="specShift">
      <use href="#specPill" transform="translate(487,290) rotate(-17)" fill="#ffffff" opacity="0.30" filter="url(#b6)"/>
      <use href="#specPill" transform="translate(487,290) rotate(-17) scale(0.78)" fill="#ffffff" opacity="0.30" filter="url(#b2)"/>
      <circle cx="463" cy="267" r="10" fill="#fff" opacity="0.75" filter="url(#b2)"/>
      <circle cx="463" cy="267" r="4" fill="#fff" opacity="0.95"/>
      <use href="#specPill" transform="translate(716,540) rotate(-17)" fill="#ffe9c8" opacity="0.10" filter="url(#b5)"/>
      <circle cx="748" cy="300" r="2.2" fill="#fff" opacity="0.45"/>
    </g>

    <path id="aRimMain" fill="none" stroke="#ffffff" stroke-opacity="0.9" stroke-width="2.4" stroke-linecap="round" filter="url(#b1)"/>
  </g>

  <path id="aOutGlow" fill="none" stroke="#ffffff" stroke-opacity="0.16" stroke-width="3.5" filter="url(#b4)"/>
  <circle cx="600" cy="412" r="270" fill="none" stroke="url(#gRim)" stroke-width="1.5" opacity="0.95"/>

  <rect width="1200" height="860" filter="url(#fGrain)" mask="url(#mGrain)" opacity="0.35"/>
</svg>

<div class="corner tl">Soda-lime glass · n 1.52</div>
<div class="corner tr">Kami 60 g/m² · 28 facets</div>

<div class="plate">
  <div class="rule"></div>
  <div class="over">Still life · glass &amp; paper</div>
  <h1>Folded Light</h1>
  <div class="hint">
    <svg width="11" height="11" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2"
         stroke-linecap="round" stroke-linejoin="round"><path d="M21 12a9 9 0 1 1-2.9-6.6"/><polyline points="21 3 21 9 15 9"/></svg>
    <span>Drag to turn the crane</span>
  </div>
</div>
</div>

<script>
(()=>{
const $=id=>document.getElementById(id);
const CX=600,CY=412,R=270;
const clamp=(v,a,b)=>v<a?a:v>b?b:v;

/* ---------- rim / reflection arc paths ---------- */
const T=Math.PI/180;
const arc=(r,a0,a1)=>{
  const x0=CX+r*Math.cos(a0*T),y0=CY+r*Math.sin(a0*T),
        x1=CX+r*Math.cos(a1*T),y1=CY+r*Math.sin(a1*T);
  return `M ${x0.toFixed(1)} ${y0.toFixed(1)} A ${r} ${r} 0 ${a1-a0>180?1:0} 1 ${x1.toFixed(1)} ${y1.toFixed(1)}`;
};
const ARCS={aRimSoft:[262,168,292],aRimMain:[267,170,290],aCntSoft:[260,8,112],aCnt:[266,14,104],
            aFrW:[268.6,172,288],aFrC:[265.4,176,284],aRing:[212,14,106],
            aStUR:[195,298,342],aStLL:[190,118,162],aOutGlow:[272.5,175,285]};
for(const k in ARCS){const[r,a,b]=ARCS[k];$(k).setAttribute('d',arc(r,a,b));}

/* ---------- refraction map ---------- */
(()=>{
  const S=540,cv=document.createElement('canvas');cv.width=cv.height=S;
  const ctx=cv.getContext('2d'),im=ctx.createImageData(S,S),d=im.data;
  const eta=1/1.32,K=64,GAIN=0.62,PLANE=-0.03;
  for(let py=0;py<S;py++){
    const v=(py+0.5)/S*2-1;
    for(let px=0;px<S;px++){
      const u=(px+0.5)/S*2-1,i=(py*S+px)*4;
      let ox=0,oy=0;const r2=u*u+v*v;
      if(r2<1){
        const z=Math.sqrt(1-r2),k=1-eta*eta*(1-z*z);
        if(k>0){
          const cT=Math.sqrt(k),f=eta*z-cT;
          const tx=f*u,ty=f*v,tz=-eta+f*z,s=(PLANE-z)/tz;
          ox=s*tx*R*GAIN; oy=s*ty*R*GAIN;
        }
      }
      d[i]  =clamp(128+ox*255/K,0,255);
      d[i+1]=clamp(128+oy*255/K,0,255);
      d[i+2]=128;d[i+3]=255;
    }
  }
  ctx.putImageData(im,0,0);
  $('refrMap').setAttribute('href',cv.toDataURL());
})();

/* ---------- origami crane: hand-built 3D mesh ---------- */
const VT={
  Ct:[0.02,0.62,0],  Cf:[0.62,0.18,0],  Cb:[-0.62,0.22,0], Cq:[0.02,-0.50,0],
  Nt:[1.30,0.66,0],  Ht:[1.45,0.80,0.05], Hm:[1.52,0.68,0.03], Bk:[1.63,0.54,0],
  Tt:[-1.42,0.95,0], Pn:[0.00,0.20,0.30],
  W1:[0.34,0.72,0.62], W2:[-0.38,0.78,0.68], Tw:[-0.16,1.42,1.10],
  A1:[0.46,0.06,0.05], A2:[0.12,-0.38,0.05], Am:[0.88,0.36,0.10],
  B1:[-0.12,-0.38,0.05], B2:[-0.46,0.06,0.05], Bm:[-0.82,0.33,0.10]
};
for(const k in VT){const v=VT[k];VT['m'+k]=[v[0],v[1],-v[2]];}

const FACES=[
  ['Ct','Cf','Pn',0,0],['Cf','Cq','Pn',0,0],['Cq','Cb','Pn',0,0],['Cb','Ct','Pn',0,0],
  ['Cf','Pn','W1',1,0.02],['Cf','W1','Tw',1,0.02],['Pn','Cb','W2',1,0.02],['Pn','W2','Tw',1,0.02],
  ['A1','Am','A2',2,0.01],['Am','Nt','A2',2,0.01],
  ['B1','Bm','B2',3,0.01],['Bm','Tt','B2',3,0.01],
  ['Nt','Hm','Bk',4,0.03],['Hm','Ht','Bk',4,0.03],
  ['mCt','mCf','mPn',0,0],['mCf','mCq','mPn',0,0],['mCq','mCb','mPn',0,0],['mCb','mCt','mPn',0,0],
  ['mCf','mPn','mW1',1,-0.02],['mCf','mW1','mTw',1,-0.02],['mPn','mCb','mW2',1,-0.02],['mPn','mW2','mTw',1,-0.02],
  ['mA1','mAm','mA2',2,-0.01],['mAm','mNt','mA2',2,-0.01],
  ['mB1','mBm','mB2',3,-0.01],['mBm','mTt','mB2',3,-0.01],
  ['mNt','mHm','mBk',4,-0.03],['mHm','mHt','mBk',4,-0.03]
];

const CREASES=[
  ['Cf','W1',4],['Pn','W2',6],['mCf','mW1',18],['mPn','mW2',20],
  ['Cf','Ct',0],['Ct','Cb',3],['mCf','mCt',14],['mCt','mCb',17]
];

const PX=0.08,PY=0.42,PZ=0,FOC=7.5,SC=R*0.362;
const n3=(x,y,z)=>{const l=Math.hypot(x,y,z)||1;return[x/l,y/l,z/l];};
const L =n3(-0.55, 0.72,0.42);
const LF=n3( 0.65,-0.30,0.45);
const H =n3(L[0],L[1],L[2]+1);
let LSX=L[0],LSY=-L[1];{const l=Math.hypot(LSX,LSY);LSX/=l;LSY/=l;}

function shade(n,back){
  const dl=Math.max(n[0]*L[0]+n[1]*L[1]+n[2]*L[2],0);
  const fl=Math.max(n[0]*LF[0]+n[1]*LF[1]+n[2]*LF[2],0);
  const sp=Math.pow(Math.max(n[0]*H[0]+n[1]*H[1]+n[2]*H[2],0),26);
  const b=back?[236,225,203]:[250,245,233];
  const s=0.40+0.60*dl;
  return[Math.min(255,b[0]*s+fl*22+sp*72),
         Math.min(255,b[1]*s+fl*24+sp*72),
         Math.min(255,b[2]*s+fl*30+sp*72)];
}

let yaw=-0.55,pitch=0.16,vy=0,vp=0,drag=false,lx=0,ly=0;
const crane=$('crane'),specShift=$('specShift'),scene=$('scene'),stage=$('stage');
const reduce=matchMedia('(prefers-reduced-motion: reduce)').matches;

function render(){
  const cyw=Math.cos(yaw),syw=Math.sin(yaw),cp=Math.cos(pitch),sp=Math.sin(pitch);
  const P={};
  for(const k in VT){
    const v=VT[k],x=v[0]-PX,y=v[1]-PY,z=v[2]-PZ;
    const x1=x*cyw+z*syw, z1=z*cyw-x*syw;
    const y2=y*cp-z1*sp,  z2=y*sp+z1*cp;
    const pe=FOC/(FOC-z2);
    P[k]=[x1,y2,z2, CX+x1*pe*SC, CY-y2*pe*SC];
  }
  const N=FACES.map(f=>{
    const a=P[f[0]],b=P[f[1]],c=P[f[2]];
    const ux=b[0]-a[0],uy=b[1]-a[1],uz=b[2]-a[2];
    const vx=c[0]-a[0],wy=c[1]-a[1],wz=c[2]-a[2];
    let nx=uy*wz-uz*wy, ny=uz*vx-ux*wz, nz=ux*wy-uy*vx;
    const l=Math.hypot(nx,ny,nz)||1;nx/=l;ny/=l;nz/=l;
    let back=false;if(nz<0){nx=-nx;ny=-ny;nz=-nz;back=true;}
    return{n:[nx,ny,nz],back,d:(a[2]+b[2]+c[2])/3+f[4]};
  });
  const order=[...FACES.keys()].sort((p,q)=>N[p].d-N[q].d);
  const defs=[],body=[];
  const st='stroke="rgba(56,42,26,0.20)" stroke-width="0.8" stroke-linejoin="round"';
  for(const i of order){
    const f=FACES[i],a=P[f[0]],b=P[f[1]],c=P[f[2]];
    const col=shade(N[i].n,N[i].back).map(Math.round);
    const pts=`${a[3].toFixed(1)},${a[4].toFixed(1)} ${b[3].toFixed(1)},${b[4].toFixed(1)} ${c[3].toFixed(1)},${c[4].toFixed(1)}`;
    const vs=[a,b,c];let iM=0,iN=0,tM=-1e18,tN=1e18;
    vs.forEach((v,vi)=>{const t=v[3]*LSX+v[4]*LSY;if(t>tM){tM=t;iM=vi;}if(t<tN){tN=t;iN=vi;}});
    if(tM-tN<1.5){
      body.push(`<polygon points="${pts}" fill="rgb(${col})" ${st}/>`);
    }else{
      const A=vs[iM],B=vs[iN];
      const c1=col.map(x=>Math.min(255,Math.round(x*1.05+5)));
      const c2=col.map(x=>Math.max(0,Math.round(x*0.85-6)));
      defs.push(`<linearGradient id="f${i}" gradientUnits="userSpaceOnUse" x1="${A[3].toFixed(1)}" y1="${A[4].toFixed(1)}" x2="${B[3].toFixed(1)}" y2="${B[4].toFixed(1)}"><stop offset="0" stop-color="rgb(${c1})"/><stop offset="1" stop-color="rgb(${c2})"/></linearGradient>`);
      body.push(`<polygon points="${pts}" fill="url(#f${i})" ${st}/>`);
    }
  }
  for(const cr of CREASES){
    const nn=N[cr[2]];
    if(nn&&!nn.back&&nn.n[2]>0.12){
      const p=P[cr[0]],q=P[cr[1]];
      body.push(`<line x1="${p[3].toFixed(1)}" y1="${p[4].toFixed(1)}" x2="${q[3].toFixed(1)}" y2="${q[4].toFixed(1)}" stroke="rgba(255,252,240,0.10)" stroke-width="1.2" stroke-linecap="round"/>`);
    }
  }
  crane.innerHTML=`<defs>${defs.join('')}</defs>${body.join('')}`;
  specShift.setAttribute('transform',`translate(${(Math.sin(yaw)*6).toFixed(1)} ${(Math.sin(pitch)*3).toFixed(1)})`);
}

/* ---------- interaction: drag to turn, inertia, idle drift ---------- */
scene.addEventListener('pointerdown',e=>{
  drag=true;vy=vp=0;lx=e.clientX;ly=e.clientY;
  scene.setPointerCapture(e.pointerId);
  scene.classList.add('dragging');stage.classList.add('dragged');
});
scene.addEventListener('pointermove',e=>{
  if(!drag)return;
  const dx=e.clientX-lx,dy=e.clientY-ly;lx=e.clientX;ly=e.clientY;
  yaw+=dx*0.0085;pitch=clamp(pitch+dy*0.006,-0.55,0.6);
  vy=clamp(vy*0.5+dx*0.0085*0.5,-0.09,0.09);
  vp=vp*0.5+dy*0.006*0.5;
});
const endDrag=()=>{drag=false;scene.classList.remove('dragging');};
scene.addEventListener('pointerup',endDrag);
scene.addEventListener('pointercancel',endDrag);
addEventListener('keydown',e=>{
  if(e.key==='ArrowLeft')vy=clamp(vy-0.012,-0.09,0.09);
  else if(e.key==='ArrowRight')vy=clamp(vy+0.012,-0.09,0.09);
  else if(e.key==='ArrowUp')pitch=clamp(pitch+0.06,-0.55,0.6);
  else if(e.key==='ArrowDown')pitch=clamp(pitch-0.06,-0.55,0.6);
  else return;
  e.preventDefault();
});

(function loop(){
  if(!drag){
    yaw+=vy;pitch=clamp(pitch+vp,-0.55,0.6);
    vy*=0.94;vp*=0.90;
    pitch+=(0.16-pitch)*0.012;
    if(!reduce&&Math.abs(vy)<0.0025)yaw+=0.0032;
  }
  render();
  requestAnimationFrame(loop);
})();
})();
</script>
</body>
</html>
Evaluation: The vector handling and geometric precision here are top tier. The subtle radial gradients, refractive highlights along the spherical curvature, and internal reflections capture genuine depth without visual artifacts.

Test 2: 3D Procedural Globe Generation

Next, we test procedural 3D world synthesis with Three.js — generating a seamless seeded value-noise terrain globe with dynamic atmosphere shaders, axial controls, and orbital particle rings:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1"/>
<title>Terra Synthetica — Procedural Globe</title>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Fraunces:ital,opsz,wght@1,9..144,300..600&family=IBM+Plex+Mono:wght@400;500&display=swap" rel="stylesheet">
<style>
  :root{
    --bg:#050608;
    --ink:#e9e4d8;
    --dim:rgba(233,228,216,.42);
    --accent:#e2aa4f;
    --hair:rgba(233,228,216,.14);
  }
  *{margin:0;padding:0;box-sizing:border-box}
  html,body{height:100%;overflow:hidden;background:var(--bg)}
  body{font-family:'IBM Plex Mono',monospace;color:var(--ink)}
  #scene{position:fixed;inset:0}
  #scene canvas{display:block}

  /* ---------- HUD ---------- */
  .hud{position:fixed;z-index:5;user-select:none;-webkit-user-select:none}
  .hud-top{top:30px;left:34px;pointer-events:none}
  .eyebrow{font-size:10px;letter-spacing:.3em;color:var(--accent)}
  h1{font-family:'Fraunces',serif;font-weight:380;font-style:italic;
     font-size:clamp(30px,4.4vw,46px);line-height:1.05;margin-top:10px;color:var(--ink)}
  .sub{margin-top:9px;font-size:9px;letter-spacing:.22em;color:var(--dim)}

  .hud-bottom{left:0;right:0;bottom:0;display:flex;align-items:flex-end;
     justify-content:space-between;gap:26px;flex-wrap:wrap;
     padding:16px 34px 18px;border-top:1px solid var(--hair);
     background:rgba(5,6,8,.35);backdrop-filter:blur(9px);-webkit-backdrop-filter:blur(9px)}
  .readouts{display:flex;gap:36px}
  .ro .lbl{font-size:9px;letter-spacing:.24em;color:var(--dim);margin-bottom:6px}
  .ro .val{font-size:15px;font-variant-numeric:tabular-nums;color:var(--ink)}
  .ro .val b{font-weight:400;color:var(--accent)}

  .ctrl{display:flex;align-items:center;gap:18px;flex:1;min-width:260px;max-width:420px}
  .ctrl .lbl{font-size:9px;letter-spacing:.24em;color:var(--dim);white-space:nowrap}
  .ctrl .val{font-size:12px;color:var(--accent);min-width:64px;text-align:right;
     font-variant-numeric:tabular-nums}

  input[type=range]{-webkit-appearance:none;appearance:none;flex:1;height:20px;
     background:transparent;cursor:pointer;--fill:34%}
  input[type=range]:focus{outline:none}
  input[type=range]::-webkit-slider-runnable-track{height:2px;border-radius:1px;
     background:linear-gradient(to right,var(--accent) var(--fill),rgba(233,228,216,.18) var(--fill))}
  input[type=range]::-webkit-slider-thumb{-webkit-appearance:none;width:13px;height:13px;
     border-radius:50%;background:var(--bg);border:1.5px solid var(--accent);
     margin-top:-5.5px;box-shadow:0 0 0 3px rgba(226,170,79,.14)}
  input[type=range]::-moz-range-track{height:2px;background:rgba(233,228,216,.18)}
  input[type=range]::-moz-range-progress{height:2px;background:var(--accent)}
  input[type=range]::-moz-range-thumb{width:11px;height:11px;border-radius:50%;
     background:var(--bg);border:1.5px solid var(--accent)}

  .hint{position:fixed;left:50%;bottom:92px;transform:translateX(-50%);z-index:4;
     font-size:9px;letter-spacing:.24em;color:var(--dim);text-transform:uppercase;
     pointer-events:none;white-space:nowrap}

  .vignette{position:fixed;inset:0;z-index:2;pointer-events:none;
     background:radial-gradient(120% 92% at 50% 42%,transparent 56%,rgba(0,0,0,.42) 100%)}

  /* ---------- loading veil ---------- */
  #veil{position:fixed;inset:0;z-index:20;background:var(--bg);
     display:flex;flex-direction:column;align-items:center;justify-content:center;gap:20px;
     transition:opacity .7s ease}
  #veil.done{opacity:0;pointer-events:none}
  #veil .vt{font-family:'Fraunces',serif;font-style:italic;font-weight:380;font-size:22px}
  #veil .vs{font-size:9px;letter-spacing:.3em;color:var(--dim)}
  #vbar{width:190px;height:1px;background:rgba(233,228,216,.14);position:relative}
  #vbar i{position:absolute;left:0;top:-.5px;height:2px;width:0%;background:var(--accent)}
  #vpct{font-size:10px;letter-spacing:.24em;color:var(--accent)}

  @media(max-width:720px){
    .hud-top{top:20px;left:20px}
    .sub{display:none}
    .readouts{gap:20px}
    .hud-bottom{padding:12px 20px 14px;gap:14px}
    .hint{bottom:118px}
  }
</style>
</head>
<body>

<div id="scene"></div>
<div class="vignette"></div>

<header class="hud hud-top">
  <div class="eyebrow">PROCEDURAL BODY · <span id="seed">SEED ----</span></div>
  <h1>Terra Synthetica</h1>
  <div class="sub">VALUE-NOISE TERRAIN — SYNTHESIZED LOCALLY IN YOUR BROWSER</div>
</header>

<div class="hint">drag to spin · scroll / pinch to zoom · double-click to reset</div>

<footer class="hud hud-bottom">
  <div class="readouts">
    <div class="ro"><div class="lbl">AXIAL SPIN</div><div class="val"><b id="roSpin">0.0</b> °/s</div></div>
    <div class="ro"><div class="lbl">CAMERA RANGE</div><div class="val" id="roDist">3.40 R</div></div>
    <div class="ro"><div class="lbl">AXIAL TILT</div><div class="val" id="roTilt">0°</div></div>
  </div>
  <div class="ctrl">
    <span class="lbl">DRIFT RATE</span>
    <input type="range" id="speed" min="0" max="100" step="1" value="34" aria-label="Globe rotation speed">
    <span class="val" id="speedVal">—</span>
  </div>
</footer>

<div id="veil">
  <div class="vt">Terra Synthetica</div>
  <div id="vbar"><i></i></div>
  <div id="vpct">0%</div>
  <div class="vs">SYNTHESIZING TERRAIN FIELDS</div>
</div>

<script type="importmap">
{ "imports": { "three": "https://cdn.jsdelivr.net/npm/[email protected]/build/three.module.js" } }
</script>

<script type="module">
import * as THREE from 'three';

/* ============================================================
   1 · Seeded 3D value noise (sampled on the sphere → seamless)
============================================================ */
const SEED = 1000 + Math.floor(Math.random() * 89999);
document.getElementById('seed').textContent = 'SEED ' + SEED;

function hash3(x, y, z){
  let n = Math.imul(x, 374761393) ^ Math.imul(y, 668265263) ^ Math.imul(z, 1440662683) ^ SEED;
  n = Math.imul(n ^ (n >>> 13), 1274126177);
  n ^= n >>> 16;
  return (n >>> 0) / 4294967296;
}
const fade = t => t * t * t * (t * (t * 6 - 15) + 10);

function vnoise(x, y, z){
  const X = Math.floor(x), Y = Math.floor(y), Z = Math.floor(z);
  const u = fade(x - X), v = fade(y - Y), w = fade(z - Z);
  const c000 = hash3(X, Y, Z),         c100 = hash3(X+1, Y, Z);
  const c010 = hash3(X, Y+1, Z),       c110 = hash3(X+1, Y+1, Z);
  const c001 = hash3(X, Y, Z+1),       c101 = hash3(X+1, Y, Z+1);
  const c011 = hash3(X, Y+1, Z+1),     c111 = hash3(X+1, Y+1, Z+1);
  const x00 = c000 + (c100-c000)*u, x10 = c010 + (c110-c010)*u;
  const x01 = c001 + (c101-c001)*u, x11 = c011 + (c111-c011)*u;
  const y0 = x00 + (x10-x00)*v, y1 = x01 + (x11-x01)*v;
  return y0 + (y1-y0)*w;
}
function fbm(x, y, z, oct){
  let s = 0, a = 0.5, n = 0, f = 1;
  for(let i = 0; i < oct; i++){ s += a * vnoise(x*f, y*f, z*f); n += a; a *= 0.5; f *= 2; }
  return s / n;
}
const sm01 = t => t <= 0 ? 0 : t >= 1 ? 1 : t*t*(3-2*t);

/* ============================================================
   2 · Colour ramps
============================================================ */
const OCEAN = [
  [0.00,[42,102,104]], [0.08,[20,64,78]],
  [0.30,[10,36,50]],   [1.00,[4,12,19]]
];
const LAND = [
  [0.00,[190,172,134]], [0.035,[150,158,108]], [0.11,[92,120,74]],
  [0.30,[62,90,58]],    [0.48,[116,103,77]],   [0.66,[126,116,99]],
  [0.82,[213,209,199]], [1.00,[241,240,236]]
];
function ramp(stops, t, out){
  if(t <= stops[0][0]){ out[0]=stops[0][1][0]; out[1]=stops[0][1][1]; out[2]=stops[0][1][2]; return; }
  for(let k = 1; k < stops.length; k++){
    if(t <= stops[k][0]){
      const a = stops[k-1], b = stops[k], u = (t - a[0]) / (b[0] - a[0]);
      out[0]=a[1][0]+(b[1][0]-a[1][0])*u;
      out[1]=a[1][1]+(b[1][1]-a[1][1])*u;
      out[2]=a[1][2]+(b[1][2]-a[1][2])*u;
      return;
    }
  }
  const L = stops[stops.length-1][1];
  out[0]=L[0]; out[1]=L[1]; out[2]=L[2];
}

/* ============================================================
   3 · Procedural map synthesis (chunked so the veil can breathe)
============================================================ */
const SEA = 0.545;
const _c = [0,0,0];

async function generateMaps(onRow){
  const W = 1024, H = 512;
  const mk = () => { const c = document.createElement('canvas'); c.width=W; c.height=H; return c; };
  const cCan = mk(), sCan = mk(), bCan = mk();
  const cCtx = cCan.getContext('2d'), sCtx = sCan.getContext('2d'), bCtx = bCan.getContext('2d');
  const cI = cCtx.createImageData(W,H), sI = sCtx.createImageData(W,H), bI = bCtx.createImageData(W,H);
  const cd = cI.data, sd = sI.data, bd = bI.data;

  let row = 0;
  while(row < H){
    const t0 = performance.now();
    while(row < H && performance.now() - t0 < 14){
      const j = row++;
      const phi = ((j + 0.5) / H) * Math.PI;
      const sy = Math.sin(phi), ny = Math.cos(phi);

      for(let i = 0; i < W; i++){
        const th = ((i + 0.5) / W) * Math.PI * 2;
        const nx = sy * Math.cos(th), nz = sy * Math.sin(th);

        const q1 = fbm(nx*1.6+5.2, ny*1.6+1.3, nz*1.6+2.8, 2) - 0.5;
        const q2 = fbm(nx*1.6+9.1, ny*1.6+6.7, nz*1.6+3.9, 2) - 0.5;
        const q3 = fbm(nx*1.6+4.4, ny*1.6+8.8, nz*1.6+7.2, 2) - 0.5;
        const px = nx + q1*0.55, py = ny + q2*0.55, pz = nz + q3*0.55;

        const base = fbm(px*1.15+3.7, py*1.15+1.9, pz*1.15+8.4, 4);
        const det  = fbm(px*3.40+7.7, py*3.40+2.1, pz*3.40+5.5, 3);
        const e = base*0.66 + det*0.34;

        const idx = (j*W + i) * 4;
        let r, g, b, spec, bump;

        if(e <= SEA){
          const d = Math.min(1, (SEA - e) / (SEA * 0.62));
          ramp(OCEAN, d, _c);
          r=_c[0]; g=_c[1]; b=_c[2];
          spec = 225 - d*70; bump = 0;
        } else {
          let t = (e - SEA) / (0.97 - SEA); if(t > 1) t = 1;
          t = Math.pow(t, 0.82);
          ramp(LAND, t, _c);
          r=_c[0]; g=_c[1]; b=_c[2];

          const m = (det - 0.5) * 26; r+=m; g+=m; b+=m;
          const an = Math.abs(ny);

          if(an > 0.12 && an < 0.62){
            const moist = fbm(px*2.2+13.1, py*2.2+4.4, pz*2.2+9.9, 2);
            const band = Math.exp(-(((an-0.36)/0.14)**2)) * (1 - moist*1.4);
            if(band > 0){
              const k = Math.min(0.6, band*0.6);
              r+=(172-r)*k; g+=(150-g)*k; b+=(108-b)*k;
            }
          }
          const eff = t + Math.max(0, an - 0.55) * 1.1;
          const sk = sm01((eff - 0.72) / 0.16);
          if(sk > 0){ r+=(236-r)*sk; g+=(238-g)*sk; b+=(236-b)*sk; }

          spec = 26; bump = t*255;

          if(an > 0.78){
            const cn = fbm(px*4.0+3.3, py*4.0+6.6, pz*4.0+1.1, 2);
            const cap = sm01(((an + (cn-0.5)*0.09) - 0.86) / 0.05);
            if(cap > 0){
              r+=(226-r)*cap; g+=(233-g)*cap; b+=(238-b)*cap;
              spec += (135-spec)*cap;
              bump = bump*(1-cap) + 200*cap;
            }
          }
        }
        cd[idx]=r;   cd[idx+1]=g;   cd[idx+2]=b;   cd[idx+3]=255;
        sd[idx]=spec;sd[idx+1]=spec;sd[idx+2]=spec;sd[idx+3]=255;
        bd[idx]=bump;bd[idx+1]=bump;bd[idx+2]=bump;bd[idx+3]=255;
      }
    }
    onRow(row / H);
    await new Promise(res => requestAnimationFrame(res));
  }
  cCtx.putImageData(cI,0,0); sCtx.putImageData(sI,0,0); bCtx.putImageData(bI,0,0);
  return { cCan, sCan, bCan };
}

async function generateClouds(onRow){
  const W = 512, H = 256;
  const can = document.createElement('canvas'); can.width=W; can.height=H;
  const ctx = can.getContext('2d');
  const img = ctx.createImageData(W,H), d = img.data;
  let row = 0;
  while(row < H){
    const t0 = performance.now();
    while(row < H && performance.now() - t0 < 14){
      const j = row++;
      const phi = ((j+0.5)/H) * Math.PI;
      const sy = Math.sin(phi), ny = Math.cos(phi);
      for(let i = 0; i < W; i++){
        const th = ((i+0.5)/W) * Math.PI * 2;
        const nx = sy*Math.cos(th), nz = sy*Math.sin(th);
        const w = fbm(nx*1.3+21.7, ny*1.3+11.2, nz*1.3+5.8, 2) - 0.5;
        const px = nx + w*0.6, py = ny + w*0.6, pz = nz + w*0.6;
        const c = fbm(px*2.3, py*1.15, pz*2.3, 4);
        let a = sm01((c - 0.50) / 0.17) * 0.9 * (0.35 + 0.65*sy);
        const idx = (j*W+i)*4;
        d[idx]=250; d[idx+1]=250; d[idx+2]=252; d[idx+3]=a*255;
      }
    }
    onRow(row / H);
    await new Promise(res => requestAnimationFrame(res));
  }
  ctx.putImageData(img,0,0);
  return can;
}

let renderer;
try{
  renderer = new THREE.WebGLRenderer({ antialias:true });
}catch(err){
  document.querySelector('#veil .vs').textContent = 'WEBGL IS NOT AVAILABLE IN THIS BROWSER';
  throw err;
}
renderer.setPixelRatio(Math.min(devicePixelRatio, 2));
renderer.setSize(innerWidth, innerHeight);
renderer.toneMapping = THREE.ACESFilmicToneMapping;
renderer.toneMappingExposure = 1.12;
document.getElementById('scene').appendChild(renderer.domElement);
const MAX_ANISO = renderer.capabilities.getMaxAnisotropy();

const scene = new THREE.Scene();
scene.background = new THREE.Color(0x050608);

const camera = new THREE.PerspectiveCamera(40, innerWidth/innerHeight, 0.1, 300);
const CAM_DIR = new THREE.Vector3(0, 0.32, 1).normalize();
let dist = 3.4, targetDist = 3.4;
const par = { x:0, y:0, tx:0, ty:0 };

const sun = new THREE.DirectionalLight(0xffd9a6, 3.0);
sun.position.set(-4.5, 2.2, 2.6);
scene.add(sun);
const rimLight = new THREE.DirectionalLight(0x5f7ea6, 1.1);
rimLight.position.set(4, -1.5, -3);
scene.add(rimLight);
scene.add(new THREE.HemisphereLight(0x30414f, 0x0b0a09, 0.55));

const SUN_DIR = sun.position.clone().normalize();

const tiltGroup = new THREE.Group();
scene.add(tiltGroup);
const planet = new THREE.Group();
tiltGroup.add(planet);

const ATMO_VERT = `
  varying vec3 vN;
  varying vec3 vWN;
  void main(){
    vN  = normalize(normalMatrix * normal);
    vWN = normalize(mat3(modelMatrix) * normal);
    gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
  }`;

function atmoMaterial(color, intensity, power, back){
  return new THREE.ShaderMaterial({
    uniforms:{
      uColor:{ value:new THREE.Color(color) },
      uSunDir:{ value:SUN_DIR },
      uIntensity:{ value:intensity },
      uPow:{ value:power }
    },
    vertexShader: ATMO_VERT,
    fragmentShader: `
      uniform vec3 uColor; uniform vec3 uSunDir; uniform float uIntensity; uniform float uPow;
      varying vec3 vN; varying vec3 vWN;
      void main(){
        float f = ${back
          ? 'pow(clamp(-dot(normalize(vN), vec3(0.0,0.0,1.0)) * 1.9, 0.0, 1.0), uPow)'
          : 'pow(1.0 - abs(dot(normalize(vN), vec3(0.0,0.0,1.0))), uPow)'};
        float day = clamp(dot(normalize(vWN), uSunDir) * 0.6 + 0.45, 0.06, 1.0);
        float a = f * day * uIntensity;
        gl_FragColor = vec4(uColor * a, a);
      }`,
    side: back ? THREE.BackSide : THREE.FrontSide,
    transparent:true, depthWrite:false, blending:THREE.AdditiveBlending
  });
}

function pointsMaterial(scale, twAmp, twSpeed){
  return new THREE.ShaderMaterial({
    uniforms:{
      uTime:{ value:0 }, uScale:{ value:scale },
      uPR:{ value:renderer.getPixelRatio() },
      uTA:{ value:twAmp }, uTS:{ value:twSpeed }
    },
    vertexShader:`
      attribute float aSize; attribute float aPhase; attribute vec3 aColor;
      uniform float uTime, uScale, uPR, uTA, uTS;
      varying vec3 vC; varying float vA;
      void main(){
        vC = aColor;
        vec4 mv = modelViewMatrix * vec4(position, 1.0);
        vA = 1.0 - uTA * (0.5 + 0.5 * sin(uTime * uTS + aPhase));
        gl_PointSize = aSize * uPR * (uScale / -mv.z);
        gl_Position = projectionMatrix * mv;
      }`,
    fragmentShader:`
      varying vec3 vC; varying float vA;
      void main(){
        float d = length(gl_PointCoord - vec2(0.5));
        float a = smoothstep(0.5, 0.08, d);
        a *= a;
        gl_FragColor = vec4(vC, a * vA);
      }`,
    transparent:true, depthWrite:false, blending:THREE.AdditiveBlending
  });
}

let built = false;
let cloudsMesh = null, ringGeo = null, ringMat = null, starMat = null;
const RING_N = 3400;
const rRadius = new Float32Array(RING_N), rAngle = new Float32Array(RING_N),
      rY = new Float32Array(RING_N),     rSpeed = new Float32Array(RING_N);

function canvasTex(can, srgb){
  const t = new THREE.CanvasTexture(can);
  if(srgb) t.colorSpace = THREE.SRGBColorSpace;
  t.wrapS = THREE.RepeatWrapping;
  t.anisotropy = MAX_ANISO;
  return t;
}

function buildScene(maps, cloudCan){
  const colorTex = canvasTex(maps.cCan, true);
  const specTex  = canvasTex(maps.sCan, false);
  const bumpTex  = canvasTex(maps.bCan, false);
  const cloudTex = canvasTex(cloudCan, true);

  const globe = new THREE.Mesh(
    new THREE.SphereGeometry(1, 128, 80),
    new THREE.MeshPhongMaterial({
      map:colorTex, specularMap:specTex,
      specular:new THREE.Color(0x9fc0cc), shininess:18,
      bumpMap:bumpTex, bumpScale:0.45
    })
  );
  planet.add(globe);

  cloudsMesh = new THREE.Mesh(
    new THREE.SphereGeometry(1.012, 96, 64),
    new THREE.MeshLambertMaterial({ map:cloudTex, transparent:true, depthWrite:false })
  );
  cloudsMesh.renderOrder = 1;
  planet.add(cloudsMesh);

  const halo = new THREE.Mesh(new THREE.SphereGeometry(1.165, 96, 64), atmoMaterial(0x9ecbdd, 1.0, 3.4, true));
  const limb = new THREE.Mesh(new THREE.SphereGeometry(1.008, 96, 64), atmoMaterial(0xbcd6e4, 0.5, 4.0, false));
  halo.renderOrder = 3; limb.renderOrder = 2;
  tiltGroup.add(halo, limb);

  const pos = new Float32Array(RING_N*3), col = new Float32Array(RING_N*3);
  const siz = new Float32Array(RING_N), pha = new Float32Array(RING_N);
  const c = new THREE.Color();
  for(let i = 0; i < RING_N; i++){
    const r = 1.52 + Math.pow(Math.random(), 0.62) * 0.95;
    rRadius[i] = r;
    rAngle[i]  = Math.random() * Math.PI * 2;
    rY[i]      = (Math.random()+Math.random()+Math.random()-1.5) * 0.028 * (0.4 + r - 1.5);
    rSpeed[i]  = 0.16 * Math.pow(1.9 / r, 1.5) + 0.02;
    let s = 0.5 + Math.pow(Math.random(),2) * 2.6;
    if(Math.random() < 0.03) s *= 2.2;
    siz[i] = s; pha[i] = Math.random() * 6.2832;
    if(Math.random() < 0.07) c.setHSL(0.55 + Math.random()*0.05, 0.35, 0.72);
    else                     c.setHSL(0.095 + Math.random()*0.035, 0.6, 0.55 + Math.random()*0.22);
    col[i*3]=c.r; col[i*3+1]=c.g; col[i*3+2]=c.b;
  }
  ringGeo = new THREE.BufferGeometry();
  ringGeo.setAttribute('position', new THREE.BufferAttribute(pos, 3));
  ringGeo.setAttribute('aColor',   new THREE.BufferAttribute(col, 3));
  ringGeo.setAttribute('aSize',    new THREE.BufferAttribute(siz, 1));
  ringGeo.setAttribute('aPhase',   new THREE.BufferAttribute(pha, 1));
  ringMat = pointsMaterial(7.0, 0.35, 1.6);
  const ring = new THREE.Points(ringGeo, ringMat);
  const ringGroup = new THREE.Group();
  ringGroup.rotation.set(0.42, 0, -0.16);
  ringGroup.add(ring);
  tiltGroup.add(ringGroup);

  const SN = 1100;
  const sp = new Float32Array(SN*3), sc = new Float32Array(SN*3),
        ss = new Float32Array(SN), sph = new Float32Array(SN);
  const v = new THREE.Vector3();
  for(let i = 0; i < SN; i++){
    v.set(Math.random()*2-1, Math.random()*2-1, Math.random()*2-1).normalize().multiplyScalar(40 + Math.random()*50);
    sp[i*3]=v.x; sp[i*3+1]=v.y; sp[i*3+2]=v.z;
    ss[i] = 0.5 + Math.pow(Math.random(),2)*1.4;
    sph[i] = Math.random()*6.2832;
    const w = Math.random();
    if(w < 0.12)      c.setHSL(0.10, 0.5, 0.72);
    else if(w < 0.24) c.setHSL(0.58, 0.35, 0.74);
    else              c.setHSL(0, 0, 0.5 + Math.random()*0.35);
    sc[i*3]=c.r; sc[i*3+1]=c.g; sc[i*3+2]=c.b;
  }
  const sg = new THREE.BufferGeometry();
  sg.setAttribute('position', new THREE.BufferAttribute(sp, 3));
  sg.setAttribute('aColor',   new THREE.BufferAttribute(sc, 3));
  sg.setAttribute('aSize',    new THREE.BufferAttribute(ss, 1));
  sg.setAttribute('aPhase',   new THREE.BufferAttribute(sph, 1));
  starMat = pointsMaterial(90, 0.5, 0.8);
  scene.add(new THREE.Points(sg, starMat));

  built = true;
}

let baseSpeed = 0, spinVel = 0, dragging = false;
let tiltCur = 0, tiltTgt = 0;
const el = renderer.domElement;
el.style.touchAction = 'none';

const ptrs = new Map();
let lastX = 0, lastY = 0, lastT = 0, pinchD = 0;
const pinchDist = () => {
  const a = [...ptrs.values()];
  return Math.hypot(a[0].x - a[1].x, a[0].y - a[1].y);
};

el.addEventListener('pointerdown', e => {
  el.setPointerCapture(e.pointerId);
  ptrs.set(e.pointerId, { x:e.clientX, y:e.clientY });
  if(ptrs.size === 1){
    dragging = true; spinVel = 0;
    lastX = e.clientX; lastY = e.clientY; lastT = performance.now();
  } else if(ptrs.size === 2){
    dragging = false; pinchD = pinchDist();
  }
});

el.addEventListener('pointermove', e => {
  par.tx =  (e.clientX / innerWidth  - 0.5) * 0.16;
  par.ty = -(e.clientY / innerHeight - 0.5) * 0.10;
  if(!ptrs.has(e.pointerId)) return;
  const p = ptrs.get(e.pointerId);
  p.x = e.clientX; p.y = e.clientY;

  if(ptrs.size === 2){
    const nd = pinchDist();
    if(pinchD > 0) targetDist = THREE.MathUtils.clamp(targetDist * pinchD / nd, 1.9, 8);
    pinchD = nd;
    return;
  }
  if(!dragging) return;

  const now = performance.now();
  const dx = e.clientX - lastX, dy = e.clientY - lastY;
  const dtm = Math.max(now - lastT, 1) / 1000;
  planet.rotation.y += dx * 0.0042;
  spinVel = spinVel * 0.55 + THREE.MathUtils.clamp(dx * 0.0042 / dtm, -8, 8) * 0.45;
  tiltTgt = THREE.MathUtils.clamp(tiltTgt + dy * 0.0028, -1.25, 1.25);
  lastX = e.clientX; lastY = e.clientY; lastT = now;
});

const endPtr = e => {
  ptrs.delete(e.pointerId);
  if(ptrs.size === 0) dragging = false;
  else if(ptrs.size === 1){
    const p = [...ptrs.values()][0];
    dragging = true; lastX = p.x; lastY = p.y; lastT = performance.now();
  }
};
el.addEventListener('pointerup', endPtr);
el.addEventListener('pointercancel', endPtr);

el.addEventListener('wheel', e => {
  e.preventDefault();
  targetDist = THREE.MathUtils.clamp(targetDist * Math.exp(e.deltaY * 0.0011), 1.9, 8);
}, { passive:false });

el.addEventListener('dblclick', () => { tiltTgt = 0; targetDist = 3.4; spinVel = 0; });

const slider = document.getElementById('speed');
const speedVal = document.getElementById('speedVal');
function applySlider(){
  const v = +slider.value;
  baseSpeed = Math.pow(v / 100, 1.55) * 1.5;
  speedVal.textContent = (baseSpeed * 57.29578).toFixed(1) + ' °/s';
  slider.style.setProperty('--fill', v + '%');
}
slider.addEventListener('input', applySlider);
applySlider();

const clock = new THREE.Clock();
const roSpin = document.getElementById('roSpin'),
      roDist = document.getElementById('roDist'),
      roTilt = document.getElementById('roTilt');
let prevRotY = 0, frame = 0;

function tick(){
  requestAnimationFrame(tick);
  if(!built) return;
  const dt = Math.min(clock.getDelta(), 0.05);
  const t = clock.elapsedTime;

  if(!dragging){
    spinVel *= Math.exp(-dt * 0.85);
    if(Math.abs(spinVel) < 0.0004) spinVel = 0;
    planet.rotation.y += (baseSpeed + spinVel) * dt;
    cloudsMesh.rotation.y += (baseSpeed + spinVel) * dt * 0.14;
  }
  tiltCur += (tiltTgt - tiltCur) * (1 - Math.exp(-dt * 7));
  tiltGroup.rotation.x = tiltCur;

  const pa = ringGeo.attributes.position.array;
  for(let i = 0; i < RING_N; i++){
    const a = rAngle[i] + t * rSpeed[i];
    pa[i*3]   = rRadius[i] * Math.cos(a);
    pa[i*3+1] = rY[i];
    pa[i*3+2] = rRadius[i] * Math.sin(a);
  }
  ringGeo.attributes.position.needsUpdate = true;
  ringMat.uniforms.uTime.value = t;
  starMat.uniforms.uTime.value = t;

  dist += (targetDist - dist) * (1 - Math.exp(-dt * 5));
  par.x += (par.tx - par.x) * (1 - Math.exp(-dt * 3));
  par.y += (par.ty - par.y) * (1 - Math.exp(-dt * 3));
  camera.position.set(CAM_DIR.x*dist + par.x, CAM_DIR.y*dist + par.y, CAM_DIR.z*dist);
  camera.lookAt(0, 0, 0);

  renderer.render(scene, camera);

  if(++frame % 5 === 0){
    const spinNow = (planet.rotation.y - prevRotY) / Math.max(dt, 1e-4);
    prevRotY = planet.rotation.y;
    roSpin.textContent = (spinNow * 57.29578).toFixed(1);
    roDist.textContent = dist.toFixed(2) + ' R';
    roTilt.textContent = Math.round(tiltCur * 57.29578) + '°';
  }
}

addEventListener('resize', () => {
  camera.aspect = innerWidth / innerHeight;
  camera.updateProjectionMatrix();
  renderer.setSize(innerWidth, innerHeight);
  const pr = Math.min(devicePixelRatio, 2);
  renderer.setPixelRatio(pr);
  if(ringMat){ ringMat.uniforms.uPR.value = pr; }
  if(starMat){ starMat.uniforms.uPR.value = pr; }
});

const veil = document.getElementById('veil'),
      vbar = document.querySelector('#vbar i'),
      vpct = document.getElementById('vpct');
const setProgress = p => {
  vbar.style.width = (p*100).toFixed(1) + '%';
  vpct.textContent = Math.round(p*100) + '%';
};

(async () => {
  setProgress(0.02);
  const maps = await generateMaps(p => setProgress(p * 0.78));
  const cloudCan = await generateClouds(p => setProgress(0.78 + p * 0.22));
  buildScene(maps, cloudCan);
  requestAnimationFrame(tick);
  veil.classList.add('done');
  setTimeout(() => veil.remove(), 900);
})();
</script>
</body>
</html>
Evaluation: Outstanding shader craftsmanship. The asynchronous chunked terrain field synthesis prevents UI locking, while the custom atmospheric Fresnel shaders and particle orbits render cleanly at a smooth 60 FPS.

Test 3: 3D Low-Poly Wizard Adventure Game

Finally, our toughest single-file real-time game prompt:
> "Create a fully functional, browser-based 3D third-person action-adventure game using Three.js inside a single self-contained HTML file, featuring a low-poly wizard exploring a vibrant floating island archipelago with bright pastel colors, dynamic day-night lighting, and environmental particle effects. Implement smooth WASD movement, spacebar jumping, and mouse-drag camera controls, complete with responsive collision detection, a dynamic camera-follow script, and an objective where the player collects glowing crystal artifacts while dodging automated elemental turrets. Include a clean user interface with a real-time score and health HUD, basic Web Audio API sound effects for jumping and collecting items, and a seamless game-over and restart system."
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Skyshard Isles</title>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link href="https://fonts.googleapis.com/css2?family=MedievalSharp&family=Nunito+Sans:wght@400;600;800&display=swap" rel="stylesheet">
<style>
  :root{
    --ink:#10142a; --line:rgba(255,240,210,.18); --cream:#f6f1e3;
    --gold:#e9bd63; --aqua:#7ef0d4; --danger:#ff6b81;
  }
  *{margin:0;padding:0;box-sizing:border-box}
  html,body{height:100%;overflow:hidden;background:#161b38}
  body{font-family:'Nunito Sans',sans-serif;color:var(--cream)}
  canvas{display:block}

  /* ---------- HUD ---------- */
  #hud{position:fixed;inset:0;pointer-events:none;z-index:5}
  #hearts{position:absolute;top:18px;left:20px;display:flex;gap:5px;filter:drop-shadow(0 2px 3px rgba(8,10,25,.55))}
  .heart{transition:transform .25s}
  .heart svg path{fill:#ff6b81;stroke:#5e1626;stroke-width:1.6;transition:fill .25s,stroke .25s}
  .heart.lost{transform:scale(.82)}
  .heart.lost svg path{fill:rgba(255,255,255,.06);stroke:rgba(255,255,255,.25)}

  #rightCluster{position:absolute;top:18px;right:20px;display:flex;flex-direction:column;align-items:flex-end;gap:9px}
  .chip{background:rgba(12,16,34,.55);border:1px solid var(--line);backdrop-filter:blur(6px);
        padding:7px 13px;border-radius:11px;display:flex;gap:9px;align-items:center}
  #gemChip{font-weight:800;letter-spacing:.06em;font-size:15px}
  #gemChip.pop{animation:gpop .35s ease}
  @keyframes gpop{40%{transform:scale(1.18)}}
  #row{display:flex;gap:9px;align-items:center}
  #muteBtn{pointer-events:auto;cursor:pointer;color:var(--cream);padding:7px 9px}
  #muteBtn:hover{border-color:var(--gold)}
  #muteBtn svg{display:block}

  #dial{position:relative;width:44px;height:44px;border-radius:50%;border:1px solid var(--line);
        background:rgba(10,14,30,.55);flex:none}
  #dialRot{position:absolute;inset:0}
  .dsun{position:absolute;left:50%;top:3px;width:9px;height:9px;margin-left:-4.5px;border-radius:50%;background:#ffd98a}
  .dmoon{position:absolute;left:50%;bottom:3px;width:7px;height:7px;margin-left:-3.5px;border-radius:50%;background:#cdd6f4}
  .dhz{position:absolute;left:6px;right:6px;top:50%;height:1px;background:var(--line)}

  #hint{position:absolute;bottom:22px;left:50%;transform:translateX(-50%);
        font-size:13px;letter-spacing:.03em;transition:opacity 1.2s;white-space:nowrap}
  #hint.gone{opacity:0}
  kbd{font-family:inherit;font-size:11.5px;font-weight:800;background:rgba(255,255,255,.09);
      border:1px solid rgba(255,255,255,.28);border-bottom-width:2px;border-radius:6px;
      padding:2px 7px;margin:0 2px}

  #floatLayer{position:absolute;inset:0;overflow:hidden}
  .floater{position:absolute;font-family:'MedievalSharp',serif;font-size:22px;color:#8ff5dd;
           text-shadow:0 2px 0 rgba(10,20,30,.65);transform:translate(-50%,-50%);
           animation:flo .95s ease-out forwards;pointer-events:none}
  .floater.bad{color:#ff8d9d}
  @keyframes flo{0%{opacity:0;margin-top:8px}15%{opacity:1}100%{opacity:0;margin-top:-52px}}

  #vigFlash,#vigLow{position:absolute;inset:0;pointer-events:none;opacity:0;
     background:radial-gradient(ellipse at center,transparent 52%,rgba(255,58,58,.42) 100%)}
  #vigFlash.flash{animation:vfl .55s ease-out}
  @keyframes vfl{0%{opacity:1}100%{opacity:0}}
  #vigLow.low{animation:vlo 1.5s ease-in-out infinite}
  @keyframes vlo{0%,100%{opacity:.10}50%{opacity:.38}}

  /* ---------- Overlays ---------- */
  .overlay{position:fixed;inset:0;z-index:10;display:flex;align-items:center;justify-content:center;
           opacity:0;pointer-events:none;transition:opacity .4s}
  .overlay.show{opacity:1;pointer-events:auto}
  .panel{position:relative;max-width:540px;width:min(92vw,540px);text-align:center;
         background:rgba(15,19,40,.88);border:1px solid rgba(233,189,99,.42);
         backdrop-filter:blur(9px);padding:38px 44px 34px;box-shadow:0 24px 70px rgba(5,8,20,.6)}
  .panel::before,.panel::after{content:"";position:absolute;width:9px;height:9px;background:var(--gold);transform:rotate(45deg)}
  .panel::before{top:11px;left:11px}
  .panel::after{bottom:11px;right:11px}
  h1{font-family:'MedievalSharp',serif;font-weight:400;font-size:clamp(30px,5vw,44px);
     letter-spacing:.10em;color:var(--cream);text-shadow:0 3px 0 rgba(5,8,20,.55)}
  .tag{margin:14px auto 4px;max-width:400px;font-size:14.5px;line-height:1.55;color:rgba(246,241,227,.82)}
  .orn{display:flex;align-items:center;justify-content:center;gap:10px;margin:18px 0}
  .orn i{height:1px;width:74px;background:linear-gradient(90deg,transparent,var(--gold));display:block}
  .orn i:last-child{transform:scaleX(-1)}
  .orn b{width:7px;height:7px;background:var(--gold);transform:rotate(45deg);display:block}
  .ctrs{display:grid;grid-template-columns:auto auto;gap:9px 22px;justify-content:center;
        margin:4px 0 22px;font-size:13.5px}
  .ctrs span:nth-child(odd){text-align:right;color:rgba(246,241,227,.72);align-self:center}
  .ctrs span:nth-child(even){text-align:left}
  .btn{pointer-events:auto;cursor:pointer;font-family:'MedievalSharp',serif;font-size:19px;letter-spacing:.08em;
       color:#241a08;background:var(--gold);border:none;padding:13px 40px;
       box-shadow:4px 4px 0 rgba(5,8,20,.55);transition:transform .12s,box-shadow .12s}
  .btn:hover{transform:translate(-2px,-2px);box-shadow:6px 6px 0 rgba(5,8,20,.55)}
  .btn:active{transform:translate(2px,2px);box-shadow:1px 1px 0 rgba(5,8,20,.55)}
  .foot{margin-top:16px;font-size:11.5px;letter-spacing:.08em;color:rgba(246,241,227,.45)}
  .stats{font-size:15px;letter-spacing:.05em;color:var(--aqua);margin:6px 0 22px}
  #deadMsg{color:rgba(246,241,227,.8)}
</style>
</head>
<body>

<div id="hud">
  <div id="hearts"></div>
  <div id="rightCluster">
    <div class="chip" id="gemChip">
      <svg viewBox="0 0 24 24" width="19" height="19"><path d="M12 2 2 9.5 12 22 22 9.5Z" fill="#7ef0d4" stroke="#0e5c4a" stroke-width="1.4"/><path d="M2 9.5h20M12 2 7.5 9.5 12 22l4.5-12.5Z" fill="none" stroke="#0e5c4a" stroke-width="1"/></svg>
      <span id="gemText">0 / 12</span>
    </div>
    <div id="row">
      <div id="dial"><div id="dialRot"><i class="dsun"></i><i class="dmoon"></i></div><i class="dhz"></i></div>
      <div class="chip" id="muteBtn" title="Toggle sound (M)"></div>
    </div>
  </div>
  <div id="hint"><kbd>W</kbd><kbd>A</kbd><kbd>S</kbd><kbd>D</kbd> move&nbsp;&nbsp;<kbd>Space</kbd> jump&nbsp;&nbsp;<kbd>Drag</kbd> look&nbsp;&nbsp;<kbd>Scroll</kbd> zoom</div>
  <div id="floatLayer"></div>
  <div id="vigLow"></div>
  <div id="vigFlash"></div>
</div>

<div class="overlay show" id="ovStart">
  <div class="panel">
    <h1>SKYSHARD ISLES</h1>
    <div class="orn"><i></i><b></b><i></i></div>
    <p class="tag">Twelve shards lie scattered across the floating isles.<br>
       Gather them all — and mind the elemental wardens.</p>
    <div class="orn"><i></i><b></b><i></i></div>
    <div class="ctrs">
      <span>Move</span><span><kbd>W</kbd><kbd>A</kbd><kbd>S</kbd><kbd>D</kbd></span>
      <span>Jump</span><span><kbd>Space</kbd></span>
      <span>Camera</span><span><kbd>Mouse drag</kbd></span>
      <span>Zoom</span><span><kbd>Scroll</kbd></span>
      <span>Mute</span><span><kbd>M</kbd></span>
    </div>
    <button class="btn" id="btnStart">BEGIN</button>
    <p class="foot">BEST WITH A KEYBOARD · SOUND ON</p>
  </div>
</div>

<div class="overlay" id="ovDead">
  <div class="panel">
    <h1>THE ISLES CLAIM YOU</h1>
    <div class="orn"><i></i><b></b><i></i></div>
    <p class="tag" id="deadMsg"></p>
    <p class="stats" id="deadStats"></p>
    <button class="btn" id="btnRetry">RISE AGAIN</button>
  </div>
</div>

<div class="overlay" id="ovWin">
  <div class="panel">
    <h1>ALL SHARDS RECOVERED</h1>
    <div class="orn"><i></i><b></b><i></i></div>
    <p class="tag">The archipelago hums with restored light.<br>The wardens bow as you pass.</p>
    <p class="stats" id="winStats"></p>
    <button class="btn" id="btnAgain">WANDER AGAIN</button>
  </div>
</div>

<script type="importmap">
{ "imports": { "three": "https://cdn.jsdelivr.net/npm/[email protected]/build/three.module.js" } }
</script>

<script type="module">
import * as THREE from 'three';

const clamp=(v,a,b)=>Math.max(a,Math.min(b,v));
const lerp=(a,b,t)=>a+(b-a)*t;
const wrapAngle=a=>Math.atan2(Math.sin(a),Math.cos(a));
const sst=(a,b,x)=>{x=clamp((x-a)/(b-a),0,1);return x*x*(3-2*x)};
function mulberry32(s){return function(){s|=0;s=s+0x6D2B79F5|0;let t=Math.imul(s^s>>>15,1|s);t=t+Math.imul(t^t>>>7,61|t)^t;return((t^t>>>14)>>>0)/4294967296}}
const rng=mulberry32(20240613);
const fmt=t=>`${Math.floor(t/60)}:${String(Math.floor(t%60)).padStart(2,'0')}`;

const _v1=new THREE.Vector3(),_v2=new THREE.Vector3(),
      _v3=new THREE.Vector3(),_v4=new THREE.Vector3(),
      _bv=new THREE.Vector3();

let AC=null,master=null,noiseBuf=null,muted=false;
function initAudio(){
  if(AC)return;
  AC=new (window.AudioContext||window.webkitAudioContext)();
  master=AC.createGain(); master.gain.value=muted?0:0.5;
  const comp=AC.createDynamicsCompressor();
  master.connect(comp); comp.connect(AC.destination);
  noiseBuf=AC.createBuffer(1,AC.sampleRate,AC.sampleRate);
  const d=noiseBuf.getChannelData(0);
  for(let i=0;i<d.length;i++)d[i]=Math.random()*2-1;
  const src=AC.createBufferSource(); src.buffer=noiseBuf; src.loop=true;
  const lp=AC.createBiquadFilter(); lp.type='lowpass'; lp.frequency.value=340;
  const wg=AC.createGain(); wg.gain.value=0.045;
  const lfo=AC.createOscillator(); lfo.frequency.value=0.07;
  const lg=AC.createGain(); lg.gain.value=0.022;
  lfo.connect(lg); lg.connect(wg.gain);
  src.connect(lp); lp.connect(wg); wg.connect(master);
  src.start(); lfo.start();
}
function tone(o){
  if(!AC)return;
  const t0=AC.currentTime+(o.delay||0);
  const osc=AC.createOscillator(),g=AC.createGain();
  osc.type=o.type||'sine';
  osc.frequency.setValueAtTime(o.f0,t0);
  osc.frequency.exponentialRampToValueAtTime(Math.max(20,o.f1||o.f0),t0+o.dur);
  g.gain.setValueAtTime(0.0001,t0);
  g.gain.exponentialRampToValueAtTime(o.vol,t0+0.012);
  g.gain.exponentialRampToValueAtTime(0.0001,t0+o.dur);
  osc.connect(g); g.connect(master);
  osc.start(t0); osc.stop(t0+o.dur+0.05);
}
function noiseHit(o){
  if(!AC)return;
  const t0=AC.currentTime+(o.delay||0);
  const s=AC.createBufferSource(); s.buffer=noiseBuf;
  const f=AC.createBiquadFilter(); f.type=o.type||'lowpass';
  f.frequency.setValueAtTime(o.f0,t0);
  f.frequency.exponentialRampToValueAtTime(Math.max(30,o.f1||o.f0),t0+o.dur);
  const g=AC.createGain();
  g.gain.setValueAtTime(0.0001,t0);
  g.gain.exponentialRampToValueAtTime(o.vol,t0+0.01);
  g.gain.exponentialRampToValueAtTime(0.0001,t0+o.dur);
  s.connect(f); f.connect(g); g.connect(master);
  s.start(t0); s.stop(t0+o.dur+0.05);
}
const sfx={
  jump(){tone({f0:330,f1:660,dur:.16,type:'triangle',vol:.16})},
  land(hard){noiseHit({dur:.12,vol:hard?.3:.16,f0:520,f1:110});tone({f0:130,f1:70,dur:.1,vol:hard?.2:.1})},
  step(){noiseHit({dur:.05,vol:.045,f0:750+Math.random()*250,f1:300})},
  collect(n){const b=523*Math.pow(2,((n-1)%12)/12);
    tone({f0:b,dur:.14,vol:.2});
    tone({f0:b*1.5,dur:.16,vol:.17,delay:.07});
    tone({f0:b*2,dur:.2,type:'triangle',vol:.13,delay:.14});
    tone({f0:b*3,dur:.3,vol:.05,delay:.14});},
  hurt(){tone({f0:270,f1:90,dur:.28,type:'sawtooth',vol:.2});noiseHit({dur:.16,vol:.2,f0:900,f1:150})},
  shoot(){tone({f0:760,f1:190,dur:.17,type:'square',vol:.09});noiseHit({dur:.08,vol:.07,f0:2200,f1:500,type:'bandpass'})},
  charge(){tone({f0:170,f1:780,dur:.85,vol:.055})},
  pop(){noiseHit({dur:.09,vol:.1,f0:900,f1:220})},
  whoosh(){noiseHit({dur:.4,vol:.2,f0:280,f1:1400,type:'bandpass'})},
  over(){[392,311,262].forEach((f,i)=>tone({f0:f,f1:f*.985,dur:.4,type:'triangle',vol:.18,delay:i*.34}));
         tone({f0:98,f1:60,dur:1.3,type:'sine',vol:.14,delay:.1})},
  win(){[523,659,784,1047,1319].forEach((f,i)=>tone({f0:f,dur:.3,type:'triangle',vol:.16,delay:i*.11}));
        noiseHit({dur:.9,vol:.05,f0:6500,f1:3000,type:'highpass',delay:.2})},
};
const SND_ON='<svg viewBox="0 0 24 24" width="17" height="17" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M3 10v4h4l5 4V6L7 10H3z" fill="currentColor" stroke="none"/><path d="M16 8.6a4.2 4.2 0 0 1 0 6.8M18.6 6a8.4 8.4 0 0 1 0 12"/></svg>';
const SND_OFF='<svg viewBox="0 0 24 24" width="17" height="17" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round"><path d="M3 10v4h4l5 4V6L7 10H3z" fill="currentColor" stroke="none"/><path d="M16.5 9.5l5 5M21.5 9.5l-5 5"/></svg>';

const renderer=new THREE.WebGLRenderer({antialias:true,powerPreference:'high-performance'});
renderer.setSize(innerWidth,innerHeight);
renderer.setPixelRatio(Math.min(devicePixelRatio,2));
renderer.shadowMap.enabled=true;
renderer.shadowMap.type=THREE.PCFSoftShadowMap;
renderer.outputColorSpace=THREE.SRGBColorSpace;
renderer.toneMapping=THREE.ACESFilmicToneMapping;
renderer.toneMappingExposure=1.06;
document.body.appendChild(renderer.domElement);
const cv=renderer.domElement;
cv.addEventListener('contextmenu',e=>e.preventDefault());

const scene=new THREE.Scene();
scene.background=new THREE.Color('#9fe4f2');
scene.fog=new THREE.Fog(new THREE.Color('#dff6f9'),55,175);

const camera=new THREE.PerspectiveCamera(58,innerWidth/innerHeight,0.1,500);
camera.position.set(0,10,30);

addEventListener('resize',()=>{
  camera.aspect=innerWidth/innerHeight;
  camera.updateProjectionMatrix();
  renderer.setSize(innerWidth,innerHeight);
});

const glowTex=(()=>{
  const c=document.createElement('canvas'); c.width=c.height=64;
  const x=c.getContext('2d');
  const g=x.createRadialGradient(32,32,0,32,32,32);
  g.addColorStop(0,'rgba(255,255,255,1)');
  g.addColorStop(0.35,'rgba(255,255,255,.55)');
  g.addColorStop(1,'rgba(255,255,255,0)');
  x.fillStyle=g; x.fillRect(0,0,64,64);
  const t=new THREE.CanvasTexture(c); t.colorSpace=THREE.SRGBColorSpace; return t;
})();

const hemi=new THREE.HemisphereLight('#cfeaf5','#c9a98c',0.9); scene.add(hemi);
const amb=new THREE.AmbientLight('#ffffff',0.35); scene.add(amb);
const keyLight=new THREE.DirectionalLight('#fff2d0',1.4);
keyLight.castShadow=true;
keyLight.shadow.mapSize.set(2048,2048);
Object.assign(keyLight.shadow.camera,{left:-36,right:36,top:36,bottom:-36,near:5,far:180});
keyLight.shadow.camera.updateProjectionMatrix();
keyLight.shadow.bias=-0.0004;
scene.add(keyLight); scene.add(keyLight.target);

const SKY_STOPS=[
  {t:0.00,sky:'#161b38',hor:'#2a3157',sun:'#aabaff',si:0.00,mi:0.32,hemi:0.24,amb:0.17},
  {t:0.20,sky:'#1d2344',hor:'#3a3f6e',sun:'#aabaff',si:0.00,mi:0.32,hemi:0.26,amb:0.18},
  {t:0.26,sky:'#7a6a9e',hor:'#ffb08a',sun:'#ffc9a0',si:0.55,mi:0.05,hemi:0.44,amb:0.27},
  {t:0.33,sky:'#a9e7f2',hor:'#dff6f9',sun:'#fff2d0',si:1.35,mi:0.00,hemi:0.85,amb:0.38},
  {t:0.50,sky:'#9fe4f2',hor:'#e2f7fb',sun:'#fff6dd',si:1.50,mi:0.00,hemi:0.95,amb:0.42},
  {t:0.67,sky:'#a9e7f2',hor:'#e8f6f2',sun:'#ffe9bd',si:1.25,mi:0.00,hemi:0.80,amb:0.36},
  {t:0.74,sky:'#8a7bb0',hor:'#ff9d7e',sun:'#ffb084',si:0.60,mi:0.04,hemi:0.46,amb:0.28},
  {t:0.80,sky:'#232a52',hor:'#4a4478',sun:'#aabaff',si:0.00,mi:0.30,hemi:0.28,amb:0.19},
  {t:1.00,sky:'#161b38',hor:'#2a3157',sun:'#aabaff',si:0.00,mi:0.32,hemi:0.24,amb:0.17},
];
SKY_STOPS.forEach(s=>{s.skyC=new THREE.Color(s.sky);s.horC=new THREE.Color(s.hor);s.sunC=new THREE.Color(s.sun)});
const CYCLE=150;
let dayT=0.32, nightF=0;
const _sky=new THREE.Color(),_hor=new THREE.Color(),_sun=new THREE.Color(),_tmpC=new THREE.Color();
const C_WHITE=new THREE.Color('#ffffff'),C_WARM=new THREE.Color('#ffd98a');

const sunSprite=new THREE.Sprite(new THREE.SpriteMaterial({map:glowTex,color:'#ffedb8',transparent:true,fog:false,depthWrite:false}));
sunSprite.scale.setScalar(24); scene.add(sunSprite);
const moonSprite=new THREE.Sprite(new THREE.SpriteMaterial({map:glowTex,color:'#e6ecff',transparent:true,fog:false,depthWrite:false}));
moonSprite.scale.setScalar(13); scene.add(moonSprite);

var stars;
{
  const n=360,pos=new Float32Array(n*3);
  for(let i=0;i<n;i++){
    const v=new THREE.Vector3(Math.random()*2-1,Math.random()*0.9+0.08,Math.random()*2-1).normalize().multiplyScalar(185);
    pos.set([v.x,v.y,v.z],i*3);
  }
  const g=new THREE.BufferGeometry();
  g.setAttribute('position',new THREE.BufferAttribute(pos,3));
  stars=new THREE.Points(g,new THREE.PointsMaterial({map:glowTex,color:'#cfd8ff',size:1.7,sizeAttenuation:false,transparent:true,opacity:0,fog:false,depthWrite:false}));
  stars.frustumCulled=false; scene.add(stars);
}

const seaMat=new THREE.MeshBasicMaterial({color:'#dff6f9'});
const sea=new THREE.Mesh(new THREE.CircleGeometry(330,40),seaMat);
sea.rotation.x=-Math.PI/2; sea.position.y=-34; scene.add(sea);

const surfaces=[];
const obstacles=[];
const reserved=[];
const world=new THREE.Group(); scene.add(world);

function jitterGeo(geo,amt,keepTop){
  const p=geo.attributes.position,h=geo.parameters.height;
  for(let i=0;i<p.count;i++){
    const y=p.getY(i);
    const top=keepTop&&y>h/2-1e-4;
    p.setX(i,p.getX(i)+(rng()-0.5)*amt*2);
    p.setZ(i,p.getZ(i)+(rng()-0.5)*amt*2);
    if(!top)p.setY(i,y+(rng()-0.5)*amt*2);
  }
}
const std=(c,o={})=>new THREE.MeshStandardMaterial({color:c,roughness:0.92,metalness:0,flatShading:true,...o});

const ISLANDS=[
  {x:0,  z:0,  y:0,   r:11,  grass:'#9fe0ae',rock:'#b08a76'},
  {x:0,  z:-26,y:1.4, r:7,   grass:'#b9e6a0',rock:'#a98fa6'},
  {x:22, z:-20,y:2.6, r:5.5, grass:'#a5dfc0',rock:'#c2a184'},
  {x:27, z:4,  y:0.6, r:6.5, grass:'#ffd6e0',rock:'#b08a76'},
  {x:20, z:24, y:2.2, r:5,   grass:'#a8e6b8',rock:'#9b8aa0'},
  {x:-2, z:28, y:1.0, r:6,   grass:'#b9e6a0',rock:'#c2a184'},
  {x:-24,z:20, y:3.2, r:5.5, grass:'#ffd6e0',rock:'#a98fa6'},
  {x:-28,z:-2, y:0.8, r:6.5, grass:'#a5dfc0',rock:'#b08a76'},
  {x:-21,z:-21,y:1.8, r:5,   grass:'#a8e6b8',rock:'#9b8aa0'},
  {x:40, z:-34,y:4.6, r:3.5, grass:'#ffe9a8',rock:'#c2a184'},
  {x:-40,z:32, y:4.2, r:3.5, grass:'#cbb3f0',rock:'#a98fa6'},
];

function addIsland(def){
  const g=new THREE.Group();
  const thick=def.r*0.16+0.9;
  const topG=new THREE.CylinderGeometry(def.r,def.r*0.82,thick,Math.max(9,Math.round(def.r*1.7)),1);
  jitterGeo(topG,0.14,true); topG.translate(0,-thick/2,0);
  const grass=std(def.grass),rock=std(def.rock),rockD=std(def.rock,{color:new THREE.Color(def.rock).multiplyScalar(0.72)});
  const top=new THREE.Mesh(topG,[rock,grass,rockD]);
  top.receiveShadow=true; g.add(top);
  const uh=def.r*1.35+rng()*2;
  const botG=new THREE.ConeGeometry(def.r*0.86,uh,9,3);
  jitterGeo(botG,0.5,false); botG.rotateX(Math.PI); botG.translate(0,-thick+0.25-uh/2,0);
  g.add(new THREE.Mesh(botG,rockD));
  g.position.set(def.x,def.y,def.z);
  world.add(g);
  surfaces.push({type:'disc',x:def.x,z:def.z,y:def.y,r:def.r});
  def.thick=thick;
}
ISLANDS.forEach(addIsland);

const wood=std('#c9a27a'),woodD=std('#a87f57');
function bridgeY(s,t){return s.ay+(s.by-s.ay)*t+Math.sin(Math.PI*t)*s.arch}
function addBridge(A,B){
  const dx=B.x-A.x,dz=B.z-A.z,L=Math.hypot(dx,dz),ux=dx/L,uz=dz/L;
  const s={ax:A.x+ux*A.r,ay:A.y,az:A.z+uz*A.r,
           bx:B.x-ux*B.r,by:B.y,bz:B.z-uz*B.r,
           width:2.3,arch:Math.min(1.1,L*0.09),len:0};
  s.len=Math.hypot(s.bx-s.ax,s.bz-s.az);
  const n=Math.max(4,Math.round(s.len/1.35));
  const seg=s.len/n;
  const plankG=new THREE.BoxGeometry(2.3,0.26,seg*1.18);
  const postG=new THREE.CylinderGeometry(0.06,0.07,0.85,5);
  const abx=s.bx-s.ax,abz=s.bz-s.az,il=1/s.len;
  const px=-abz*il,pz=abx*il;
  for(let i=0;i<n;i++){
    const t0=i/n,t1=(i+1)/n,tm=(t0+t1)/2;
    const y0=bridgeY(s,t0),y1=bridgeY(s,t1);
    const m=new THREE.Mesh(plankG,wood);
    m.position.set(s.ax+abx*tm,bridgeY(s,tm),s.az+abz*tm);
    m.quaternion.setFromEuler(new THREE.Euler(-Math.atan2(y1-y0,seg),Math.atan2(abx,abz),0,'YXZ'));
    m.castShadow=m.receiveShadow=true; world.add(m);
    if(i%2===0){
      const t=t0,y=bridgeY(s,t)+0.34;
      for(const side of[-1,1]){
        const p=new THREE.Mesh(postG,woodD);
        p.position.set(s.ax+abx*t+px*side*(s.width/2-0.14),y,s.az+abz*t+pz*side*(s.width/2-0.14));
        p.castShadow=true; world.add(p);
      }
    }
  }
  surfaces.push(s);
  reserved.push({x:s.ax,z:s.az},{x:s.bx,z:s.bz});
}
addBridge(ISLANDS[0],ISLANDS[1]);
addBridge(ISLANDS[0],ISLANDS[5]);
addBridge(ISLANDS[0],ISLANDS[3]);

function addStones(A,B){
  const dx=B.x-A.x,dz=B.z-A.z,D=Math.hypot(dx,dz),ux=dx/D,uz=dz/D;
  const px=-uz,pz=ux;
  const ax=A.x+ux*A.r,az=A.z+uz*A.r,bx=B.x-ux*B.r,bz=B.z-uz*B.r;
  const span=Math.hypot(bx-ax,bz-az);
  const n=Math.max(1,Math.round(span/3.6));
  for(let i=1;i<=n;i++){
    const t=i/(n+1);
    const wob=Math.sin(t*Math.PI)*(rng()*1.4-0.7);
    const x=ax+(bx-ax)*t+px*wob, z=az+(bz-az)*t+pz*wob;
    const y=lerp(A.y,B.y,t)+Math.sin(t*Math.PI)*0.9;
    const r=1.35+rng()*0.5;
    const g=new THREE.CylinderGeometry(r,r*0.7,0.8,7);
    jitterGeo(g,0.1,true); g.translate(0,-0.4,0);
    const m=new THREE.Mesh(g,[std('#b08a76'),std(A.grass),std('#8a6a5c')]);
    m.position.set(x,y,z); m.castShadow=m.receiveShadow=true; world.add(m);
    surfaces.push({type:'disc',x,z,y,r:r+0.15});
    reserved.push({x,z});
  }
}
[[0,7],[0,2],[1,2],[1,8],[7,8],[5,4],[4,6],[6,5],[2,9],[3,4]].forEach(([a,b])=>addStones(ISLANDS[a],ISLANDS[b]));

{
  const g=new THREE.CylinderGeometry(1.7,1.9,0.22,10);
  const m=new THREE.Mesh(g,std('#d8cdbb'));
  m.position.set(0,0.11,5.5); m.receiveShadow=true; world.add(m);
  const ring=new THREE.Mesh(new THREE.TorusGeometry(1.25,0.035,5,20),std('#c9b08a'));
  ring.rotation.x=Math.PI/2; ring.position.set(0,0.23,5.5); world.add(ring);
  surfaces.push({type:'disc',x:0,z:5.5,y:0.22,r:1.85});
  reserved.push({x:0,z:5.5});
}

const CRYSTAL_DEFS=[
  {i:0,ox:3.4,oz:2.4},{i:0,ox:-4.6,oz:-3.6},{i:1,ox:1.6,oz:1.4},{i:2,ox:0.6,oz:-1},
  {i:3,ox:2.2,oz:0.4},{i:4,ox:-1,oz:1},{i:5,ox:-1.6,oz:-1.2},{i:6,ox:1.2,oz:-0.6},
  {i:7,ox:-2,oz:0.8},{i:8,ox:0.4,oz:1.2},{i:9,ox:0,oz:0},{i:10,ox:-1.4,oz:1.2},
];
const CRYSTAL_COLORS=['#7ef0d4','#ffa8c5','#ffe08a','#c9a7ff'];
const TOTAL=CRYSTAL_DEFS.length;
const crystals=[];
CRYSTAL_DEFS.forEach((d,idx)=>{
  const isl=ISLANDS[d.i];
  const col=CRYSTAL_COLORS[idx%4];
  const g=new THREE.Group();
  const core=new THREE.Mesh(new THREE.OctahedronGeometry(0.4,0),
    new THREE.MeshStandardMaterial({color:'#eafffa',emissive:col,emissiveIntensity:1.1,flatShading:true,roughness:0.3}));
  core.scale.y=1.6; core.castShadow=true; g.add(core);
  const glow=new THREE.Sprite(new THREE.SpriteMaterial({map:glowTex,color:col,transparent:true,opacity:0.75,depthWrite:false}));
  glow.scale.setScalar(2.3); g.add(glow);
  const beam=new THREE.Mesh(new THREE.CylinderGeometry(0.05,0.05,7,6,1,true),
    new THREE.MeshBasicMaterial({color:col,transparent:true,opacity:0.15,blending:THREE.AdditiveBlending,depthWrite:false,side:THREE.DoubleSide}));
  beam.position.y=2.7; g.add(beam);
  const x=isl.x+d.ox,z=isl.z+d.oz,y=isl.y+1.05;
  g.position.set(x,y,z); scene.add(g);
  reserved.push({x,z});
  crystals.push({g,core,beam,baseY:y,col,on:false,ph:idx*1.7});
});

const ELEMENTS=[
  {name:'ember',core:'#ff9a5c',dark:'#8a3d1e'},
  {name:'frost',core:'#7ee8fa',dark:'#1e5a8a'},
  {name:'bloom',core:'#b0f07e',dark:'#3d6e1e'},
  {name:'void', core:'#c9a7ff',dark:'#4a2e8a'},
];
const TURRET_DEFS=[
  {i:1,x:0,z:-23.2,el:0},{i:3,x:25.5,z:6.2,el:1},{i:6,x:-22.4,z:19.4,el:2},
  {i:2,x:20.4,z:-18.6,el:0},{i:10,x:-40,z:32,el:3},
];
const turrets=[];
TURRET_DEFS.forEach((d,idx)=>{
  const isl=ISLANDS[d.i],el=ELEMENTS[d.el];
  const g=new THREE.Group(); g.position.set(d.x,isl.y,d.z);
  const base=new THREE.Mesh(new THREE.ConeGeometry(1.0,1.1,6),std('#9b93a8')); base.position.y=0.55; base.castShadow=true;
  const pil=new THREE.Mesh(new THREE.CylinderGeometry(0.3,0.42,0.95,7),std('#b7ada8')); pil.position.y=1.5; pil.castShadow=true;
  const head=new THREE.Group(); head.position.y=2.1;
  const spin=new THREE.Group(); head.add(spin);
  const ring=new THREE.Mesh(new THREE.TorusGeometry(0.5,0.08,6,12),
    new THREE.MeshStandardMaterial({color:el.dark,emissive:el.core,emissiveIntensity:0.7,flatShading:true}));
  ring.rotation.x=Math.PI/2; spin.add(ring);
  const core=new THREE.Mesh(new THREE.IcosahedronGeometry(0.24,0),
    new THREE.MeshStandardMaterial({color:el.dark,emissive:el.core,emissiveIntensity:1.2,flatShading:true}));
  core.position.y=0.05; head.add(core);
  for(let k=0;k<3;k++){
    const sp=new THREE.Mesh(new THREE.ConeGeometry(0.09,0.42,5),std('#8a8296'));
    const a=k/3*Math.PI*2;
    sp.position.set(Math.cos(a)*0.5,-0.05,Math.sin(a)*0.5);
    sp.rotation.z=Math.cos(a)*1.2; sp.rotation.x=-Math.sin(a)*1.2;
    head.add(sp);
  }
  g.add(base,pil,head); scene.add(g);
  reserved.push({x:d.x,z:d.z});
  obstacles.push({x:d.x,z:d.z,r:0.85,h:1.9,y:isl.y});
  turrets.push({g,head,spin,core,el,x:d.x,z:d.z,y:isl.y,range:15,
                cool:1.5+Math.random()*2,charging:0,ph:idx*2.1});
});

const trunkMat=std('#8a5f45');
const canopyMats=['#7ccf8f','#8fdc9a','#6fc48f'].map(c=>std(c));
const blossomMat=std('#ffb7cd');
const treeSpots=[],rockSpots=[],tuftSpots=[];
for(const isl of ISLANDS){
  const nT=Math.min(6,Math.round(isl.r*0.75)),nR=Math.round(isl.r*0.5),nG=Math.round(isl.r*2.1);
  const place=min=>{
    for(let k=0;k<24;k++){
      const a=rng()*Math.PI*2,d=(0.25+rng()*0.72)*isl.r;
      const x=isl.x+Math.cos(a)*d,z=isl.z+Math.sin(a)*d;
      if(reserved.every(p=>Math.hypot(p.x-x,p.z-z)>min))return{x,z};
    }
    return null;
  };
  for(let i=0;i<nT;i++){const p=place(1.9);if(p)treeSpots.push({...p,y:isl.y,blossom:rng()<0.3,s:0.85+rng()*0.5})}
  for(let i=0;i<nR;i++){const p=place(1.4);if(p)rockSpots.push({...p,y:isl.y,s:0.28+rng()*0.34})}
  for(let i=0;i<nG;i++){const p=place(0.9);if(p)tuftSpots.push({...p,y:isl.y,s:0.7+rng()*0.8,c:rng()})}
}
treeSpots.forEach(t=>{
  const g=new THREE.Group();
  const trunk=new THREE.Mesh(new THREE.CylinderGeometry(0.13,0.2,1.0,6),trunkMat);
  trunk.position.y=0.5; trunk.castShadow=true; g.add(trunk);
  if(t.blossom){
    for(const[ox,oy,oz,r]of[[0,1.5,0,0.72],[0.4,1.9,0.15,0.5],[-0.35,1.85,-0.2,0.46]]){
      const b=new THREE.Mesh(new THREE.IcosahedronGeometry(r,0),blossomMat);
      b.position.set(ox,oy,oz); b.castShadow=true; g.add(b);
    }
  }else{
    const m=canopyMats[Math.floor(rng()*3)];
    const c1=new THREE.Mesh(new THREE.ConeGeometry(0.78,1.15,7),m); c1.position.y=1.5; c1.castShadow=true;
    const c2=new THREE.Mesh(new THREE.ConeGeometry(0.55,0.95,7),m); c2.position.y=2.15; c2.rotation.y=rng(); c2.castShadow=true;
    g.add(c1,c2);
  }
  g.position.set(t.x,t.y-0.05,t.z); g.scale.setScalar(t.s); g.rotation.y=rng()*6.28;
  world.add(g);
  obstacles.push({x:t.x,z:t.z,r:0.4*t.s,h:2.6*t.s,y:t.y});
});
{
  const rockGeo=new THREE.DodecahedronGeometry(1,0);
  const im=new THREE.InstancedMesh(rockGeo,std('#b7ada8'),rockSpots.length);
  const M=new THREE.Matrix4(),Q=new THREE.Quaternion(),E=new THREE.Euler(),S=new THREE.Vector3();
  rockSpots.forEach((r,i)=>{
    E.set(rng(),rng()*6.28,rng()); Q.setFromEuler(E);
    S.set(r.s,r.s*0.7,r.s);
    M.compose(new THREE.Vector3(r.x,r.y+r.s*0.35,r.z),Q,S);
    im.setMatrixAt(i,M);
    im.setColorAt(i,_tmpC.set(['#b7ada8','#a9a3b5','#c4b49a'][i%3]));
    obstacles.push({x:r.x,z:r.z,r:r.s*0.9,h:r.s*0.8,y:r.y});
  });
  im.castShadow=im.receiveShadow=true; world.add(im);
}
{
  const tuftGeo=new THREE.ConeGeometry(0.09,0.36,4); tuftGeo.translate(0,0.18,0);
  const im=new THREE.InstancedMesh(tuftGeo,new THREE.MeshStandardMaterial({roughness:1,flatShading:true}),tuftSpots.length);
  const M=new THREE.Matrix4(),Q=new THREE.Quaternion();
  tuftSpots.forEach((t,i)=>{
    Q.setFromAxisAngle(_v1.set(0,1,0),rng()*6.28);
    M.compose(new THREE.Vector3(t.x,t.y,t.z),Q,_v2.set(t.s,t.s,t.s));
    im.setMatrixAt(i,M);
    im.setColorAt(i,_tmpC.set(t.c<0.5?'#7ccf8f':'#a5e08a').offsetHSL(0,(rng()-0.5)*0.1,(rng()-0.5)*0.08));
  });
  world.add(im);
}

const STEP=0.55,PR=0.42,GRAV=24,JUMPV=9.3,MAXSP=7.2,KILLY=-26;
function surfaceHeightAt(x,z,refY){
  let best=-1e9;
  for(let i=0;i<surfaces.length;i++){
    const s=surfaces[i];
    if(s.type==='disc'){
      if(Math.hypot(x-s.x,z-s.z)<s.r+0.35&&s.y<=refY+STEP&&s.y>best)best=s.y;
    }else{
      const abx=s.bx-s.ax,abz=s.bz-s.az,L2=abx*abx+abz*abz;
      let t=((x-s.ax)*abx+(z-s.az)*abz)/L2; t=clamp(t,0,1);
      const cx=s.ax+abx*t,cz=s.az+abz*t;
      if(Math.hypot(x-cx,z-cz)<s.width/2+0.3){
        const y=s.ay+(s.by-s.ay)*t+Math.sin(Math.PI*t)*s.arch;
        if(y<=refY+STEP&&y>best)best=y;
      }
    }
  }
  return best;
}

const wiz={root:new THREE.Group(),mats:[]};
{
  const M=(c,o={})=>{const m=std(c,{roughness:0.85,...o});wiz.mats.push(m);return m};
  const teal=M('#2e6e68'),tealD=M('#22544f'),gold=M('#e6b54a'),
        skin=M('#f3cba2'),beardM=M('#ece7dc'),dark=M('#2b2b33'),woodM=M('#8a5a3b');
  const add=(geo,mat,x,y,z,parent=wiz.root)=>{
    const m=new THREE.Mesh(geo,mat); m.position.set(x,y,z); m.castShadow=true; parent.add(m); return m;
  };
  wiz.robe=add(new THREE.ConeGeometry(0.58,1.15,9),teal,0,0.575,0);
  const trim=add(new THREE.TorusGeometry(0.5,0.045,6,14),gold,0,0.07,0); trim.rotation.x=Math.PI/2;
  const belt=add(new THREE.TorusGeometry(0.33,0.04,6,12),gold,0,0.66,0); belt.rotation.x=Math.PI/2;
  add(new THREE.BoxGeometry(0.1,0.1,0.05),gold,0,0.66,0.33);
  add(new THREE.SphereGeometry(0.27,8,6),skin,0,1.3,0);
  const nose=add(new THREE.ConeGeometry(0.05,0.13,5),skin,0,1.27,0.29); nose.rotation.x=Math.PI/2;
  add(new THREE.SphereGeometry(0.033,6,4),dark,-0.1,1.35,0.22);
  add(new THREE.SphereGeometry(0.033,6,4),dark,0.1,1.35,0.22);
  const beard=add(new THREE.ConeGeometry(0.19,0.5,7),beardM,0,1.13,0.15); beard.rotation.x=Math.PI-0.35;

  wiz.head=new THREE.Group(); wiz.head.position.set(0,1.42,0); wiz.root.add(wiz.head);
  const hat=new THREE.Group(); wiz.head.add(hat); wiz.hat=hat;
  add(new THREE.CylinderGeometry(0.55,0.6,0.08,10),tealD,0,0.05,0,hat);
  add(new THREE.ConeGeometry(0.36,0.62,9),tealD,0,0.4,0,hat);
  const tip=add(new THREE.ConeGeometry(0.17,0.55,8),tealD,0.07,0.83,0,hat); tip.rotation.z=-0.3;
  const band=add(new THREE.TorusGeometry(0.31,0.035,5,12),gold,0,0.14,0,hat); band.rotation.x=Math.PI/2;
  add(new THREE.OctahedronGeometry(0.06),gold,0,0.14,0.32,hat);

  const mkArm=side=>{
    const p=new THREE.Group(); p.position.set(side*0.44,1.08,0); wiz.root.add(p);
    const a=add(new THREE.CylinderGeometry(0.07,0.09,0.55,6),teal,0,-0.26,0,p);
    a.rotation.z=side*0.28;
    add(new THREE.SphereGeometry(0.075,6,5),skin,0,-0.55,0,p);
    return p;
  };
  wiz.armL=mkArm(-1); wiz.armR=mkArm(1);

  const staff=new THREE.Group(); staff.position.set(0.6,0,0.2); staff.rotation.z=-0.1; wiz.root.add(staff);
  add(new THREE.CylinderGeometry(0.045,0.06,1.55,6),woodM,0,0.775,0,staff);
  wiz.orb=add(new THREE.IcosahedronGeometry(0.15,0),
    new THREE.MeshStandardMaterial({color:'#bffce8',emissive:'#7ef0d4',emissiveIntensity:1.6,flatShading:true}),
    0,1.62,0,staff);
  wiz.mats.push(wiz.orb.material);
  const og=new THREE.Sprite(new THREE.SpriteMaterial({map:glowTex,color:'#7ef0d4',transparent:true,opacity:0.7,depthWrite:false}));
  og.scale.setScalar(0.95); og.position.y=1.62; staff.add(og);
  wiz.orbLight=new THREE.PointLight('#7ef0d4',2.4,7); wiz.orbLight.position.y=1.62; staff.add(wiz.orbLight);

  wiz.root.traverse(o=>{if(o.isMesh)o.castShadow=true});
  scene.add(wiz.root);
}

const projs=[];
for(let i=0;i<24;i++){
  const m=new THREE.Mesh(new THREE.SphereGeometry(0.2,8,6),new THREE.MeshBasicMaterial({color:'#ffffff'}));
  const gl=new THREE.Sprite(new THREE.SpriteMaterial({map:glowTex,transparent:true,opacity:0.9,depthWrite:false}));
  gl.scale.setScalar(1.2); m.add(gl); m.visible=false; scene.add(m);
  projs.push({m,vel:new THREE.Vector3(),life:0,trail:0});
}
function fireProjectile(t){
  const p=projs.find(p=>p.life<=0); if(!p)return;
  t.head.getWorldPosition(_v1);
  _v2.set(Math.sin(t.head.rotation.y),0,Math.cos(t.head.rotation.y));
  _v1.addScaledVector(_v2,0.6);
  _v3.copy(player.pos); _v3.y+=1.05;
  const dist=_v1.distanceTo(_v3);
  _v3.addScaledVector(player.vel,dist/8.5*0.55);
  _v3.sub(_v1).normalize();
  p.m.position.copy(_v1);
  p.vel.copy(_v3).multiplyScalar(8.5);
  p.m.material.color.set(t.el.core);
  p.life=4; p.trail=0; p.m.visible=true;
  sfx.shoot();
}
function updateTurrets(dt){
  for(const t of turrets){
    t.spin.rotation.y+=dt*(t.charging>0?7:1.2);
    const boost=t.charging>0?(1-t.charging/0.85)*0.9:0;
    t.core.scale.setScalar(1+Math.sin(perfT*3+t.ph)*0.08+boost*0.7);
    t.core.material.emissiveIntensity=1.1+boost*2.2;
    if(state!=='playing'||graceT>0){t.head.rotation.y+=dt*0.4;continue}
    const dx=player.pos.x-t.x,dz=player.pos.z-t.z;
    const dist=Math.hypot(dx,dz,player.pos.y-t.y);
    if(dist<t.range){
      const want=Math.atan2(dx,dz),diff=wrapAngle(want-t.head.rotation.y);
      t.head.rotation.y+=diff*Math.min(1,dt*5);
      if(t.cool<=0&&t.charging<=0){t.charging=0.85;sfx.charge()}
      if(t.charging>0){
        t.charging-=dt;
        if(t.charging<=0){
          if(Math.abs(diff)<0.4)fireProjectile(t);
          else t.charging=0.15;
          t.cool=2.3*(0.85+Math.random()*0.3);
        }
      }
    }else{t.head.rotation.y+=dt*0.4;t.charging=0}
    t.cool-=dt;
  }
}
function updateProjs(dt){
  for(const p of projs){
    if(p.life<=0)continue;
    p.life-=dt;
    p.m.position.addScaledVector(p.vel,dt);
    p.trail-=dt;
    if(p.trail<=0){p.trail=0.045;spawnP(p.m.position,p.m.material.color.getHex(),_v1.set(0,0,0),0.25,0.5,0)}
    const dx=p.m.position.x-player.pos.x,dy=p.m.position.y-(player.pos.y+0.95),dz=p.m.position.z-player.pos.z;
    let dead=p.life<=0||p.m.position.y<KILLY-6;
    if(!dead&&state==='playing'&&dx*dx+dy*dy+dz*dz<0.72){
      damage(p.vel,'warden'); dead=true;
    }
    if(!dead){
      const g=surfaceHeightAt(p.m.position.x,p.m.position.z,p.m.position.y+0.5);
      if(g>-1e8&&p.m.position.y<g)dead=true;
    }
    if(dead){
      burst(p.m.position,p.m.material.color.getHex(),8,2,0.55,0.35,2);
      sfx.pop(); p.life=0; p.m.visible=false;
    }
  }
}

const POOL=150,bursts=[];let burstIdx=0;
for(let i=0;i<POOL;i++){
  const s=new THREE.Sprite(new THREE.SpriteMaterial({map:glowTex,transparent:true,depthWrite:false,blending:THREE.AdditiveBlending}));
  s.visible=false; scene.add(s);
  bursts.push({s,vel:new THREE.Vector3(),life:0,max:1,size:1,grav:0});
}
function spawnP(pos,color,vel,life,size,grav){
  const b=bursts[burstIdx++%POOL];
  b.s.visible=true; b.s.position.copy(pos);
  b.s.material.color.set(color); b.s.material.opacity=1;
  b.vel.copy(vel); b.life=b.max=life; b.size=size; b.grav=grav;
}
function burst(pos,color,n,spd,size,life,grav=3,up=1.6){
  for(let i=0;i<n;i++){
    _bv.set(Math.random()*2-1,Math.random()*2-1,Math.random()*2-1).normalize()
       .multiplyScalar(spd*(0.4+Math.random()*0.6));
    _bv.y+=up;
    spawnP(pos,color,_bv,life*(0.7+Math.random()*0.5),size,grav);
  }
}
function updateBursts(dt){
  for(const b of bursts){
    if(b.life<=0)continue;
    b.life-=dt;
    if(b.life<=0){b.s.visible=false;continue}
    b.s.position.addScaledVector(b.vel,dt);
    b.vel.y-=b.grav*dt;
    const k=b.life/b.max;
    b.s.material.opacity=k;
    b.s.scale.setScalar(b.size*(0.4+0.6*k));
  }
}

const motes={n:240};
{
  const pos=new Float32Array(motes.n*3);
  motes.vel=new Float32Array(motes.n*3);
  for(let i=0;i<motes.n;i++){
    pos[i*3]=(Math.random()*2-1)*55; pos[i*3+1]=Math.random()*20-3; pos[i*3+2]=(Math.random()*2-1)*55;
    motes.vel[i*3]=(Math.random()-0.5)*0.3; motes.vel[i*3+1]=(Math.random()-0.5)*0.1; motes.vel[i*3+2]=(Math.random()-0.5)*0.3;
  }
  const g=new THREE.BufferGeometry();
  g.setAttribute('position',new THREE.BufferAttribute(pos,3));
  motes.mat=new THREE.PointsMaterial({map:glowTex,size:0.18,transparent:true,opacity:0.4,depthWrite:false,blending:THREE.AdditiveBlending,color:'#ffffff'});
  motes.pts=new THREE.Points(g,motes.mat); motes.pts.frustumCulled=false; scene.add(motes.pts);
  motes.geo=g;
}
function updateMotes(dt){
  const p=motes.geo.attributes.position.array;
  for(let i=0;i<motes.n;i++){
    const j=i*3;
    p[j]+=(motes.vel[j]+Math.sin(perfT*0.7+i)*0.18)*dt;
    p[j+1]+=motes.vel[j+1]*dt;
    p[j+2]+=(motes.vel[j+2]+Math.cos(perfT*0.6+i*1.3)*0.18)*dt;
    if(p[j]>55)p[j]=-55; if(p[j]<-55)p[j]=55;
    if(p[j+1]>20)p[j+1]=-3; if(p[j+1]<-4)p[j+1]=20;
    if(p[j+2]>55)p[j+2]=-55; if(p[j+2]<-55)p[j+2]=55;
  }
  motes.geo.attributes.position.needsUpdate=true;
}

const clouds=[];
for(let i=0;i<7;i++){
  const g=new THREE.Group();
  const mat=std('#ffffff',{transparent:true,opacity:0.95});
  const nP=4+Math.floor(Math.random()*3);
  for(let k=0;k<nP;k++){
    const s=new THREE.Mesh(new THREE.IcosahedronGeometry(1.1+Math.random()*1.3,0),mat);
    s.position.set((Math.random()-0.5)*4.5,(Math.random()-0.5)*0.8,(Math.random()-0.5)*2.2);
    s.scale.y=0.6; g.add(s);
  }
  g.scale.setScalar(1.5+Math.random()*1.2);
  scene.add(g);
  clouds.push({g,ang:Math.random()*6.28,rad:28+Math.random()*34,h:8+Math.random()*9,spd:(0.008+Math.random()*0.012)*(Math.random()<0.5?-1:1),rot:(Math.random()-0.5)*0.1});
}
function updateClouds(dt){
  for(const c of clouds){
    c.ang+=c.spd*dt;
    c.g.position.set(Math.cos(c.ang)*c.rad,c.h,Math.sin(c.ang)*c.rad);
    c.g.rotation.y+=c.rot*dt;
  }
}

const drifters=[];
for(let i=0;i<10;i++){
  const m=new THREE.Mesh(new THREE.OctahedronGeometry(0.8+Math.random()*1.5,0),
    std(['#b08a76','#a98fa6','#c2a184'][i%3]));
  scene.add(m);
  drifters.push({m,ang:Math.random()*6.28,rad:55+Math.random()*30,h:-6+Math.random()*20,spd:(0.004+Math.random()*0.006)*(Math.random()<0.5?-1:1),rx:(Math.random()-0.5)*0.4,ry:(Math.random()-0.5)*0.4});
}
function updateDrifters(dt){
  for(const d of drifters){
    d.ang+=d.spd*dt;
    d.m.position.set(Math.cos(d.ang)*d.rad,d.h,Math.sin(d.ang)*d.rad);
    d.m.rotation.x+=d.rx*dt; d.m.rotation.y+=d.ry*dt;
  }
}

const keys={};
let camYaw=0.35,camPitch=0.42,camDist=9.5,dragging=false,lastPX=0,lastPY=0;
const SENS=0.0052,PITCH_MIN=-0.1,PITCH_MAX=1.15;
addEventListener('keydown',e=>{
  if(['Space','ArrowUp','ArrowDown','ArrowLeft','ArrowRight'].includes(e.code))e.preventDefault();
  keys[e.code]=true;
  if(e.code==='Space'){jumpBuf=0.14;hintJump=true}
  if(e.code==='KeyM')toggleMute();
  if(e.code==='Enter'){
    if(state==='menu'||state==='dead'||state==='win')beginRun();
  }
});
addEventListener('keyup',e=>keys[e.code]=false);
addEventListener('blur',()=>{for(const k in keys)keys[k]=false});
cv.addEventListener('pointerdown',e=>{
  if(state==='menu')return;
  dragging=true; lastPX=e.clientX; lastPY=e.clientY;
  cv.setPointerCapture(e.pointerId);
});
cv.addEventListener('pointermove',e=>{
  if(!dragging)return;
  const dx=e.clientX-lastPX,dy=e.clientY-lastPY;
  lastPX=e.clientX; lastPY=e.clientY;
  camYaw-=dx*SENS;
  camPitch=clamp(camPitch+dy*SENS,PITCH_MIN,PITCH_MAX);
});
const endDrag=()=>dragging=false;
cv.addEventListener('pointerup',endDrag);
cv.addEventListener('pointercancel',endDrag);
cv.addEventListener('wheel',e=>{
  e.preventDefault();
  camDist=clamp(camDist*Math.exp(e.deltaY*0.0012),5,16);
},{passive:false});

const $=id=>document.getElementById(id);
const heartsEl=$('hearts'),gemText=$('gemText'),gemChip=$('gemChip'),
      dialRot=$('dialRot'),hintEl=$('hint'),vigFlash=$('vigFlash'),vigLow=$('vigLow'),
      floatLayer=$('floatLayer'),
      ovStart=$('ovStart'),ovDead=$('ovDead'),ovWin=$('ovWin'),
      deadMsg=$('deadMsg'),deadStats=$('deadStats'),winStats=$('winStats'),
      muteBtn=$('muteBtn');
const HEART='<svg viewBox="0 0 24 24" width="22" height="22"><path d="M12 21.35l-1.45-1.32C5.4 15.36 2 12.28 2 8.5 2 5.42 4.42 3 7.5 3c1.74 0 3.41.81 4.5 2.09C13.09 3.81 14.76 3 16.5 3 19.58 3 22 5.42 22 8.5c0 3.78-3.4 6.86-8.55 11.54L12 21.35z"/></svg>';
const MAXHP=5;
function renderHearts(){
  if(!heartsEl)return;
  heartsEl.innerHTML='';
  for(let i=0;i<MAXHP;i++){
    const s=document.createElement('span');
    s.className='heart'+(i<hp?'':' lost');
    s.innerHTML=HEART;
    heartsEl.appendChild(s);
  }
  if(vigLow)vigLow.classList.toggle('low',hp===1&&state==='playing');
}
function renderGems(){
  if(!gemText)return;
  gemText.textContent=`${score} / ${TOTAL}`;
  if(gemChip){gemChip.classList.remove('pop'); void gemChip.offsetWidth; gemChip.classList.add('pop');}
}
function toggleMute(){
  muted=!muted;
  if(master)master.gain.value=muted?0:0.5;
  if(muteBtn)muteBtn.innerHTML=muted?SND_OFF:SND_ON;
}
if(muteBtn){
  muteBtn.innerHTML=SND_ON;
  muteBtn.addEventListener('click',e=>{initAudio();toggleMute();e.currentTarget.blur()});
}
function floater(worldPos,text,bad){
  if(!floatLayer)return;
  _v1.copy(worldPos).project(camera);
  if(_v1.z>1)return;
  const d=document.createElement('div');
  d.className='floater'+(bad?' bad':'');
  d.textContent=text;
  d.style.left=((_v1.x*0.5+0.5)*innerWidth)+'px';
  d.style.top=((-_v1.y*0.5+0.5)*innerHeight)+'px';
  floatLayer.appendChild(d);
  setTimeout(()=>d.remove(),960);
}
function vigPulse(){if(vigFlash){vigFlash.classList.remove('flash');void vigFlash.offsetWidth;vigFlash.classList.add('flash')}}
function showOv(el){[ovStart,ovDead,ovWin].forEach(o=>{if(o)o.classList.toggle('show',o===el)})}

let state='menu',hp=MAXHP,score=0,hits=0,gameTime=0,graceT=0;
let timeScale=1,invuln=0,shake=0,dip=0,dipV=0,perfT=0,T=0;
let lastDamage='warden',hintMoved=false,hintJump=false,hintDone=false;
const player={pos:new THREE.Vector3(0,0.3,5.5),vel:new THREE.Vector3()};
let grounded=false,prevGrounded=false,coyote=0,jumpBuf=0,heading=Math.PI;
let walkPhase=0,stepAcc=0,deform=0,deformV=0,flashT=0;
const lastSafe=new THREE.Vector3(0,0.3,5.5);

const tweens=[];
function tween(dur,fn,onDone){tweens.push({t:0,dur,fn,onDone})}
function updateTweens(dt){
  for(let i=tweens.length-1;i>=0;i--){
    const tw=tweens[i]; tw.t+=dt;
    const k=clamp(tw.t/tw.dur,0,1);
    tw.fn(k*k*(3-2*k));
    if(k>=1){tweens.splice(i,1);tw.onDone&&tw.onDone()}
  }
}

function beginRun(){
  initAudio(); if(AC&&AC.state==='suspended')AC.resume();
  hp=MAXHP;score=0;hits=0;gameTime=0;graceT=2.4;timeScale=1;invuln=1.5;
  shake=0;dip=0;dipV=0;deform=0;deformV=0;flashT=0;
  player.pos.set(0,0.3,5.5); player.vel.set(0,0,0);
  heading=Math.PI; lastSafe.copy(player.pos);
  wiz.root.visible=true; wiz.root.rotation.set(0,Math.PI,0);
  crystals.forEach(c=>{c.on=false;c.g.visible=true;c.g.scale.setScalar(1)});
  projs.forEach(p=>{p.life=0;p.m.visible=false});
  turrets.forEach(t=>{t.cool=1.2+Math.random()*2;t.charging=0});
  renderHearts(); if(gemText)gemText.textContent=`0 / ${TOTAL}`;
  showOv(null);
  state='playing';
  if(!hintDone)setTimeout(()=>{if(!hintDone)dismissHint()},25000);
}
const btnStart=$('btnStart'); if(btnStart)btnStart.addEventListener('click',e=>{beginRun();e.currentTarget.blur()});
const btnRetry=$('btnRetry'); if(btnRetry)btnRetry.addEventListener('click',e=>{beginRun();e.currentTarget.blur()});
const btnAgain=$('btnAgain'); if(btnAgain)btnAgain.addEventListener('click',e=>{beginRun();e.currentTarget.blur()});
function dismissHint(){hintDone=true;if(hintEl)hintEl.classList.add('gone')}

function damage(srcVel,cause){
  if(invuln>0||state!=='playing')return;
  hp--; hits++; lastDamage=cause;
  renderHearts(); vigPulse(); sfx.hurt();
  shake=0.35; flashT=0.2;
  wiz.mats.forEach(m=>{m.emissive.set('#ff5544');m.emissiveIntensity=0.8});
  if(srcVel){_v4.copy(srcVel);_v4.y=0;if(_v4.lengthSq()>0.01){_v4.normalize();player.vel.addScaledVector(_v4,5);player.vel.y=3.5}}
  floater(_v2.copy(player.pos).add(_v3.set(0,2.2,0)),'-1',true);
  if(hp<=0)die();
  else invuln=1.3;
}
function die(){
  state='dead';
  burst(_v1.copy(player.pos).add(_v2.set(0,1,0)),'#7ef0d4',40,5,1.1,0.9,3);
  wiz.root.visible=false;
  sfx.over();
  renderHearts();
  setTimeout(()=>{
    if(state!=='dead')return;
    if(deadMsg)deadMsg.textContent=lastDamage==='fall'
      ?'You slipped beneath the cloud sea. The isles are patient — try once more.'
      :'A warden’s bolt found its mark. Their aim is true, but your feet can be quicker.';
    if(deadStats)deadStats.textContent=`Shards ${score} / ${TOTAL} · Time ${fmt(gameTime)}`;
    showOv(ovDead);
  },1000);
}
function onFall(){
  hp--; hits++; lastDamage='fall';
  renderHearts(); vigPulse(); sfx.hurt(); sfx.whoosh();
  if(hp<=0){die();return}
  player.pos.copy(lastSafe); player.pos.y+=0.2;
  player.vel.set(0,0,0); invuln=1.2;
}
function collect(c){
  c.on=true; score++;
  renderGems(); sfx.collect(score);
  burst(c.g.position,c.col,18,3.5,0.8,0.6,2.5);
  floater(c.g.position,'+1');
  const g=c.g,s0=g.scale.x;
  tween(0.28,k=>{g.scale.setScalar(s0*(1-k));g.position.y=c.baseY+k*1.2},()=>{g.visible=false});
  if(score===TOTAL)triggerWin();
}
function triggerWin(){
  timeScale=0.22;
  sfx.win();
  for(let i=0;i<3;i++){
    const col=['#ffe08a','#7ef0d4','#ffa8c5'][i];
    tween(0.2+i*0.25,()=>{},()=>burst(_v1.copy(player.pos).add(_v2.set((i-1)*1.5,2.5+i*0.7,(i-1)*-1.2)),col,26,4.5,1,0.9,2.5));
  }
  setTimeout(()=>{
    if(state!=='playing'||score<TOTAL)return;
    state='win';
    if(winStats)winStats.textContent=`Time ${fmt(gameTime)} · Hits taken ${hits}`;
    showOv(ovWin);
  },1400);
}

function physics(dt){
  const fA=(keys.KeyW||keys.ArrowUp?1:0)-(keys.KeyS||keys.ArrowDown?1:0);
  const sA=(keys.KeyD||keys.ArrowRight?1:0)-(keys.KeyA||keys.ArrowLeft?1:0);
  const fx=-Math.sin(camYaw),fz=-Math.cos(camYaw),rx=Math.cos(camYaw),rz=-Math.sin(camYaw);
  let mx=fx*fA+rx*sA,mz=fz*fA+rz*sA;
  const ml=Math.hypot(mx,mz);
  if(ml>1){mx/=ml;mz/=ml}
  if(ml>0.01)hintMoved=true;
  const ctrl=grounded?1:0.65;
  player.vel.x+=mx*48*ctrl*dt;
  player.vel.z+=mz*48*ctrl*dt;
  const hs=Math.hypot(player.vel.x,player.vel.z);
  if(ml<=0.01&&grounded){
    const d=Math.exp(-9.5*dt);
    player.vel.x*=d; player.vel.z*=d;
  }else if(hs>MAXSP){
    player.vel.x*=MAXSP/hs; player.vel.z*=MAXSP/hs;
  }

  player.pos.x+=player.vel.x*dt;
  player.pos.z+=player.vel.z*dt;
  for(const o of obstacles){
    if(player.pos.y>o.y+o.h)continue;
    const dx=player.pos.x-o.x,dz=player.pos.z-o.z;
    const d=Math.hypot(dx,dz),min=o.r+PR;
    if(d<min&&d>1e-4){
      player.pos.x=o.x+dx/d*min;
      player.pos.z=o.z+dz/d*min;
    }
  }

  const prevY=player.pos.y;
  player.vel.y-=GRAV*dt;
  player.pos.y+=player.vel.y*dt;
  const g=surfaceHeightAt(player.pos.x,player.pos.z,prevY+STEP);
  prevGrounded=grounded; grounded=false;
  if(player.vel.y<=0&&g>-1e8&&player.pos.y<=g&&(prevY>=g-0.001||player.pos.y>g-0.6)){
    player.pos.y=g;
    if(!prevGrounded){
      const hard=player.vel.y<-11;
      sfx.land(hard);
      dipV-=Math.min(1,Math.abs(player.vel.y)/14)*2.2;
      deformV-=Math.min(1,Math.abs(player.vel.y)/14)*3;
      burst(_v1.set(player.pos.x,g+0.1,player.pos.z),'#efe6d2',hard?12:6,hard?2.6:1.6,0.5,0.4,3,1);
    }
    player.vel.y=0; grounded=true; coyote=0.12;
  }else{
    coyote-=dt;
  }

  jumpBuf-=dt;
  if(jumpBuf>0&&(grounded||coyote>0)){
    player.vel.y=JUMPV; grounded=false; coyote=0; jumpBuf=0;
    sfx.jump(); deformV+=1.4; hintJump=true;
    burst(_v1.set(player.pos.x,player.pos.y+0.1,player.pos.z),'#efe6d2',5,1.4,0.4,0.3,2,0.5);
  }

  if(player.pos.y<KILLY&&state==='playing')onFall();

  if(grounded){
    let safe=false;
    for(const s of surfaces){
      if(s.type==='disc'){
        if(Math.hypot(player.pos.x-s.x,player.pos.z-s.z)<s.r-0.8&&Math.abs(player.pos.y-s.y)<0.3){safe=true;break}
      }else{
        const abx=s.bx-s.ax,abz=s.bz-s.az,L2=abx*abx+abz*abz;
        const t=clamp(((player.pos.x-s.ax)*abx+(player.pos.z-s.az)*abz)/L2,0,1);
        const cx=s.ax+abx*t,cz=s.az+abz*t;
        if(Math.hypot(player.pos.x-cx,player.pos.z-cz)<s.width/2-0.5&&t>0.08&&t<0.92){safe=true;break}
      }
    }
    if(safe)lastSafe.copy(player.pos);
  }

  if(grounded&&hs>1){
    stepAcc+=hs*dt;
    if(stepAcc>2.1){stepAcc=0;sfx.step()}
  }

  if(ml>0.15){
    const target=Math.atan2(player.vel.x,player.vel.z);
    const dh=wrapAngle(target-heading);
    heading+=dh*Math.min(1,dt*10);
    wiz.root.rotation.z=lerp(wiz.root.rotation.z,clamp(-dh*0.6,-0.22,0.22),Math.min(1,dt*8));
  }else{
    wiz.root.rotation.z=lerp(wiz.root.rotation.z,0,Math.min(1,dt*6));
  }
  wiz.root.rotation.y=heading;
  wiz.root.position.copy(player.pos);

  invuln-=dt;
  if(flashT>0){
    flashT-=dt;
    if(flashT<=0)wiz.mats.forEach(m=>{m.emissive.set('#000000');m.emissiveIntensity=0});
  }
  if(invuln>0)wiz.root.visible=Math.floor(perfT*14)%2===0;
  else if(state!=='dead')wiz.root.visible=true;

  if(state==='playing'){
    for(const c of crystals){
      if(c.on)continue;
      const dx=player.pos.x-c.g.position.x,dy=player.pos.y+0.9-c.g.position.y,dz=player.pos.z-c.g.position.z;
      if(dx*dx+dy*dy+dz*dz<2.1)collect(c);
    }
  }
}

function animateWizard(dt){
  const hs=Math.hypot(player.vel.x,player.vel.z),sr=clamp(hs/MAXSP,0,1);
  walkPhase+=dt*(4+hs*1.7);
  deformV+=(-deform*160-deformV*10)*dt;
  deform=clamp(deform+deformV*dt,-0.45,0.5);
  wiz.root.scale.set(1-deform*0.35,1+deform,1-deform*0.35);
  const bob=grounded?Math.abs(Math.sin(walkPhase))*0.09*sr:0;
  wiz.root.position.y=player.pos.y+bob;
  wiz.robe.rotation.x=sr*0.09;
  wiz.robe.scale.x=wiz.robe.scale.z=1+Math.sin(walkPhase*2)*0.03*sr;
  if(!grounded){
    wiz.armL.rotation.x=lerp(wiz.armL.rotation.x,-2.5,Math.min(1,dt*8));
    wiz.armR.rotation.x=lerp(wiz.armR.rotation.x,-2.1,Math.min(1,dt*8));
  }else{
    wiz.armL.rotation.x=Math.sin(walkPhase)*0.55*sr+Math.sin(perfT*1.4)*0.06;
    wiz.armR.rotation.x=-Math.sin(walkPhase)*0.2*sr+Math.sin(perfT*1.4+1)*0.06;
  }
  wiz.head.rotation.y=Math.sin(perfT*0.6)*0.25*(1-sr);
  wiz.hat.rotation.z=Math.sin(walkPhase)*0.05*sr+Math.sin(perfT*1.1)*0.02;
  wiz.orb.position.y=1.62+Math.sin(perfT*2.2)*0.05;
  wiz.orb.rotation.y+=dt*2;
  wiz.orbLight.intensity=2.2+Math.sin(perfT*3.1)*0.6+nightF*1.3;
  if(state==='win'&&grounded){player.vel.y=5.5;grounded=false;heading+=dt*4;wiz.root.rotation.y=heading}
}

function updateCrystals(dt){
  let best=-1,bestD=1e9;
  for(let i=0;i<crystals.length;i++){
    const c=crystals[i];
    if(c.on)continue;
    const d=c.g.position.distanceToSquared(player.pos);
    if(d<bestD){bestD=d;best=i}
  }
  for(let i=0;i<crystals.length;i++){
    const c=crystals[i];
    if(c.on)continue;
    c.g.position.y=c.baseY+Math.sin(perfT*1.8+c.ph)*0.16;
    c.core.rotation.y+=dt*1.4;
    c.core.rotation.x=Math.sin(perfT+c.ph)*0.2;
    c.beam.material.opacity=lerp(c.beam.material.opacity,i===best?0.42:0.13+nightF*0.08,Math.min(1,dt*5));
  }
}

const camPos=new THREE.Vector3(0,10,30),camTarget=new THREE.Vector3();
let camSnap=false,menuAng=0;
function updateCamera(rdt){
  if(state==='menu'){
    menuAng+=rdt*0.1;
    _v1.set(Math.sin(menuAng)*32,9+Math.sin(menuAng*0.6)*2,Math.cos(menuAng)*32);
    camPos.lerp(_v1,Math.min(1,rdt*2));
    camera.position.copy(camPos);
    camera.lookAt(0,2.5,0);
    return;
  }
  camTarget.set(player.pos.x,player.pos.y+1.7,player.pos.z);
  const cp=Math.cos(camPitch);
  _v1.set(Math.sin(camYaw)*cp,Math.sin(camPitch),Math.cos(camYaw)*cp).multiplyScalar(camDist).add(camTarget);
  if(!camSnap){camPos.copy(_v1);camSnap=true}
  camPos.lerp(_v1,1-Math.exp(-rdt*7));
  const gh=surfaceHeightAt(camPos.x,camPos.z,camPos.y+10);
  if(gh>-1e8&&camPos.y<gh+0.6)camPos.y=gh+0.6;
  camera.position.copy(camPos);
  if(shake>0){
    camera.position.x+=(Math.random()-0.5)*shake;
    camera.position.y+=(Math.random()-0.5)*shake;
    shake*=Math.exp(-rdt*6);
  }
  dipV+=(-dip*180-dipV*12)*rdt;
  dip+=dipV*rdt;
  camera.position.y+=dip;
  camera.lookAt(camTarget);
}

function checkHint(){
  if(hintDone||state!=='playing')return;
  if(hintMoved&&hintJump)setTimeout(dismissHint,1200);
}

const clock=new THREE.Clock();
renderer.setAnimationLoop(()=>{
  const rdt=Math.min(clock.getDelta(),0.05);
  perfT+=rdt;
  timeScale+=(1-timeScale)*Math.min(1,rdt*1.6);
  const dt=rdt*timeScale;
  T+=dt;

  if(state==='playing'){
    gameTime+=dt; graceT-=dt;
    physics(dt); checkHint();
  }else if(state==='win'){
    physics(dt);
  }else if(state==='menu'){
    wiz.root.position.set(0,0.05,5.5);
    wiz.head.rotation.y=Math.sin(perfT*0.5)*0.4;
  }
  updateTurrets(dt);
  updateProjs(dt);
  updateCrystals(dt);
  animateWizard(dt);
  updateBursts(dt);
  updateMotes(dt);
  updateClouds(dt);
  updateDrifters(dt);
  updateTweens(dt);
  updateCamera(rdt);
  renderer.render(scene,camera);
});

renderHearts();
</script>
</body>
</html>
Evaluation: Exceptional execution. The physics loop with coyote time, jump buffering, responsive collision response, procedural archipelago terrain generation, Web Audio synthesis, and dynamic day-night transitions all run seamlessly in a single contained bundle.

Final Verdict

Ox Alpha demonstrates remarkable coherence on long-form complex code generation tasks. From vector mathematics to complete 3D interactive game loops, it handles spatial logic and complex state machines with zero hallucinations or broken syntax.
Overall Score: 9.5 / 10