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
55.9 s
Cost
$0.023
Output tokens
4,469
Spent thinking
157 tokens
Speed
87 tok/s
Console errors
0
First token after
4.5 s
First visible text after
4.5 s
Prompt tokens
423
Code size
12.3 KB
Finish reason
stop
Served by
OpenAI
Model id
openai/gpt-6.1-terra
Reasoning sent
{"effort":"low"}
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 · 265 lines

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>The Quiet Aquarium</title>
<style>
  * { box-sizing: border-box; }
  html, body { margin: 0; width: 100%; height: 100%; overflow: hidden; }
  body {
    font-family: Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
    color: #e9fbf9;
    background: #071c25;
  }
  #scene { position: absolute; inset: 0; }
  canvas { display: block; width: 100%; height: 100%; }
  .shade {
    pointer-events: none; position: absolute; inset: 0;
    background: linear-gradient(180deg, rgba(3,20,29,.5), transparent 24%, transparent 70%, rgba(3,20,25,.5)),
      radial-gradient(ellipse at center, transparent 45%, rgba(2,20,28,.26) 100%);
  }
  header {
    position: absolute; top: 0; left: 0; right: 0; display: flex;
    justify-content: space-between; align-items: flex-start; padding: 37px 5%;
    pointer-events: none;
  }
  .eyebrow { font-size: 10px; font-weight: 700; letter-spacing: .25em; color: #9ce4dc; text-transform: uppercase; }
  h1 { font-size: clamp(25px, 3vw, 39px); font-weight: 400; letter-spacing: -.045em; margin: 8px 0 0; line-height: 1; }
  h1 span { font-family: Georgia, serif; font-style: italic; font-weight: 400; }
  .status { display: flex; align-items: center; gap: 9px; color: #c5e4df; font-size: 10px; letter-spacing: .16em; text-transform: uppercase; padding-top: 6px; }
  .dot { width: 7px; height: 7px; border-radius: 50%; background: #a3efbe; box-shadow: 0 0 12px #93efb9; }
  .bottom {
    position: absolute; bottom: 0; left: 0; right: 0; padding: 30px 5% 34px;
    display: flex; align-items: end; justify-content: space-between; gap: 20px; pointer-events: none;
  }
  .hint { display: flex; gap: 13px; align-items: center; }
  .mouse {
    width: 27px; height: 38px; border: 1px solid rgba(213,250,242,.6); border-radius: 15px;
    position: relative; flex: none;
  }
  .mouse:after { content: ""; position: absolute; width: 2px; height: 7px; background: #c9f2e9; left: 11px; top: 7px; border-radius: 3px; }
  .hint strong { display: block; font-size: 12px; font-weight: 600; letter-spacing: .02em; }
  .hint span { display: block; margin-top: 4px; font-size: 11px; color: #a8cfc9; }
  .caption { text-align: right; color: #afd3cd; font-size: 10px; letter-spacing: .15em; text-transform: uppercase; line-height: 1.8; }
  .caption b { color: #e4f6ed; font-weight: 500; }
  .cross { position: absolute; left: 50%; top: 50%; color: rgba(214,255,245,.25); font-size: 18px; font-weight: 200; pointer-events: none; }
  @media(max-width: 600px) {
    header { padding: 25px 6%; }
    .status { font-size: 9px; }
    .bottom { padding: 22px 6% 25px; }
    .caption { font-size: 9px; }
    .hint span { max-width: 170px; 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="shade"></div>
<header>
  <div><div class="eyebrow">A little window into the blue</div><h1>The quiet <span>aquarium.</span></h1></div>
  <div class="status"><i class="dot"></i> Live habitat</div>
</header>
<div class="cross">+</div>
<div class="bottom">
  <div class="hint"><div class="mouse"></div><div><strong>Make a little ripple</strong><span>Move your mouse near the fish to see them scatter.</span></div></div>
  <div class="caption">A moment of calm<br><b>Take your time &nbsp;·&nbsp; 01 / 01</b></div>
</div>
<script type="module">
import * as THREE from 'three';

const container = document.getElementById('scene');
const scene = new THREE.Scene();
scene.background = new THREE.Color(0x0b4149);
scene.fog = new THREE.FogExp2(0x0c5057, 0.035);
const camera = new THREE.PerspectiveCamera(43, innerWidth / innerHeight, 0.1, 100);
camera.position.set(0, 2.2, 20);
camera.lookAt(0, 0.1, 0);
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.12;
container.appendChild(renderer.domElement);

scene.add(new THREE.HemisphereLight(0xc9fff3, 0x16444b, 2.2));
const sun = new THREE.DirectionalLight(0xfff1cf, 2.4);
sun.position.set(-5, 10, 8); scene.add(sun);
const aqua = new THREE.PointLight(0x58f4dd, 38, 30);
aqua.position.set(2, 4, 5); scene.add(aqua);

const mat = (color, extra={}) => new THREE.MeshStandardMaterial({color, roughness: .7, ...extra});
const sandMat = mat(0xc2b58c);
const sand = new THREE.Mesh(new THREE.BoxGeometry(25, .45, 10), sandMat);
sand.position.set(0,-4.65,0); scene.add(sand);

// Softly rolling sand mounds.
for (let i=0; i<19; i++) {
  const mound = new THREE.Mesh(new THREE.SphereGeometry(1, 16, 10), mat(i%2 ? 0xc9bd94 : 0xb8ad88));
  mound.scale.set(1.1+Math.random()*1.8, .09+Math.random()*.15, .8+Math.random());
  mound.position.set(-11+i*1.25, -4.43, -1+Math.random()*3); scene.add(mound);
}

// Pebbles scattered across the floor.
for(let i=0;i<95;i++){
  const rock = new THREE.Mesh(new THREE.DodecahedronGeometry(.06+Math.random()*.17, 0),
    mat([0x86988c,0xa89e7e,0xd8cba3,0x6f8d83][i%4]));
  rock.position.set((Math.random()-.5)*23, -4.36+Math.random()*.05, (Math.random()-.5)*7);
  rock.scale.set(1.3,.55,1); rock.rotation.y=Math.random()*6; scene.add(rock);
}

// Rock clusters.
function rock(x,z,s,c){
  const r=new THREE.Mesh(new THREE.DodecahedronGeometry(1,1),mat(c));
  r.position.set(x,-4.25+s*.36,z); r.scale.set(s*1.2,s*.65,s*.8);
  r.rotation.set(.1,Math.random()*3,.12); scene.add(r);
}
rock(-7.8,-1,1.1,0x637f75); rock(-6.6,-1.3,.65,0x81968a);
rock(7.2,-1.8,1.05,0x6c877c); rock(8.2,-1,.7,0x8a9b87);

// Long, curved, tapered seagrass blades.
const plantMaterials=[mat(0x1d7869,{side:THREE.DoubleSide}),mat(0x3b9b7b,{side:THREE.DoubleSide}),mat(0x72ad83,{side:THREE.DoubleSide}),mat(0x246f63,{side:THREE.DoubleSide})];
const plants=[];
function blade(x,z,h,width,lean,material) {
  const vertices=[], indices=[];
  const segments=10;
  for(let i=0;i<=segments;i++){
    const t=i/segments;
    const cx=lean*t*t;
    const w=width*(1-t)*(.75+.25*Math.sin(t*Math.PI));
    vertices.push(cx-w/2,t*h,0,cx+w/2,t*h,0);
    if(i<segments){let a=i*2; indices.push(a,a+1,a+2,a+1,a+3,a+2);}
  }
  const geo=new THREE.BufferGeometry();
  geo.setAttribute('position',new THREE.Float32BufferAttribute(vertices,3));
  geo.setIndex(indices); geo.computeVertexNormals();
  const mesh=new THREE.Mesh(geo,material);
  mesh.position.set(x,-4.42,z); mesh.rotation.y=Math.random()*Math.PI;
  scene.add(mesh); plants.push({mesh,phase:Math.random()*6,base:mesh.rotation.z});
}
for(const [x,z,count] of [[-8,-2,22],[-5.7,-2.7,14],[7.8,-2,23],[5.9,-3,15],[-10,1,13],[10,0,14]]){
  for(let i=0;i<count;i++) blade(x+(Math.random()-.5)*1.8,z+(Math.random()-.5)*1.1,1+Math.random()*2.8,.13+Math.random()*.17,(Math.random()-.5)*1.4,plantMaterials[i%4]);
}

// Tiny particles suspended in the water.
const dustGeo = new THREE.BufferGeometry(), dustPos=[];
for(let i=0;i<260;i++) dustPos.push((Math.random()-.5)*24, (Math.random()-.5)*11, (Math.random()-.5)*8);
dustGeo.setAttribute('position', new THREE.Float32BufferAttribute(dustPos,3));
const dust = new THREE.Points(dustGeo,new THREE.PointsMaterial({color:0xc6f8e8,size:.025,transparent:true,opacity:.55}));
scene.add(dust);

// Rising bubbles.
const bubbles=[];
const bubbleMat = new THREE.MeshPhysicalMaterial({color:0xb5f9ed, roughness:.08, metalness:.1, transparent:true, opacity:.35});
const bubbleGeo = new THREE.SphereGeometry(1,12,10);
for(let i=0;i<32;i++){
  const b=new THREE.Mesh(bubbleGeo,bubbleMat);
  let size=.025+Math.random()*.07; b.scale.setScalar(size);
  b.position.set(6.3+(Math.random()-.5)*1.4, -4+Math.random()*10, -1.3+Math.random());
  scene.add(b); bubbles.push({mesh:b,speed:.35+Math.random()*.45,phase:Math.random()*6,baseX:b.position.x});
}

// A fish is built facing right, with a body, tail, fins and bright eyes.
const fishList=[];
const bodyGeo=new THREE.SphereGeometry(1,24,16);
const eyeGeo=new THREE.SphereGeometry(.09,12,8);
const pupilGeo=new THREE.SphereGeometry(.047,12,8);
function triangle(points, material){
  const g=new THREE.BufferGeometry();
  g.setAttribute('position',new THREE.Float32BufferAttribute(points,3));
  g.computeVertexNormals();
  return new THREE.Mesh(g,material);
}
function makeFish(x,y,z,scale,color,accent,dir){
  const root=new THREE.Group();
  const bodyMat=mat(color,{roughness:.46,metalness:.08});
  const finMat=mat(accent,{side:THREE.DoubleSide,roughness:.5});
  const body=new THREE.Mesh(bodyGeo,bodyMat);
  body.scale.set(.78,.37,.29); root.add(body);
  const tailPivot=new THREE.Group(); tailPivot.position.x=-.65;
  const tail=triangle([0,0,0,-.65,.43,0,-.54,0,0, 0,0,0,-.54,0,0,-.65,-.43,0],finMat);
  tailPivot.add(tail); root.add(tailPivot);
  const dorsal=triangle([-.36,.24,0,-.12,.65,0,.17,.31,0],finMat); root.add(dorsal);
  const lower=triangle([-.3,-.25,0,-.12,-.5,0,.12,-.29,0],finMat); root.add(lower);
  for(const side of [-1,1]){
    const white=new THREE.Mesh(eyeGeo,mat(0xf4f4dc)); white.position.set(.48,.12,side*.23); root.add(white);
    const pupil=new THREE.Mesh(pupilGeo,mat(0x132c30)); pupil.position.set(.51,.13,side*.303); root.add(pupil);
    const fin=triangle([-.08,.02,side*.27,-.36,-.24,side*.4,.03,-.13,side*.3],finMat); root.add(fin);
  }
  root.position.set(x,y,z); root.scale.setScalar(scale); scene.add(root);
  fishList.push({root,tailPivot,vel:new THREE.Vector3(dir*(.65+Math.random()*.4), (Math.random()-.5)*.18,0), phase:Math.random()*10, speed:.55+Math.random()*.45, turn:dir===1?0:Math.PI});
}
makeFish(-5.8,1.2,1.0,.78,0xf49c62,0xe87454,1);
makeFish(-2.6,-.2,2.3,.92,0xf7c476,0xee9561,-1);
makeFish(1.4,1.8,.3,.72,0xffb077,0xed795c,-1);
makeFish(4.6,.15,1.1,.8,0xf2c66f,0xef945c,1);
makeFish(7.1,2.3,-1,.58,0xd5dfb1,0x87c8b3,-1);
makeFish(-7.3,-1.6,-.8,.6,0xa6ddd0,0x69b8b0,1);
makeFish(0,-1.9,-.8,.62,0xf2a778,0xde7965,1);
makeFish(3.1,-1.7,2,.55,0xc5e4c8,0x7ec5b2,-1);
makeFish(-3.9,2.5,-1.5,.48,0xf8d28c,0xe9a66f,1);

// Pointer ray intersects a plane through the swimming area.
const mouse=new THREE.Vector2(100,100), mouseWorld=new THREE.Vector3();
const raycaster=new THREE.Raycaster(), plane=new THREE.Plane(new THREE.Vector3(0,0,1),0);
let pointerActive=false;
window.addEventListener('pointermove', e=>{
  mouse.set(e.clientX/innerWidth*2-1,-(e.clientY/innerHeight)*2+1);
  pointerActive=true;
});
window.addEventListener('pointerleave',()=>pointerActive=false);
window.addEventListener('resize',()=>{
  camera.aspect=innerWidth/innerHeight; camera.updateProjectionMatrix();
  renderer.setSize(innerWidth,innerHeight); renderer.setPixelRatio(Math.min(devicePixelRatio,2));
});
const clock=new THREE.Clock();
function animate(){
  requestAnimationFrame(animate);
  const dt=Math.min(clock.getDelta(),.04), t=clock.elapsedTime;
  if(pointerActive){
    raycaster.setFromCamera(mouse,camera);
    raycaster.ray.intersectPlane(plane,mouseWorld);
  }
  for(const f of fishList){
    const p=f.root.position;
    f.vel.y += Math.sin(t*.8+f.phase)*dt*.13;
    if(p.x>9) f.vel.x-=dt*1.5;
    if(p.x< -9) f.vel.x+=dt*1.5;
    if(p.y>3.4) f.vel.y-=dt*1.3;
    if(p.y< -3.1) f.vel.y+=dt*1.3;
    if(pointerActive){
      const dx=p.x-mouseWorld.x, dy=p.y-mouseWorld.y;
      const d=Math.sqrt(dx*dx+dy*dy);
      if(d<2.5 && d>.001){
        const force=(2.5-d)*2.2;
        f.vel.x+=dx/d*force*dt;
        f.vel.y+=dy/d*force*dt;
      }
    }
    const speed=Math.hypot(f.vel.x,f.vel.y);
    const max=2.5;
    if(speed>max){f.vel.x*=max/speed;f.vel.y*=max/speed;}
    if(speed<f.speed){ f.vel.x+=(f.vel.x>=0?1:-1)*dt*.35; }
    f.vel.y*=Math.pow(.78,dt);
    p.x+=f.vel.x*dt; p.y+=f.vel.y*dt;
    const target=f.vel.x>=0?0:Math.PI;
    let diff=((target-f.turn+Math.PI*3)%(Math.PI*2))-Math.PI;
    f.turn+=diff*Math.min(1,dt*3);
    f.root.rotation.y=f.turn;
    f.root.rotation.z=THREE.MathUtils.lerp(f.root.rotation.z,THREE.MathUtils.clamp(f.vel.y*.18*(f.vel.x>=0?1:-1),-.3,.3),dt*2);
    f.tailPivot.rotation.y=Math.sin(t*10+f.phase)*.38;
  }
  for(const b of bubbles){
    b.mesh.position.y+=b.speed*dt;
    b.mesh.position.x=b.baseX+Math.sin(t*1.2+b.phase)*.12;
    if(b.mesh.position.y>5.8) b.mesh.position.y=-4.2;
  }
  for(const p of plants) p.mesh.rotation.z=p.base+Math.sin(t*.75+p.phase)*.055;
  renderer.render(scene,camera);
}
animate();
</script>
</body>
</html>