Models 44

GPT-6.1 Terra

by OpenAIReasoningClean
Open in new window

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

How it went

Total time
1 min 36 s
Cost
$0.038
Output tokens
7,536
Spent thinking
1,387 tokens
Speed
84 tok/s
Console errors
0
First token after
6.7 s
First visible text after
30.0 s
Prompt tokens
423
Code size
17.9 KB
Finish reason
stop
Served by
OpenAI
Model id
openai/gpt-6.1-terra
Reasoning sent
{"effort":"medium"}
Max output
128,000 tokens
Generated
Nov 12, 2026

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 · 336 lines

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>The Glasshouse — Living Aquarium</title>
<style>
  * { box-sizing: border-box; }
  html, body { margin: 0; width: 100%; height: 100%; overflow: hidden; }
  body {
    color: #e9f7ee;
    font-family: Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
    background: radial-gradient(ellipse at 50% 42%, #164a4d 0%, #0b292e 46%, #061a20 100%);
  }
  #scene { position: fixed; inset: 0; }
  canvas { display: block; width: 100%; height: 100%; }
  .vignette {
    position: fixed; inset: 0; pointer-events: none;
    background: radial-gradient(ellipse at center, transparent 45%, rgba(1, 13, 18, .48) 100%);
  }
  .interface { position: fixed; inset: 0; pointer-events: none; }
  header {
    position: absolute; top: 32px; left: 5%; right: 5%;
    display: flex; align-items: center; justify-content: space-between;
  }
  .brand { display: flex; align-items: center; gap: 11px; }
  .brand-mark {
    width: 34px; height: 34px; border: 1px solid rgba(182, 229, 208, .55);
    border-radius: 50%; display: grid; place-items: center;
  }
  .brand-mark svg { width: 20px; height: 20px; }
  .brand-name { font-size: 11px; letter-spacing: .2em; font-weight: 750; }
  .brand-sub { margin-top: 3px; font-size: 8px; letter-spacing: .22em; color: #85aaa6; }
  .live { display: flex; align-items: center; gap: 8px; color: #a7c7bc; font-size: 10px; font-weight: 650; letter-spacing: .16em; }
  .live-dot { width: 6px; height: 6px; border-radius: 50%; background: #96e5b9; box-shadow: 0 0 12px #86e8b0; }
  .intro { position: absolute; top: 104px; left: 5%; }
  .eyebrow { color: #a5c8ba; text-transform: uppercase; letter-spacing: .22em; font-size: 9px; font-weight: 700; }
  h1 { font-family: Georgia, "Times New Roman", serif; font-size: clamp(25px, 3vw, 40px); line-height: 1.1; font-weight: 400; margin: 10px 0 0; letter-spacing: -.03em; text-shadow: 0 2px 20px #082a2c; }
  h1 em { color: #abd7c0; font-weight: 400; }
  .bottom {
    position: absolute; left: 5%; right: 5%; bottom: 35px;
    display: flex; justify-content: space-between; align-items: end; gap: 20px;
  }
  .hint { display: flex; align-items: center; gap: 13px; }
  .mouse-icon {
    width: 35px; height: 35px; border: 1px solid rgba(183, 224, 208, .32);
    border-radius: 50%; display: grid; place-items: center; flex: none;
  }
  .hint-title { font-size: 12px; font-weight: 600; color: #e3f4e9; }
  .hint-sub { font-size: 10px; margin-top: 4px; color: #91b4aa; }
  .stats { display: flex; gap: 30px; }
  .stat-label { color: #799e97; font-size: 8px; font-weight: 700; letter-spacing: .18em; }
  .stat-value { color: #cce3d7; font-size: 12px; margin-top: 6px; }
  .corner-note { position: absolute; right: 5%; top: 107px; text-align: right; color: #83a9a0; font-size: 9px; letter-spacing: .14em; line-height: 1.8; }
  @media (max-width: 600px) {
    header { top: 22px; left: 6%; right: 6%; }
    .live { font-size: 8px; letter-spacing: .1em; }
    .intro { top: 95px; left: 6%; }
    .corner-note { display: none; }
    .bottom { left: 6%; right: 6%; bottom: 25px; }
    .stats { gap: 15px; }
    .stat:last-child { display: none; }
    .hint-sub { max-width: 155px; line-height: 1.4; }
  }
</style>
<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>
</head>
<body>
<div id="scene"></div>
<div class="vignette"></div>
<div class="interface">
  <header>
    <div class="brand">
      <div class="brand-mark">
        <svg viewBox="0 0 24 24" fill="none" stroke="#bee7ce" stroke-width="1.2"><path d="M3 12c3.5-5 9-5.6 14-1l4-2v6l-4-2c-5 4.6-10.5 4-14-1Z"/><circle cx="8" cy="11" r=".7" fill="#bee7ce" stroke="none"/></svg>
      </div>
      <div><div class="brand-name">THE GLASSHOUSE</div><div class="brand-sub">A SMALLER WORLD</div></div>
    </div>
    <div class="live"><span class="live-dot"></span> LIVE ECOSYSTEM</div>
  </header>
  <div class="intro"><div class="eyebrow">A moment of calm &nbsp; / &nbsp; No. 01</div><h1>A little life, <em>in motion.</em></h1></div>
  <div class="corner-note">TAKE A BREATH<br>STAY A WHILE</div>
  <div class="bottom">
    <div class="hint">
      <div class="mouse-icon"><svg width="15" height="19" viewBox="0 0 15 19" fill="none"><rect x="2.5" y="1" width="10" height="16" rx="5" stroke="#B9DCCB"/><path d="M7.5 4v3" stroke="#B9DCCB" stroke-linecap="round"/></svg></div>
      <div><div class="hint-title">Make a little ripple</div><div class="hint-sub">Move your cursor near the fish to watch them scatter.</div></div>
    </div>
    <div class="stats">
      <div class="stat"><div class="stat-label">WATER TEMP</div><div class="stat-value">24.6 °C</div></div>
      <div class="stat"><div class="stat-label">INHABITANTS</div><div class="stat-value">12 little swimmers</div></div>
      <div class="stat"><div class="stat-label">ENVIRONMENT</div><div class="stat-value">Freshwater</div></div>
    </div>
  </div>
</div>
<script type="module">
import * as THREE from 'three';

const container = document.getElementById('scene');
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(36, 1, .1, 100);
const renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true });
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.outputColorSpace = THREE.SRGBColorSpace;
renderer.toneMapping = THREE.ACESFilmicToneMapping;
renderer.toneMappingExposure = 1.15;
container.appendChild(renderer.domElement);

scene.add(new THREE.HemisphereLight(0xc8fff1, 0x214c3b, 2.0));
const key = new THREE.DirectionalLight(0xfff1cf, 2.8);
key.position.set(-4, 10, 7); scene.add(key);
const fill = new THREE.DirectionalLight(0x58d1c0, 1.1);
fill.position.set(5, 4, -4); scene.add(fill);

const W = 12, H = 6.3, D = 4.4;
const tank = new THREE.Group(); scene.add(tank);

// A softly graded back wall gives the water depth without hiding the swimmers.
const bgCanvas = document.createElement('canvas');
bgCanvas.width = 64; bgCanvas.height = 512;
const bg = bgCanvas.getContext('2d');
const grad = bg.createLinearGradient(0, 0, 0, 512);
grad.addColorStop(0, '#388a83'); grad.addColorStop(.45, '#17645f'); grad.addColorStop(1, '#0a393b');
bg.fillStyle = grad; bg.fillRect(0, 0, 64, 512);
const bgTex = new THREE.CanvasTexture(bgCanvas); bgTex.colorSpace = THREE.SRGBColorSpace;
const back = new THREE.Mesh(new THREE.PlaneGeometry(W, H), new THREE.MeshBasicMaterial({ map: bgTex }));
back.position.set(0, H/2, -D/2); tank.add(back);

const sideMat = new THREE.MeshBasicMaterial({ color: 0x59bbb0, transparent: true, opacity: .12, side: THREE.DoubleSide, depthWrite: false });
for (const x of [-W/2, W/2]) {
  const side = new THREE.Mesh(new THREE.PlaneGeometry(D, H), sideMat);
  side.rotation.y = Math.PI/2; side.position.set(x, H/2, 0); tank.add(side);
}
const glass = new THREE.Mesh(new THREE.PlaneGeometry(W, H), new THREE.MeshBasicMaterial({color: 0xb5fff0, transparent: true, opacity: .035, side: THREE.DoubleSide, depthWrite: false}));
glass.position.set(0, H/2, D/2); glass.renderOrder = 5; tank.add(glass);
const water = new THREE.Mesh(new THREE.PlaneGeometry(W, D), new THREE.MeshBasicMaterial({color: 0x91e3d4, transparent: true, opacity: .13, side: THREE.DoubleSide, depthWrite: false}));
water.rotation.x = -Math.PI/2; water.position.y = H; tank.add(water);

// Glass edges.
const edgeMat = new THREE.LineBasicMaterial({color: 0xa2e8db, transparent: true, opacity: .48});
const box = new THREE.LineSegments(new THREE.EdgesGeometry(new THREE.BoxGeometry(W, H, D)), edgeMat);
box.position.y = H/2; tank.add(box);
const rimMat = new THREE.LineBasicMaterial({color: 0xd5fff0, transparent: true, opacity: .4});
const rimPoints = [new THREE.Vector3(-6,H,2.2),new THREE.Vector3(6,H,2.2)];
tank.add(new THREE.Line(new THREE.BufferGeometry().setFromPoints(rimPoints), rimMat));

// Sand and a dark plinth.
const sand = new THREE.Mesh(new THREE.BoxGeometry(W, .24, D), new THREE.MeshStandardMaterial({color:0xb5a882, roughness:1}));
sand.position.y = .08; tank.add(sand);
const base = new THREE.Mesh(new THREE.BoxGeometry(W+.18, .18, D+.18), new THREE.MeshStandardMaterial({color:0x1d3c39, roughness:.65, metalness:.2}));
base.position.y = -.12; tank.add(base);
const floor = new THREE.Mesh(new THREE.PlaneGeometry(35, 25), new THREE.MeshBasicMaterial({color:0x081f22, transparent:true, opacity:.45}));
floor.rotation.x = -Math.PI/2; floor.position.y = -.24; scene.add(floor);

const pebbleGeo = new THREE.SphereGeometry(1, 8, 6);
const pebbleMats = [0xc6b99a,0x8f9e89,0xd7c7a4,0x6b8174,0xada38d].map(c => new THREE.MeshStandardMaterial({color:c, roughness:1}));
for (let i=0;i<220;i++) {
  const p = new THREE.Mesh(pebbleGeo, pebbleMats[i%pebbleMats.length]);
  p.position.set((Math.random()-.5)*11.7, .23, (Math.random()-.5)*4.1);
  const s=.025+Math.random()*.065; p.scale.set(s*1.5,s*.5,s);
  tank.add(p);
}

// Smooth river stones.
const rockMat = [0x687e6e, 0x899487, 0x526e65].map(c=>new THREE.MeshStandardMaterial({color:c, roughness:.92}));
const rocks = [[-4.6,.36,-.8,.85],[-3.9,.33,-1.05,.62],[-4.9,.3,.2,.55],[3.9,.38,-1.1,.9],[4.6,.3,-.7,.65],[2.9,.28,-1.5,.55],[-1.9,.26,-1.7,.5]];
rocks.forEach(([x,y,z,s],i)=>{
  const r = new THREE.Mesh(new THREE.DodecahedronGeometry(1,1), rockMat[i%3]);
  r.position.set(x,y,z); r.scale.set(s*1.25,s*.52,s*.8); r.rotation.set(Math.random(),Math.random(),Math.random()*.2); tank.add(r);
});

// Individual curved leaves, arranged in little rooted clusters.
const plantMats = [0x2c8064,0x43a17b,0x1e6c58,0x79ad7c,0x357e69].map(c=>new THREE.MeshStandardMaterial({color:c, side:THREE.DoubleSide, roughness:.8}));
const leaves = [];
function makeLeaf(x,z,height,angle,lean,mat) {
  const seg=8, verts=[], indices=[];
  for(let j=0;j<=seg;j++){
    const t=j/seg, width=Math.sin(Math.PI*t)*(.09+height*.035);
    const bend=lean*t*t;
    for(const sign of [-1,1]){
      verts.push(Math.cos(angle)*bend + Math.cos(angle+Math.PI/2)*width*sign, height*t,
        Math.sin(angle)*bend + Math.sin(angle+Math.PI/2)*width*sign);
    }
  }
  for(let j=0;j<seg;j++){let k=j*2;indices.push(k,k+1,k+2,k+1,k+3,k+2);}
  const g=new THREE.BufferGeometry(); g.setAttribute('position',new THREE.Float32BufferAttribute(verts,3)); g.setIndex(indices); g.computeVertexNormals();
  const leaf=new THREE.Mesh(g,mat); leaf.position.set(x,.2,z); tank.add(leaf);
  leaves.push({mesh:leaf, phase:Math.random()*6, speed:.5+Math.random()*.5});
}
const clusters=[[-5.2,-1.55,1.9],[-4.15,-1.8,2.1],[-2.9,-1.9,1.25],[-.7,-2,1.3],[1.7,-1.9,1.4],[3.6,-1.8,2],[5,-1.5,2.25],[-5.4,1.1,1.05],[5.3,.9,1.2]];
clusters.forEach(([x,z,h])=>{
  for(let i=0;i<7;i++) makeLeaf(x+(Math.random()-.5)*.45,z+(Math.random()-.5)*.35,h*(.55+Math.random()*.65),Math.random()*Math.PI*2,.2+Math.random()*.65,plantMats[Math.floor(Math.random()*plantMats.length)]);
});

// Gentle translucent shafts of light.
for (let i=0;i<4;i++){
  const geom=new THREE.BufferGeometry();
  const x=-4.2+i*2.7;
  geom.setAttribute('position',new THREE.Float32BufferAttribute([x,6.27,-2.16,x+1.0,6.27,-2.16,x-1.1,.3,-2.15,x+1.0,6.27,-2.16,x-.3,.3,-2.15,x-1.1,.3,-2.15],3));
  const beam=new THREE.Mesh(geom,new THREE.MeshBasicMaterial({color:0xb6f7dd,transparent:true,opacity:.035,side:THREE.DoubleSide,depthWrite:false})); tank.add(beam);
}

const sphereGeo = new THREE.SphereGeometry(1, 20, 12);
const eyeGeo = new THREE.SphereGeometry(1, 12, 8);
const darkEye = new THREE.MeshStandardMaterial({color:0x102e2b, roughness:.3});
const eyeShine = new THREE.MeshBasicMaterial({color:0xf2fff3});
function finGeometry(points) {
  const g=new THREE.BufferGeometry();
  g.setAttribute('position',new THREE.Float32BufferAttribute(points,3)); g.computeVertexNormals(); return g;
}
function makeFish(color, accent, scale) {
  const root = new THREE.Group();
  const bodyMat = new THREE.MeshStandardMaterial({color, roughness:.45, metalness:.08});
  const finMat = new THREE.MeshStandardMaterial({color:accent, roughness:.55, side:THREE.DoubleSide, transparent:true, opacity:.85});
  const body = new THREE.Mesh(sphereGeo,bodyMat); body.scale.set(.68,.33,.22); root.add(body);
  const head = new THREE.Mesh(sphereGeo,bodyMat); head.position.x=.43; head.scale.set(.3,.25,.19); root.add(head);
  const tail = new THREE.Group(); tail.position.x=-.54; root.add(tail);
  const tailMesh=new THREE.Mesh(finGeometry([0,0,0,-.58,.38,0,-.48,0,0, 0,0,0,-.48,0,0,-.58,-.38,0]),finMat); tail.add(tailMesh);
  const dorsal=new THREE.Mesh(finGeometry([-.36,.2,0,-.12,.52,0,.24,.27,0]),finMat); root.add(dorsal);
  const lower=new THREE.Mesh(finGeometry([-.32,-.22,0,-.12,-.41,0,.18,-.23,0]),finMat); root.add(lower);
  const sideFin=new THREE.Mesh(finGeometry([.03,.03,.205,-.23,-.18,.27,-.18,.08,.25]),finMat); root.add(sideFin);
  const sideFin2=sideFin.clone(); sideFin2.scale.z=-1; root.add(sideFin2);
  for(const side of [-1,1]) {
    const eye=new THREE.Mesh(eyeGeo,darkEye); eye.position.set(.46,.10,side*.174); eye.scale.set(.048,.048,.025); root.add(eye);
    const shine=new THREE.Mesh(eyeGeo,eyeShine); shine.position.set(.475,.116,side*.195); shine.scale.set(.014,.014,.008); root.add(shine);
    // A delicate gill line.
    const pts=[];
    for(let i=0;i<=8;i++){let a=-.75+i*1.5/8;pts.push(new THREE.Vector3(.22+.045*Math.cos(a),.18*Math.sin(a),side*(.208+.008*Math.cos(a))));}
    root.add(new THREE.Line(new THREE.BufferGeometry().setFromPoints(pts),new THREE.LineBasicMaterial({color:accent,transparent:true,opacity:.6})));
  }
  root.scale.setScalar(scale); tank.add(root);
  return {root,tail,sideFin,sideFin2};
}

const palettes=[[0xf2a76d,0xd96851],[0xf4d49c,0xe4a85e],[0x8dc7b9,0x50a399],[0xe98d72,0xf2b78d],[0xe2dfbd,0x92bdb0],[0xf4bd7a,0xe5835a]];
const fish=[];
for(let i=0;i<12;i++){
  const [color,accent]=palettes[i%palettes.length];
  const f=makeFish(color,accent,.68+Math.random()*.28);
  f.root.position.set((Math.random()-.5)*9.8,1.15+Math.random()*4.2,(Math.random()-.5)*2.7);
  const a=Math.random()*Math.PI*2;
  f.velocity=new THREE.Vector3(Math.cos(a)*(.55+Math.random()*.3),(Math.random()-.5)*.18,Math.sin(a)*.3);
  f.phase=Math.random()*10; f.turn=0;
  f.root.rotation.y=-Math.atan2(f.velocity.z,f.velocity.x);
  fish.push(f);
}

// Bubbles are distributed along two streams.
const bubbles=[];
const bubbleMat=new THREE.MeshBasicMaterial({color:0xd4fff4,transparent:true,opacity:.35,wireframe:true,depthWrite:false});
const bubbleGeo=new THREE.SphereGeometry(1,10,8);
for(let i=0;i<42;i++){
  const b=new THREE.Mesh(bubbleGeo,bubbleMat);
  const s=.025+Math.random()*.045; b.scale.setScalar(s);
  b.userData={x:i%2 ? -4.65:4.6, z:i%2 ? -1.45:-1.3, y:Math.random()*6, speed:.3+Math.random()*.35, phase:Math.random()*10};
  tank.add(b); bubbles.push(b);
}
const particles=[];
const particleMat=new THREE.MeshBasicMaterial({color:0xc2eee2,transparent:true,opacity:.42});
for(let i=0;i<65;i++){
  const p=new THREE.Mesh(new THREE.SphereGeometry(.012+Math.random()*.012,6,4),particleMat);
  p.position.set((Math.random()-.5)*11.5,Math.random()*6,(Math.random()-.5)*4);
  p.userData.phase=Math.random()*10; tank.add(p); particles.push(p);
}

const raycaster=new THREE.Raycaster();
const mouse=new THREE.Vector2();
const pointerWorld=new THREE.Vector3();
const plane=new THREE.Plane(new THREE.Vector3(0,0,1),0);
let pointerActive=false;
function updatePointer(e){
  mouse.set(e.clientX/window.innerWidth*2-1, -(e.clientY/window.innerHeight)*2+1);
  raycaster.setFromCamera(mouse,camera);
  pointerActive=!!raycaster.ray.intersectPlane(plane,pointerWorld);
}
window.addEventListener('pointermove',updatePointer);
window.addEventListener('pointerleave',()=>pointerActive=false);
window.addEventListener('pointerdown',updatePointer);

function resize(){
  const w=window.innerWidth,h=window.innerHeight,aspect=w/h;
  renderer.setSize(w,h); camera.aspect=aspect;
  camera.position.set(0,5.4,Math.max(16.2, 14.5/aspect));
  camera.lookAt(0,2.9,0); camera.updateProjectionMatrix();
}
window.addEventListener('resize',resize); resize();

const clock=new THREE.Clock();
function animate(){
  requestAnimationFrame(animate);
  const dt=Math.min(clock.getDelta(),.04), t=clock.elapsedTime;
  leaves.forEach(l=>{l.mesh.rotation.z=Math.sin(t*l.speed+l.phase)*.035; l.mesh.rotation.x=Math.cos(t*.6+l.phase)*.025;});
  bubbles.forEach(b=>{
    const d=b.userData; d.y+=dt*d.speed; if(d.y>6.2)d.y=.25;
    b.position.set(d.x+Math.sin(t*1.4+d.phase)*.12,d.y,d.z+Math.cos(t+d.phase)*.08);
  });
  particles.forEach(p=>{p.position.y+=dt*.035;if(p.position.y>6.15)p.position.y=.2; p.position.x+=Math.sin(t+p.userData.phase)*dt*.006;});
  fish.forEach((f,i)=>{
    const p=f.root.position,v=f.velocity;
    const ax=Math.sin(t*.55+f.phase)*.12, az=Math.cos(t*.42+f.phase*1.7)*.12;
    v.x+=ax*dt; v.z+=az*dt; v.y+=Math.sin(t*.7+f.phase)*.035*dt;
    if(p.x>5.1)v.x-=(p.x-5.1)*1.8*dt;
    if(p.x< -5.1)v.x+=(-5.1-p.x)*1.8*dt;
    if(p.y>5.65)v.y-=(p.y-5.65)*1.5*dt;
    if(p.y<.85)v.y+=(.85-p.y)*1.5*dt;
    if(p.z>1.55)v.z-=(p.z-1.55)*1.8*dt;
    if(p.z< -1.55)v.z+=(-1.55-p.z)*1.8*dt;
    if(pointerActive){
      const dx=p.x-pointerWorld.x,dy=p.y-pointerWorld.y;
      const dist=Math.sqrt(dx*dx+dy*dy);
      if(dist<2.25 && dist>.001){
        const force=(1-dist/2.25)*4.5;
        v.x+=dx/dist*force*dt; v.y+=dy/dist*force*dt;
        v.z+=(p.z>=0?.22:-.22)*force*dt;
      }
    }
    v.y=THREE.MathUtils.clamp(v.y,-.7,.7);
    const speed=v.length();
    if(speed>1.8)v.multiplyScalar(1.8/speed);
    if(speed<.48)v.multiplyScalar(.48/Math.max(speed,.001));
    v.multiplyScalar(1-dt*.06);
    p.addScaledVector(v,dt);
    let target=-Math.atan2(v.z,v.x);
    let diff=Math.atan2(Math.sin(target-f.root.rotation.y),Math.cos(target-f.root.rotation.y));
    f.root.rotation.y+=diff*Math.min(1,dt*2.2);
    f.root.rotation.z=THREE.MathUtils.lerp(f.root.rotation.z,Math.atan2(v.y,Math.sqrt(v.x*v.x+v.z*v.z))*(v.x>=0?1:-1),dt*2);
    f.tail.rotation.y=Math.sin(t*(7+v.length()*2)+f.phase)*.35;
    f.sideFin.rotation.x=Math.sin(t*8+f.phase)*.25;
    f.sideFin2.rotation.x=-f.sideFin.rotation.x;
  });
  renderer.render(scene,camera);
}
animate();
</script>
</body>
</html>
Reasoning trace (1,387 tokens)
**Designing a 3D Aquarium Scene**

I need to create a polished scene using a Three.js CDN import map. The idea is to build a full-screen 3D aquarium with some nice overlays. The fish should flee from the mouse, adding a dynamic element. I’ll design the tank with detailed geometry, plants, rocks, and lighting effects. The camera perspective will be set at (0, 5.1, 15.8) to focus on the 12 fish swimming naturally inside, enhancing the whole visual presentation.**Creating Interactive Fish Behavior**

I’m exploring how to make mouse interactions with the fish in the scene. I need to use the raycaster to check for ray-plane intersections at z=0 while comparing the fish's positions in the XY world when near the pointer. In addition, adding a visual pointer effect might enhance it, though it won't require prompts since it's not a game. 

The fish should swim away based on velocity steering and have oscillating fins. I’ll also control their orientation based on velocity and adjust their shapes to make them visually appealing.**Designing the Aquarium Environment**

I’m focusing on creating the aquarium environment with glass walls and a water surface at y=6.3. The glass panels should be transparent, and I’ll add emissive lines at the edges using LineSegments for a sleek look. For the substrate, I want to use numerous small pebbles and larger rocks for an authentic feel, along with plants that have curved leaf geometry. I’ll design clumps of plants that taper from their base to y, adding an oscillating effect for realism.**Setting up camera parameters**

I'm figuring out the camera field of view (fov) to set it at 43 and adjusting the Z position. For mobile, given the aspect ratio of 0.47, it leads to a calculated height of about 250 for the tank. I need to add responsive overlays and check the camera position. While the fish look tiny, their size is still acceptable. I wonder if I can improve the responsive tank scale and ensure the render order works well with transparent surfaces.