Models 44

Muse Ember

by MetaReasoning1 console error
Open in new window

Running live in a sandboxed frame. Click inside it before using the keyboard.

How it went

Total time
44.4 s
Cost
$0.011
Output tokens
22,740
Spent thinking
11,857 tokens
Speed
536.6 tok/s
Console errors
1
First token after
2.0 s
First visible text after
30.9 s
Prompt tokens
441
Code size
30.9 KB
Finish reason
stop
Served by
Meta
Model id
meta/muse-ember
Reasoning sent
model default
Max output
943,718 tokens
Generated
Nov 12, 2026

Console errors

Caught in the first 3 seconds after load, in a sandboxed iframe like the one above.

Unexpected token '.'

What it was asked

The prompt
“a 3D aquarium with Three.js where the fish swim away when I move the mouse near them (Load Three.js only through this import map: <script type="importmap">{"imports":{"three":"https://cdn.jsdelivr.net/npm/three@0.170.0/build/three.module.js","three/addons/":"https://cdn.jsdelivr.net/npm/three@0.170.0/examples/jsm/"}}</script>)”
System prompt, sent with every prompt
You are generating a self-contained web demo. It will be rendered automatically in a sandboxed iframe and compared side by side with the output of other AI models given the exact same task.

Output rules:
- Reply with exactly ONE fenced code block containing the complete file: ```html (or ```svg when the task asks for an SVG). No text before or after the code block.
- Everything must be inline: CSS in <style>, JavaScript in <script>. No external files, images, fonts or network requests, except the CDN URLs explicitly allowed by the task.
- Do not use localStorage, sessionStorage, cookies, IndexedDB, alert(), confirm(), prompt() or window.open(): they are blocked in the sandbox and will throw.
- The page must look right in a 1280×800 viewport and adapt gracefully down to 375px wide. No horizontal scrollbar.
- Something meaningful must be visible on first paint: a screenshot is taken automatically about 3 seconds after load, without any interaction.
- Everything that makes the demo interesting must be visible within the first seconds: nothing hidden behind a high score, a later level or a long play session.
- Games must start in a self-playing demo mode (a simple AI plays) behind a "Click or press a key to start" message, so the game can be judged in action without playing.
- The iframe only receives keyboard events after the user clicks it: if the demo uses the keyboard, display a clear "Click or press a key to start" message.
- The code must run with zero errors in the console of the latest Chrome.

Code run-1.html · 361 lines

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>3D Aquarium — Shy Fish Flee From Your Cursor</title>
<script type="importmap">{"imports":{"three":"https://cdn.jsdelivr.net/npm/three@0.170.0/build/three.module.js","three/addons/":"https://cdn.jsdelivr.net/npm/three@0.170.0/examples/jsm/"}}</script>
<style>
  *{box-sizing:border-box}
  html,body{margin:0;padding:0;width:100%;height:100%;overflow:hidden;background:#04263f;font-family:system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Inter,Arial,sans-serif;color:#eaf8ff}
  #scene{position:fixed;inset:0}
  #scene canvas{display:block;cursor:crosshair}
  #vignette{position:fixed;inset:0;pointer-events:none;background:radial-gradient(ellipse at 50% 42%,transparent 55%,rgba(2,20,38,.55) 100%);z-index:2}
  .ui{position:fixed;inset:0;pointer-events:none;z-index:5}
  .panel{pointer-events:auto;background:rgba(5,38,62,.62);backdrop-filter:blur(14px);-webkit-backdrop-filter:blur(14px);border:1px solid rgba(125,230,255,.28);border-radius:18px;box-shadow:0 12px 40px rgba(0,0,0,.38),inset 0 1px 0 rgba(255,255,255,.12);padding:16px 18px}
  #titlePanel{position:absolute;top:16px;left:16px;width:min(365px,52vw)}
  .badge{display:inline-flex;align-items:center;gap:7px;font-size:10px;letter-spacing:.16em;font-weight:800;color:#7ff0ff;background:rgba(77,227,255,.12);border:1px solid rgba(125,230,255,.35);padding:5px 9px;border-radius:999px}
  .dot{width:7px;height:7px;border-radius:50%;background:#4effa6;box-shadow:0 0 10px #4effa6;animation:pulse 1.4s infinite}
  @keyframes pulse{0%,100%{opacity:1;transform:scale(1)}50%{opacity:.45;transform:scale(.75)}}
  h1{margin:10px 0 7px;font-size:clamp(24px,3.4vw,38px);line-height:.95;letter-spacing:-.02em;text-shadow:0 4px 24px rgba(0,200,255,.35)}
  #titlePanel p{margin:0;font-size:13.5px;line-height:1.5;color:#cfeeff}
  #titlePanel p b{color:#ffe27a}
  .modeRow{margin-top:12px}
  #modeLabel{display:inline-block;font-size:12px;font-weight:700;color:#0a2e44;background:linear-gradient(135deg,#7ff0ff,#4effa6);padding:7px 10px;border-radius:999px;box-shadow:0 4px 16px rgba(77,227,255,.35)}
  #statsPanel{position:absolute;top:16px;right:16px;width:248px}
  .stat{display:flex;justify-content:space-between;align-items:center;padding:6px 0;border-bottom:1px solid rgba(255,255,255,.09);font-size:13px;color:#bfeaff}
  .stat strong{font-size:18px;color:#fff;min-width:38px;text-align:right}
  .stat.pop strong{animation:pop .35s ease}
  @keyframes pop{0%{transform:scale(1)}45%{transform:scale(1.55);color:#ffe27a}100%{transform:scale(1)}}
  #status{margin:10px 0 4px;text-align:center;font-weight:900;letter-spacing:.06em;font-size:12px;padding:7px;border-radius:999px;background:rgba(78,255,166,.18);color:#8affc2;border:1px solid rgba(78,255,166,.4)}
  #status.danger{background:rgba(255,90,90,.22);color:#ff9a9a;border-color:rgba(255,120,120,.6);animation:blink .45s infinite alternate}
  @keyframes blink{from{transform:scale(1)}to{transform:scale(1.035)}}
  label{display:block;font-size:12px;font-weight:700;color:#d8f6ff;margin-top:11px}
  label span{float:right;color:#7ff0ff}
  input[type=range]{width:100%;margin-top:6px;accent-color:#4de3ff;height:22px;cursor:pointer}
  .btnRow{display:flex;gap:7px;margin-top:13px;flex-wrap:wrap}
  button{flex:1;border:0;border-radius:999px;padding:9px 8px;font-weight:800;font-size:12px;cursor:pointer;color:#062a42;background:linear-gradient(135deg,#7ff0ff,#3ec6ff);box-shadow:0 4px 14px rgba(77,227,255,.3);transition:transform .12s,filter .12s;white-space:nowrap}
  button:hover{transform:translateY(-1px);filter:brightness(1.08)}button:active{transform:scale(.96)}
  button:nth-child(2){background:linear-gradient(135deg,#ffe27a,#ffb86b)}button:nth-child(3){background:linear-gradient(135deg,#d6f7ff,#9be8ff)}
  .hint{position:absolute;left:50%;bottom:16px;transform:translateX(-50%);pointer-events:none;background:rgba(4,32,54,.68);backdrop-filter:blur(12px);border:1px solid rgba(125,230,255,.25);padding:10px 16px;border-radius:999px;font-size:12.5px;font-weight:600;color:#dff8ff;white-space:nowrap;box-shadow:0 8px 28px rgba(0,0,0,.3)}
  .hint b{color:#ffe27a}
  #legend{position:absolute;left:16px;bottom:16px;pointer-events:none;background:rgba(4,32,54,.55);backdrop-filter:blur(10px);border:1px solid rgba(125,230,255,.2);border-radius:999px;padding:8px 12px;font-size:11px;color:#cfeeff;display:flex;gap:10px;align-items:center}
  .ld{display:inline-flex;align-items:center;gap:5px}.ld i{width:9px;height:9px;border-radius:50%;display:inline-block;box-shadow:0 0 6px rgba(255,255,255,.4)}
  @media (max-width:640px){
    #titlePanel{top:10px;left:10px;width:48vw;padding:12px 13px}
    h1{font-size:21px;margin:8px 0 5px}
    #titlePanel p{font-size:11px;line-height:1.35}
    #modeLabel{font-size:10px;padding:5px 7px}
    #statsPanel{top:10px;right:10px;width:158px;padding:11px 12px}
    .stat{font-size:11px;padding:4px 0}.stat strong{font-size:15px}
    label{font-size:10px;margin-top:8px}button{font-size:10px;padding:7px 5px}
    .hint{left:10px;right:10px;transform:none;white-space:normal;text-align:center;font-size:11px;padding:8px 10px;bottom:10px;border-radius:14px}
    #legend{display:none}
  }
</style>
</head>
<body>
<div id="scene"></div>
<div id="vignette"></div>
<div class="ui">
  <div class="panel" id="titlePanel">
    <span class="badge"><span class="dot"></span>LIVE • THREE.JS AQUARIUM</span>
    <h1>🫧 3D Aquarium</h1>
    <p>Shy fish! Move your cursor <b>near a fish</b> and it will dart away. The glowing orb is the danger zone — watch them flee.</p>
    <div class="modeRow"><span id="modeLabel">🤖 Demo cursor — moving on its own</span></div>
  </div>
  <div class="panel" id="statsPanel">
    <div class="stat"><span>🐠 Fish</span><strong id="fishCount">24</strong></div>
    <div class="stat" id="startledStat"><span>💨 Startled</span><strong id="startledCount">0</strong></div>
    <div class="stat"><span>📏 Nearest fish</span><strong id="nearestDist">—</strong></div>
    <div id="status">😌 CALM</div>
    <label>Fear radius <span id="fearVal">2.0m</span><input type="range" id="fearRange" min="0.8" max="3.5" step="0.1" value="2"></label>
    <label>Swim speed <span id="speedVal">1.0×</span><input type="range" id="speedRange" min="0.4" max="2" step="0.1" value="1"></label>
    <div class="btnRow"><button id="scatterBtn">💥 Scatter</button><button id="feedBtn">🍤 Feed</button><button id="pauseBtn">⏸ Pause</button></div>
  </div>
  <div id="legend"><span class="ld"><i style="background:#ff7a1a"></i>Clownfish</span><span class="ld"><i style="background:#1e6bff"></i>Blue Tang</span><span class="ld"><i style="background:#ffd93b"></i>Yellow</span><span class="ld"><i style="background:#ff5d8f"></i>Anthias</span><span class="ld"><i style="background:#2ec4b6"></i>Chromis</span></div>
  <div class="hint">🖱 Move near a fish to <b>scare it</b> &nbsp;•&nbsp; Click water to drop food &nbsp;•&nbsp; Drag to orbit &nbsp;•&nbsp; Scroll to zoom</div>
</div>

<script type="module">
import * as THREE from 'three';
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';

const container=document.getElementById('scene');
const rand=(a,b)=>a+Math.random()*(b-a);
const clamp=(v,a,b)=>Math.max(a,Math.min(b,v));

// Renderer / Scene / Camera
const renderer=new THREE.WebGLRenderer({antialias:true});
renderer.setPixelRatio(Math.min(devicePixelRatio,2));
renderer.setSize(innerWidth,innerHeight);
renderer.outputColorSpace=THREE.SRGBColorSpace;
renderer.toneMapping=THREE.ACESFilmicToneMapping;
renderer.toneMappingExposure=1.15;
container.appendChild(renderer.domElement);

const scene=new THREE.Scene();
scene.background=new THREE.Color(0x06314f);
scene.fog=new THREE.FogExp2(0x06314f,0.032);

const camera=new THREE.PerspectiveCamera(50,innerWidth/innerHeight,0.1,100);
camera.position.set(0,1.35,10.4);
const controls=new OrbitControls(camera,renderer.domElement);
controls.target.set(0,0.1,0);
controls.enableDamping=true; controls.dampingFactor=0.06;
controls.minDistance=6; controls.maxDistance=16;
controls.maxPolarAngle=1.68; controls.minPolarAngle=0.55; controls.enablePan=false;

scene.add(new THREE.HemisphereLight(0xbfefff,0x133548,1.0));
scene.add(new THREE.AmbientLight(0x88ccee,0.5));
const sun=new THREE.DirectionalLight(0xffffff,2.0); sun.position.set(5,9,6); scene.add(sun);
const fill=new THREE.PointLight(0x33bbff,28,24,2); fill.position.set(-5,3,4); scene.add(fill);
const fill2=new THREE.PointLight(0xff8fab,10,18,2); fill2.position.set(5,-1,-3); scene.add(fill2);

// Tank bounds
const BOUNDS={x:4.8,yMin:-2.05,yMax:2.15,z:2.55};

// Glow texture
function radialTex(){const c=document.createElement('canvas');c.width=c.height=128;const g=c.getContext('2d');const gr=g.createRadialGradient(64,64,2,64,64,64);gr.addColorStop(0,'rgba(255,255,255,1)');gr.addColorStop(.35,'rgba(140,240,255,.55)');gr.addColorStop(1,'rgba(80,220,255,0)');g.fillStyle=gr;g.fillRect(0,0,128,128);return new THREE.CanvasTexture(c);}
function exclaimTex(){const c=document.createElement('canvas');c.width=c.height=96;const g=c.getContext('2d');g.font='900 72px Arial';g.textAlign='center';g.textBaseline='middle';g.lineWidth=10;g.strokeStyle='#062a42';g.strokeText('!',48,50);g.fillStyle='#ffe27a';g.fillText('!',48,50);return new THREE.CanvasTexture(c);}
const glowTex=radialTex(), exTex=exclaimTex();

// Tank glass + frame
const tankGeo=new THREE.BoxGeometry(10.6,5.4,5.7);
const glass=new THREE.Mesh(tankGeo,new THREE.MeshPhysicalMaterial({color:0xaeeeff,transparent:true,opacity:0.055,roughness:0.06,metalness:0,side:THREE.DoubleSide,depthWrite:false}));
glass.position.y=0.15; scene.add(glass);
const edges=new THREE.LineSegments(new THREE.EdgesGeometry(tankGeo),new THREE.LineBasicMaterial({color:0x7fe7ff,transparent:true,opacity:0.85}));
edges.position.copy(glass.position); scene.add(edges);
const rimMat=new THREE.MeshStandardMaterial({color:0x9beeff,roughness:.25,metalness:.7,emissive:0x226688,emissiveIntensity:.4});
[[0,2.9,2.87,10.7,.09,.09],[0,2.9,-2.87,10.7,.09,.09],[5.33,2.9,0,.09,.09,5.8],[-5.33,2.9,0,.09,.09,5.8]].forEach(([x,y,z,w,h,d])=>{const m=new THREE.Mesh(new THREE.BoxGeometry(w,h,d),rimMat);m.position.set(x,y,z);scene.add(m);});

// Sand
const sandGeo=new THREE.PlaneGeometry(11,6.2,42,26); sandGeo.rotateX(-Math.PI/2);
{const p=sandGeo.attributes.position;for(let i=0;i<p.count;i++){const x=p.getX(i),z=p.getZ(i);p.setY(i,Math.sin(x*1.4)*Math.cos(z*1.8)*.09+Math.sin(x*3.1+z*2)*.035);}sandGeo.computeVertexNormals();}
const sand=new THREE.Mesh(sandGeo,new THREE.MeshStandardMaterial({color:0xd9c48f,roughness:1})); sand.position.y=-2.62; scene.add(sand);

// Rocks, coral, seaweed, starfish, shell
const rockMat=new THREE.MeshStandardMaterial({color:0x5f7585,roughness:.95,flatShading:true});
const seaweeds=[], jellies=[];
function rock(x,y,z,s){const m=new THREE.Mesh(new THREE.DodecahedronGeometry(s,0),rockMat);m.position.set(x,y,z);m.rotation.set(rand(0,3),rand(0,3),rand(0,3));m.scale.y=.7;scene.add(m);return m;}
rock(-3.6,-2.25,-1.8,1.0);rock(-2.8,-2.35,-1.2,.7);rock(3.4,-2.25,-1.6,.9);rock(4.1,-2.35,-.5,.6);rock(0.5,-2.4,-2.1,.8);rock(-4.4,-2.3,.8,.65);rock(4.3,-2.3,1.0,.55);
function coral(x,y,z,color,s){const g=new THREE.Group();const mat=new THREE.MeshStandardMaterial({color,roughness:.6,emissive:color,emissiveIntensity:.18});
 for(let i=0;i<7;i++){const h=rand(.35,.85)*s;const c=new THREE.Mesh(new THREE.ConeGeometry(.09*s,h,7),mat);c.position.set(rand(-.35,.35)*s,h/2,rand(-.3,.3)*s);c.rotation.set(rand(-.4,.4),0,rand(-.5,.5));g.add(c);}
 for(let i=0;i<5;i++){const b=new THREE.Mesh(new THREE.SphereGeometry(.13*s,10,8),mat);b.position.set(rand(-.45,.45)*s,rand(.2,.7)*s,rand(-.35,.35)*s);g.add(b);}
 g.position.set(x,y,z);scene.add(g);}
coral(-3.7,-2.15,-1.7,0xff5d8f,1.1);coral(3.5,-2.15,-1.5,0xff9f45,1.0);coral(-.2,-2.3,-2.0,0xf15bb5,.9);coral(4.0,-2.25,-.6,0xff6b6b,.8);coral(-4.3,-2.25,.9,0xffa62b,.75);
function seaweed(x,z,h){const g=new THREE.Group();const mat=new THREE.MeshStandardMaterial({color:0x1db954,roughness:.7,side:THREE.DoubleSide,emissive:0x0a4420,emissiveIntensity:.25});
 for(let i=0;i<5;i++){const b=new THREE.Mesh(new THREE.PlaneGeometry(.17,h,1,5),mat);b.position.set(rand(-.3,.3),h/2,rand(-.2,.2));b.rotation.y=rand(0,3);g.add(b);}
 g.position.set(x,-2.55,z);g.userData.phase=rand(0,6);scene.add(g);seaweeds.push(g);}
seaweed(-4.8,-1.2,2.2);seaweed(-4.4,-.3,1.7);seaweed(4.7,-1.0,2.0);seaweed(4.5,.4,1.6);seaweed(-1.8,-2.2,1.4);seaweed(2.2,-2.2,1.5);seaweed(5.0,1.2,1.8);seaweed(-5.0,1.0,1.5);
// starfish
{const sh=new THREE.Shape();for(let i=0;i<10;i++){const r=i%2? .16:.42,a=i*Math.PI/5;const x=Math.cos(a)*r,y=Math.sin(a)*r;i?sh.lineTo(x,y):sh.moveTo(x,y);}sh.closePath();const m=new THREE.Mesh(new THREE.ExtrudeGeometry(sh,{depth:.07,bevelEnabled:true,bevelSize:.03,bevelThickness:.03}),new THREE.MeshStandardMaterial({color:0xff8c42,roughness:.7,emissive:0x552200,emissiveIntensity:.3}));m.rotation.x=-Math.PI/2;m.position.set(2.4,-2.52,1.2);scene.add(m);
 const shell=new THREE.Mesh(new THREE.TorusGeometry(.22,.12,10,20,Math.PI*1.4),new THREE.MeshStandardMaterial({color:0xffd6e8,roughness:.4,emissive:0x442233,emissiveIntensity:.2}));shell.position.set(-2.6,-2.45,1.4);shell.rotation.set(.6,.4,.5);scene.add(shell);}

// Jellyfish
function jelly(x,y,z,color){const g=new THREE.Group();const mat=new THREE.MeshStandardMaterial({color,transparent:true,opacity:.62,roughness:.3,emissive:color,emissiveIntensity:.45,side:THREE.DoubleSide});
 const dome=new THREE.Mesh(new THREE.SphereGeometry(.62,20,12,0,Math.PI*2,0,Math.PI/2),mat);g.add(dome);
 const tentMat=new THREE.MeshBasicMaterial({color,transparent:true,opacity:.5});
 for(let i=0;i<7;i++){const a=i/7*Math.PI*2;const t=new THREE.Mesh(new THREE.CylinderGeometry(.015,.008,1.9,5),tentMat);t.position.set(Math.cos(a)*.35,-.95,Math.sin(a)*.35);g.add(t);}
 g.position.set(x,y,z);g.userData={bx:x,by:y,ph:rand(0,6)};scene.add(g);jellies.push(g);}
jelly(-3.2,1.2,-2.2,0xf15bb5); jelly(3.6,.6,-2.3,0x7fdcff); jelly(1.8,1.7,-2.4,0xff9f45);

// Water surface
const waterGeo=new THREE.PlaneGeometry(10.6,5.7,22,12); waterGeo.rotateX(Math.PI/2);
const waterBase=waterGeo.attributes.position.array.slice();
const water=new THREE.Mesh(waterGeo,new THREE.MeshBasicMaterial({color:0x8feeff,transparent:true,opacity:.16,side:THREE.DoubleSide,depthWrite:false}));
water.position.y=2.78; scene.add(water);
// Light rays
const rays=[];
for(let i=0;i<4;i++){const r=new THREE.Mesh(new THREE.PlaneGeometry(rand(.7,1.4),6.5),new THREE.MeshBasicMaterial({color:0xaaf4ff,transparent:true,opacity:.06,side:THREE.DoubleSide,blending:THREE.AdditiveBlending,depthWrite:false}));r.position.set(-4+i*2.6,1.2,-1+rand(-.5,.5));r.rotation.z=.38;r.rotation.y=rand(-.3,.3);scene.add(r);rays.push(r);}
// Marine snow
const snowCount=320, snowPos=new Float32Array(snowCount*3);
for(let i=0;i<snowCount;i++){snowPos[i*3]=rand(-5,5);snowPos[i*3+1]=rand(-2.5,2.7);snowPos[i*3+2]=rand(-2.6,2.6);}
const snowGeo=new THREE.BufferGeometry(); snowGeo.setAttribute('position',new THREE.BufferAttribute(snowPos,3));
const snow=new THREE.Points(snowGeo,new THREE.PointsMaterial({color:0xdff8ff,size:.055,transparent:true,opacity:.55})); scene.add(snow);

// Fish factory
const variants=[
 {name:'Clownfish',color:0xff7a1a,tail:0xffa640,stripe:true,scale:.58},
 {name:'BlueTang',color:0x1e6bff,tail:0xffd23f,scale:.72},
 {name:'Yellow',color:0xffd93b,tail:0xffb703,scale:.52},
 {name:'Anthias',color:0xff5d8f,tail:0xff8fab,scale:.46},
 {name:'Chromis',color:0x2ec4b6,tail:0x06d6a0,scale:.5},
 {name:'Purple',color:0x9b5de5,tail:0xf15bb5,scale:.56},
 {name:'Silver',color:0xced4da,tail:0xadb5bd,scale:.62},
 {name:'Coral',color:0xff6b6b,tail:0xff9f68,scale:.5},
];
const bodyGeo=new THREE.SphereGeometry(.5,22,16);
const eyeWGeo=new THREE.SphereGeometry(.085,10,8), eyeBGeo=new THREE.SphereGeometry(.042,8,8);
function finShape(pts){const s=new THREE.Shape();s.moveTo(pts[0][0],pts[0][1]);for(let i=1;i<pts.length;i++)s.lineTo(pts[i][0],pts[i][1]);s.closePath();return new THREE.ExtrudeGeometry(s,{depth:.05,bevelEnabled:false});}
const tailGeo=finShape([[0,0],[.58,.4],[.44,0],[.58,-.4]]);
const dorsalGeo=finShape([[-.38,0],[0,.32],[.38,0]]);
function makeFish(cfg){
 const group=new THREE.Group(), bodyGroup=new THREE.Group(); group.add(bodyGroup);
 const mat=new THREE.MeshStandardMaterial({color:cfg.color,roughness:.35,metalness:.15,emissive:cfg.color,emissiveIntensity:.08});
 const body=new THREE.Mesh(bodyGeo,mat); body.scale.set(.62,.92,1.5); bodyGroup.add(body);
 const belly=new THREE.Mesh(bodyGeo,new THREE.MeshStandardMaterial({color:0xffffff,roughness:.5,transparent:true,opacity:.22})); belly.scale.set(.5,.7,1.25); belly.position.y=-.12; bodyGroup.add(belly);
 const tailMat=new THREE.MeshStandardMaterial({color:cfg.tail,roughness:.4,emissive:cfg.tail,emissiveIntensity:.12,side:THREE.DoubleSide});
 const tail=new THREE.Mesh(tailGeo,tailMat); tail.rotation.y=Math.PI/2; tail.position.set(0,0,-.62); bodyGroup.add(tail);
 const dorsal=new THREE.Mesh(dorsalGeo,tailMat); dorsal.rotation.y=Math.PI/2; dorsal.position.set(0,.38,.05); dorsal.scale.set(1,1,1); bodyGroup.add(dorsal);
 if(cfg.stripe){const white=new THREE.MeshStandardMaterial({color:0xffffff,roughness:.45});
   [[.16,.82,1.18],[-.26,.72,1.0]].forEach(([z,sx,sy])=>{const t=new THREE.Mesh(new THREE.TorusGeometry(.38,.07,10,26),white);t.scale.set(sx,sy,1);t.position.z=z;bodyGroup.add(t);});}
 const eyeMat=new THREE.MeshBasicMaterial({color:0xffffff}), pupilMat=new THREE.MeshBasicMaterial({color:0x111111});
 [-1,1].forEach(side=>{const e=new THREE.Mesh(eyeWGeo,eyeMat);e.position.set(side*.27,.13,.38);bodyGroup.add(e);const p=new THREE.Mesh(eyeBGeo,pupilMat);p.position.set(side*.34,.13,.42);bodyGroup.add(p);});
 const finMat=tailMat; const fins=[];
 [-1,1].forEach(side=>{const f=new THREE.Mesh(bodyGeo,finMat);f.scale.set(.08,.32,.55);f.position.set(side*.34,-.08,.22);f.rotation.z=side*.5;bodyGroup.add(f);fins.push(f);});
 const ex=new THREE.Sprite(new THREE.SpriteMaterial({map:exTex,transparent:true,opacity:0,depthWrite:false})); ex.scale.set(.55,.55,1); ex.position.set(0,.62,0); group.add(ex);
 group.scale.setScalar(cfg.scale);
 return {group,bodyGroup,tail,fins,mat,ex,exTimer:0,vel:new THREE.Vector3(rand(-1,1),0,rand(-1,1)).normalize().multiplyScalar(rand(.6,1.1)),target:new THREE.Vector3(rand(-4,4),rand(-1.5,1.8),rand(-2,2)),speed:rand(.85,1.35),panic:0,cooldown:0,phase:rand(0,6),cfg,nom:0};
}
const fish=[]; const cfgs=[...variants,...variants,...variants].slice(0,24);
for(let i=cfgs.length-1;i>0;i--){const j=Math.floor(Math.random()*(i+1));[cfgs[i],cfgs[j]]=[cfgs[j],cfgs[i]];}
cfgs.forEach((cfg,i)=>{const f=makeFish(cfg);f.group.position.set(rand(-4.2,4.2),rand(-1.6,1.9),rand(-2.2,2.2));if(i<4)f.group.position.set(rand(-1.2,1.2),rand(.2,1.1),rand(.4,1.4));scene.add(f.group);fish.push(f);});
document.getElementById('fishCount').textContent=fish.length;

// Cursor orb + fear zone + trail
const orb=new THREE.Group();
const core=new THREE.Mesh(new THREE.SphereGeometry(.13,18,14),new THREE.MeshBasicMaterial({color:0xbffbff})); orb.add(core);
const glow=new THREE.Sprite(new THREE.SpriteMaterial({map:glowTex,transparent:true,opacity:.95,depthWrite:false,blending:THREE.AdditiveBlending})); glow.scale.set(1.15,1.15,1); orb.add(glow);
const orbRing=new THREE.Mesh(new THREE.TorusGeometry(.28,.018,8,40),new THREE.MeshBasicMaterial({color:0x7ff0ff,transparent:true,opacity:.9})); orb.add(orbRing);
const orbLight=new THREE.PointLight(0x66eaff,9,7,2); orb.add(orbLight);
const fearSphere=new THREE.Mesh(new THREE.SphereGeometry(1,28,18),new THREE.MeshBasicMaterial({color:0x4de3ff,transparent:true,opacity:.065,depthWrite:false,side:THREE.DoubleSide})); orb.add(fearSphere);
const fearWire=new THREE.Mesh(new THREE.SphereGeometry(1,18,10),new THREE.MeshBasicMaterial({color:0x4de3ff,transparent:true,opacity:.13,wireframe:true,depthWrite:false})); orb.add(fearWire);
scene.add(orb);
const trailHist=[]; const trailGeo=new THREE.BufferGeometry(); const trailPos=new Float32Array(30*3); trailGeo.setAttribute('position',new THREE.BufferAttribute(trailPos,3));
const trail=new THREE.Line(trailGeo,new THREE.LineBasicMaterial({color:0x7ff0ff,transparent:true,opacity:.5})); scene.add(trail);

// Bubbles pool
const bubbles=[]; const bubGeo=new THREE.SphereGeometry(.06,10,8); const bubMat=new THREE.MeshBasicMaterial({color:0xcff6ff,transparent:true,opacity:.5});
for(let i=0;i<150;i++){const m=new THREE.Mesh(bubGeo,bubMat);m.visible=false;m.userData={active:false,vel:new THREE.Vector3(),life:0,base:1};scene.add(m);bubbles.push(m);}
function spawnBubble(pos,vel,life=1.4,scale=1){const b=bubbles.find(x=>!x.userData.active);if(!b)return;b.userData.active=true;b.userData.life=life;b.userData.base=scale;b.visible=true;b.position.copy(pos);b.userData.vel.copy(vel);b.scale.setScalar(scale);}
function burst(pos,n=6){for(let i=0;i<n;i++){spawnBubble(pos,new THREE.Vector3(rand(-.7,.7),rand(.5,1.4),rand(-.7,.7)),rand(.7,1.3),rand(.6,1.4));}}
let bubTimer=0;

// Food & ripples
const pellets=[]; const pelletGeo=new THREE.SphereGeometry(.075,10,8); const pelletMat=new THREE.MeshStandardMaterial({color:0xc47a3a,roughness:.8});
function spawnFood(at){for(let i=0;i<6;i++){const m=new THREE.Mesh(pelletGeo,pelletMat);m.position.copy(at).add(new THREE.Vector3(rand(-.4,.4),rand(-.2,.3),rand(-.4,.4)));m.userData={life:7,ph:rand(0,6)};scene.add(m);pellets.push(m);} spawnRipple(at);}
const ripples=[];
function spawnRipple(at){const m=new THREE.Mesh(new THREE.RingGeometry(.82,1,42),new THREE.MeshBasicMaterial({color:0x7ff0ff,transparent:true,opacity:.85,side:THREE.DoubleSide,depthWrite:false}));m.position.copy(at);m.lookAt(camera.position);m.userData.life=.75;scene.add(m);ripples.push(m);}

// Pointer / demo logic
let fearRadius=2.0, speedFactor=1.0, paused=false, startled=0;
const raycaster=new THREE.Raycaster(), pointerPlane=new THREE.Plane(new THREE.Vector3(0,0,1),0);
const pointerNDC=new THREE.Vector2(0,0), pointerTarget=new THREE.Vector3(0,.6,1), pointer3D=new THREE.Vector3(0,.6,1);
let lastMove=-9999, demoMode=true, demoT=0, downX=0, downY=0, downT=0;
const modeLabel=document.getElementById('modeLabel'), statusEl=document.getElementById('status'), nearestEl=document.getElementById('nearestDist');
let lastMode='', lastStatus='';
window.addEventListener('pointermove',e=>{pointerNDC.set((e.clientX/innerWidth)*2-1,-(e.clientY/innerHeight)*2+1);lastMove=performance.now();});
renderer.domElement.addEventListener('pointerdown',e=>{downX=e.clientX;downY=e.clientY;downT=performance.now();pointerNDC.set((e.clientX/innerWidth)*2-1,-(e.clientY/innerHeight)*2+1);lastMove=performance.now();});
renderer.domElement.addEventListener('pointerup',e=>{if(Math.hypot(e.clientX-downX,e.clientY-downY)<6 && performance.now()-downT<450){burst(pointer3D,7);spawnFood(pointer3D);}});

// UI
const startledEl=document.getElementById('startledCount'), startledStat=document.getElementById('startledStat');
function bumpStartled(){startled++;startledEl.textContent=startled;startledStat.classList.remove('pop');void startledStat.offsetWidth;startledStat.classList.add('pop');}
document.getElementById('fearRange').addEventListener('input',e=>{fearRadius=parseFloat(e.target.value);document.getElementById('fearVal').textContent=fearRadius.toFixed(1)+'m';});
document.getElementById('speedRange').addEventListener('input',e=>{speedFactor=parseFloat(e.target.value);document.getElementById('speedVal').textContent=speedFactor.toFixed(1)+'×';});
document.getElementById('scatterBtn').addEventListener('click',()=>{fish.forEach(f=>{f.panic=1;f.cooldown=Math.max(f.cooldown,.8);const d=f.group.position.clone().sub(pointer3D).normalize();f.vel.add(d.multiplyScalar(2.2));f.target.set(rand(-4,4),rand(-1.5,1.8),rand(-2,2));burst(f.group.position,3);});burst(pointer3D,14);spawnRipple(pointer3D);});
document.getElementById('feedBtn').addEventListener('click',()=>spawnFood(pointer3D));
const pauseBtn=document.getElementById('pauseBtn');
function togglePause(){paused=!paused;pauseBtn.textContent=paused?'▶ Resume':'⏸ Pause';}
pauseBtn.addEventListener('click',togglePause);
window.addEventListener('keydown',e=>{if(e.code==='Space'){e.preventDefault();togglePause();} if(e.key==='f'||e.key==='F')spawnFood(pointer3D); if(e.key==='s'||e.key==='S')document.getElementById('scatterBtn').click();});

// Temp vectors
const _desired=new THREE.Vector3(), _targetVel=new THREE.Vector3(), _dir=new THREE.Vector3(), _hit=new THREE.Vector3(), _prevQ=new THREE.Quaternion(), _targetQ=new THREE.Quaternion(), _look=new THREE.Vector3();
const upVec=new THREE.Vector3(0,1,0);
function pickTarget(f){f.target.set(rand(-4.3,4.3),rand(-1.7,1.9),rand(-2.2,2.2));}
function updateFish(dt,t){
 let nearest=999;
 for(const f of fish){
  const pos=f.group.position;
  const dist=pointer3D.distanceTo(pos); nearest=Math.min(nearest,dist);
  f.cooldown-=dt; f.panic=Math.max(0,f.panic-dt*1.4);
  const fleeing=dist<fearRadius;
  if(fleeing){
    const strength=1-dist/fearRadius;
    f.panic=Math.max(f.panic,strength);
    if(dist<fearRadius*.98 && strength>.22 && f.cooldown<=0){f.cooldown=1.4;bumpStartled();burst(pos,6);f.exTimer=.65;pickTarget(f);}
  }
  _desired.set(0,0,0);
  if(pos.distanceTo(f.target)<.55) pickTarget(f);
  _dir.copy(f.target).sub(pos).normalize(); _desired.add(_dir.multiplyScalar(.9));
  // food seeking
  if(f.panic<.25 && pellets.length){let best=null,bd=1e9;for(const p of pellets){const d=pos.distanceTo(p.position);if(d<bd){bd=d;best=p;}} if(best&&bd<4.5){_dir.copy(best.position).sub(pos).normalize();_desired.add(_dir.multiplyScalar(1.6));}}
  // flee (dominant)
  if(fleeing){const s=1-dist/fearRadius;_dir.copy(pos).sub(pointer3D).normalize();_desired.add(_dir.multiplyScalar(2+s*6));}
  // separation
  for(const o of fish){if(o===f)continue;const d=pos.distanceTo(o.group.position);if(d<.62&&d>0.001){_dir.copy(pos).sub(o.group.position).normalize();_desired.add(_dir.multiplyScalar((.62-d)*1.6));}}
  // bounds
  if(pos.x>4.2)_desired.x-=(pos.x-4.2)*3; if(pos.x<-4.2)_desired.x-=(pos.x+4.2)*3;
  if(pos.y>1.8)_desired.y-=(pos.y-1.8)*3; if(pos.y<-1.8)_desired.y-=(pos.y+1.8)*3;
  if(pos.z>2.2)_desired.z-=(pos.z-2.2)*3; if(pos.z<-2.2)_desired.z-=(pos.z+2.2)*3;
  if(!paused){
    if(_desired.lengthSq()>0.001){_targetVel.copy(_desired).normalize().multiplyScalar(f.speed*speedFactor*(f.panic>.2?2.7:1));_targetVel.y+=Math.sin(t*2+f.phase)*.12;
      f.vel.lerp(_targetVel,1-Math.exp(-dt*(f.panic>.2?6.5:2.6)));
      const maxS=f.panic>.2?4.6:2.2*speedFactor; if(f.vel.length()>maxS)f.vel.setLength(maxS);
    }
    pos.addScaledVector(f.vel,dt);
    pos.x=clamp(pos.x,-BOUNDS.x,BOUNDS.x);pos.y=clamp(pos.y,BOUNDS.yMin,BOUNDS.yMax);pos.z=clamp(pos.z,-BOUNDS.z,BOUNDS.z);
    // eat
    for(let i=pellets.length-1;i>=0;i--){if(pos.distanceTo(pellets[i].position)<.28){scene.remove(pellets[i]);pellets.splice(i,1);f.nom=.3;burst(pos,2);}}
    // orientation smoothing via lookAt capture
    _look.copy(pos).add(f.vel); if(_look.distanceToSquared(pos)>.0001){_prevQ.copy(f.group.quaternion);f.group.lookAt(_look);_targetQ.copy(f.group.quaternion);f.group.quaternion.copy(_prevQ).slerp(_targetQ,1-Math.exp(-dt*9));}
    const wagSpeed=f.panic>.2?26:11+ f.vel.length()*4;
    f.phase+=dt*wagSpeed;
    f.tail.rotation.y=Math.PI/2+Math.sin(f.phase)*.65;
    f.bodyGroup.rotation.y=Math.sin(f.phase*.55)*.16;
    f.bodyGroup.position.y=Math.sin(t*2.2+f.phase)*.03;
    f.fins.forEach((fin,i)=>{fin.rotation.x=Math.sin(f.phase*1.3+i*Math.PI)*.5;});
    const stretch=f.panic>.2?1.22:1; f.group.scale.setScalar(f.cfg.scale*stretch);
    f.mat.emissiveIntensity=f.panic>.2?.55:.08;
    if(f.nom>0){f.nom-=dt;f.bodyGroup.scale.setScalar(1+f.nom*.5);}else f.bodyGroup.scale.setScalar(1);
  }
  f.exTimer-=dt; f.ex.material.opacity=clamp(f.exTimer/.65,0,1); f.ex.position.y=.62+Math.sin(t*14)*.03;
 }
 return nearest;
}

const clock=new THREE.Clock(); let meterTimer=0;
renderer.setAnimationLoop(()=>{
 const dt=Math.min(clock.getDelta(),.033), t=clock.elapsedTime;
 controls.update();
 // pointer target
 demoMode=(performance.now()-lastMove>3000);
 const modeTxt=demoMode?'🤖 Demo cursor — moving on its own':'🎯 Your cursor — fish fear you!';
 if(modeTxt!==lastMode){modeLabel.textContent=modeTxt;lastMode=modeTxt;}
 if(demoMode){demoT+=dt;pointerTarget.set(Math.sin(demoT*.6)*3.6+Math.sin(demoT*1.3)*.4,.6+Math.sin(demoT*.92)*1.25,Math.cos(demoT*.45)*1.35);}
 else{raycaster.setFromCamera(pointerNDC,camera);if(raycaster.ray.intersectPlane(pointerPlane,_hit))pointerTarget.copy(_hit);}
 pointer3D.lerp(pointerTarget,1-Math.exp(-dt*11));
 orb.position.copy(pointer3D);
 const pulse=1+Math.sin(t*3.2)*.05; orbRing.rotation.x=t*1.4; orbRing.rotation.y=t*1.1; glow.material.opacity=.8+Math.sin(t*4)*.15;
 fearSphere.scale.setScalar(fearRadius*pulse); fearWire.scale.setScalar(fearRadius*pulse);
 // trail
 trailHist.unshift(pointer3D.clone()); if(trailHist.length>30)trailHist.pop();
 trailHist.forEach((p,i)=>{trailPos[i*3]=p.x;trailPos[i*3+1]=p.y;trailPos[i*3+2]=p.z;}); trailGeo.attributes.position.needsUpdate=true;
 // fish
 const nearest=paused?999:updateFish(dt,t);
 meterTimer+=dt;
 if(meterTimer>.1){meterTimer=0;nearestEl.textContent=nearest===999?'—':nearest.toFixed(1)+'m';
   const isDanger=nearest<fearRadius&&!paused; const st=isDanger?'⚠ FLEEING!':'😌 CALM';
   if(st!==lastStatus){statusEl.textContent=st;statusEl.classList.toggle('danger',isDanger);lastStatus=st;}}
 // pellets
 for(let i=pellets.length-1;i>=0;i--){const p=pellets[i];p.userData.life-=dt;p.position.y=Math.max(-2.42,p.position.y-dt*.28);p.position.x+=Math.sin(t*3+p.userData.ph)*dt*.12;if(p.userData.life<=0){scene.remove(p);pellets.splice(i,1);}}
 // ripples
 for(let i=ripples.length-1;i>=0;i--){const r=ripples[i];r.userData.life-=dt;const k=1-r.userData.life/.75;r.scale.setScalar(.25+k*2.4);r.material.opacity=.85*(1-k);r.lookAt(camera.position);if(r.userData.life<=0){scene.remove(r);ripples.splice(i,1);}}
 // bubbles
 bubTimer+=dt; if(bubTimer>.14){bubTimer=0;const vent=Math.random()<.5?new THREE.Vector3(-3.6,-2,. -1.6):new THREE.Vector3(3.4,-2,-1.4);spawnBubble(vent,new THREE.Vector3(rand(-.1,.1),rand(.7,1.1),rand(-.1,.1)),rand(2,3.5),rand(.5,1.1));}
 for(const b of bubbles){if(!b.userData.active)continue;b.userData.life-=dt;b.userData.vel.y+=dt*.25;b.position.addScaledVector(b.userData.vel,dt);b.position.x+=Math.sin(t*5+b.position.y*4)*dt*.15;b.scale.setScalar(b.userData.base*(0.6+clamp(b.userData.life,0,1)*.5));if(b.userData.life<=0||b.position.y>2.6){b.userData.active=false;b.visible=false;}}
 // environment motion
 seaweeds.forEach(s=>{s.rotation.z=Math.sin(t*1.15+s.userData.phase)*.14;s.rotation.x=Math.cos(t*.9+s.userData.phase)*.08;});
 jellies.forEach(j=>{j.position.y=j.userData.by+Math.sin(t*.5+j.userData.ph)*.35;j.position.x=j.userData.bx+Math.sin(t*.22+j.userData.ph)*.45;const s=1+Math.sin(t*2+j.userData.ph)*.06;j.scale.set(s,2-s,s);});
 rays.forEach((r,i)=>{r.material.opacity=.045+Math.sin(t*.7+i*1.4)*.025;});
 {const p=waterGeo.attributes.position;for(let i=0;i<p.count;i++){const x=waterBase[i*3],z=waterBase[i*3+2];p.setY(i,Math.sin(x*1.8+t*1.6)*Math.cos(z*2.1+t*1.2)*.06);}p.needsUpdate=true;waterGeo.computeVertexNormals();}
 {const p=snowGeo.attributes.position;for(let i=0;i<snowCount;i++){let y=p.getY(i)-dt*.07;if(y<-2.5)y=2.7;p.setY(i,y);p.setX(i,p.getX(i)+Math.sin(t+i)*dt*.02);}p.needsUpdate=true;}
 renderer.render(scene,camera);
});

window.addEventListener('resize',()=>{camera.aspect=innerWidth/innerHeight;camera.updateProjectionMatrix();renderer.setSize(innerWidth,innerHeight);});
</script>
</body>
</html>
Reasoning trace (11,857 tokens)
Implementing a Three-js 3D aquarium with auto demo cursor for fish flee behavior and single-file CDN output.Adding boid-based fish AI with raycast-driven flee response and idle demo attractor.Extending fish design with variant meshes and adding click-spawned food attraction alongside flee logic.Detailing Three.js scene setup with lighting, geometry, and fish orientation for the aquarium.Extending the scene with bubble, food, ripple, and UI systems plus demo-mode fish behavior and environment details.Adding pointer-driven fish fleeing, food targeting, bubble pools, UI controls, and telemetry overlays.Extending rendering with opacity, scaling, dashed lines, and geometry adjustments for fish and stripes.Adding steering, bounds, panic, food seeking, click handling, and UI controls for fish behavior.Adding UI controls, demo orb visuals, tank rendering, and CSS layout for the fish simulation.Extending the scene with corals, seaweed, jellyfish, bubbles, marine snow, water surface, light rays, and UI stats plus animation updates.