Interactive 3D aquariumOne-line
GPT-6 Luna
by OpenAIReasoningClean
Running live in a sandboxed frame. Click inside it before using the keyboard.
How it went
- Total time
- 50.0 s
- Cost
- $0.0020
- Output tokens
- 3,932
- Spent thinking
- 176 tokens
- Speed
- 128.1 tok/s
- Console errors
- 0
- First token after
- 19.3 s
- First visible text after
- 19.3 s
- Prompt tokens
- 423
- Code size
- 11.1 KB
- Finish reason
- stop
- Served by
- OpenAI
- Model id
openai/gpt-6-luna- Reasoning sent
{"effort":"low"}- Max output
- 64,000 tokens
- Generated
- Nov 10, 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 · 226 lines
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Bluewater Aquarium</title>
<style>
* { box-sizing: border-box; }
html, body { margin: 0; width: 100%; height: 100%; overflow: hidden; background: #061827; }
body { font-family: Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; color: #e9f9ff; }
#scene { position: fixed; inset: 0; }
canvas { display: block; width: 100%; height: 100%; }
.hud { position: fixed; inset: 0; pointer-events: none; }
.topbar {
position: absolute; top: 30px; left: 42px; right: 42px;
display: flex; align-items: center; justify-content: space-between;
}
.brand { display: flex; align-items: center; gap: 11px; color: #d9f4ff; font-size: 12px; font-weight: 700; letter-spacing: .18em; text-transform: uppercase; }
.brand-mark { width: 27px; height: 27px; border: 1px solid #68d5ec; border-radius: 50%; display: grid; place-items: center; color: #70dff1; font-size: 15px; }
.live { display: flex; align-items: center; gap: 8px; padding: 9px 14px; border: 1px solid #a6e7f12c; border-radius: 99px; background: #0c2738a8; color: #b8dce8; font-size: 10px; letter-spacing: .12em; text-transform: uppercase; }
.dot { width: 6px; height: 6px; background: #65e3c2; border-radius: 50%; box-shadow: 0 0 12px #65e3c2; }
.title { position: absolute; top: 110px; left: 7.2%; }
.eyebrow { color: #75d9e9; font-size: 10px; font-weight: 700; letter-spacing: .24em; text-transform: uppercase; margin-bottom: 13px; }
h1 { margin: 0; font-size: clamp(34px, 4.2vw, 59px); line-height: .98; letter-spacing: -.055em; font-weight: 500; }
.subtitle { margin-top: 15px; color: #a1c1d0; font-size: 13px; letter-spacing: .015em; }
.hint {
position: absolute; left: 50%; bottom: 34px; transform: translateX(-50%);
display: flex; align-items: center; gap: 12px; padding: 12px 18px;
border: 1px solid #9be9f02e; border-radius: 40px; background: #062337b8;
box-shadow: 0 8px 35px #03121d66; color: #c5e2eb; font-size: 12px; white-space: nowrap;
backdrop-filter: blur(12px);
}
.pointer-icon { width: 19px; height: 19px; border: 1px solid #8de4ef; border-radius: 50%; position: relative; }
.pointer-icon:after { content:""; position:absolute; width:4px; height:4px; background:#8de4ef; border-radius:50%; left:6.5px; top:6.5px; box-shadow:0 0 8px #8de4ef; }
.footer { position:absolute; bottom:38px; right:42px; color:#84aab8; font-size:9px; letter-spacing:.17em; text-transform:uppercase; }
@media(max-width:600px) {
.topbar { top:20px; left:20px; right:20px; }
.title { top:100px; left:24px; }
.subtitle { max-width:250px; line-height:1.5; }
.hint { bottom:24px; font-size:10px; padding:11px 14px; }
.footer { display:none; }
}
</style>
</head>
<body>
<div id="scene"></div>
<div class="hud">
<div class="topbar">
<div class="brand"><span class="brand-mark">✳</span> Stillwater Studio</div>
<div class="live"><span class="dot"></span> Live habitat</div>
</div>
<div class="title">
<div class="eyebrow">A quiet moment below the surface</div>
<h1>Bluewater<br>aquarium</h1>
<div class="subtitle">A little world that responds to your presence.</div>
</div>
<div class="hint"><span class="pointer-icon"></span> Move your cursor near the fish</div>
<div class="footer">Move gently · Observe quietly</div>
</div>
<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>
<script type="module">
import * as THREE from 'three';
const mount = document.querySelector('#scene');
const scene = new THREE.Scene();
scene.background = new THREE.Color(0x071c2b);
scene.fog = new THREE.Fog(0x0a2a3c, 13, 30);
const camera = new THREE.PerspectiveCamera(37, innerWidth / innerHeight, .1, 80);
camera.position.set(0, 2.0, 16.8);
camera.lookAt(0, 0, 0);
const renderer = new THREE.WebGLRenderer({ antialias: true, alpha: false });
renderer.setPixelRatio(Math.min(devicePixelRatio, 2));
renderer.setSize(innerWidth, innerHeight);
renderer.outputColorSpace = THREE.SRGBColorSpace;
renderer.toneMapping = THREE.ACESFilmicToneMapping;
renderer.toneMappingExposure = 1.14;
mount.appendChild(renderer.domElement);
scene.add(new THREE.HemisphereLight(0xa7efff, 0x123343, 2.0));
const key = new THREE.DirectionalLight(0xa7f0ff, 2.5);
key.position.set(-4, 7, 8); scene.add(key);
const warm = new THREE.PointLight(0xffbd78, 28, 18);
warm.position.set(3, 2, 6); scene.add(warm);
const tank = new THREE.Group(); scene.add(tank);
const glassMat = new THREE.MeshPhysicalMaterial({ color: 0x78d8e5, transparent: true, opacity: .065, roughness: .08, metalness: .1, side: THREE.DoubleSide, depthWrite: false });
const edgeMat = new THREE.LineBasicMaterial({ color: 0x83d9e5, transparent: true, opacity: .34 });
const boxGeo = new THREE.BoxGeometry(13.2, 6.6, 5.6);
const glass = new THREE.Mesh(boxGeo, glassMat); glass.position.y = -.15; tank.add(glass);
const edges = new THREE.LineSegments(new THREE.EdgesGeometry(boxGeo), edgeMat); edges.position.copy(glass.position); tank.add(edges);
// Subtle back wall and sandy floor
const back = new THREE.Mesh(new THREE.PlaneGeometry(13.1, 6.5), new THREE.MeshStandardMaterial({ color: 0x0c3447, roughness: .9 }));
back.position.set(0, -.15, -2.78); tank.add(back);
const floor = new THREE.Mesh(new THREE.PlaneGeometry(13.1, 5.6), new THREE.MeshStandardMaterial({ color: 0x876f51, roughness: .95 }));
floor.rotation.x = -Math.PI / 2; floor.position.set(0, -3.43, 0); tank.add(floor);
// Lighting streaks and suspended particles
for (let i=0; i<5; i++) {
const beam = new THREE.Mesh(new THREE.PlaneGeometry(.23, 6.2), new THREE.MeshBasicMaterial({ color: 0x7ad9e7, transparent:true, opacity:.045, side:THREE.DoubleSide }));
beam.position.set(-4.8 + i*2.1, -.1, -2.72); beam.rotation.z = -.17; tank.add(beam);
}
const particles = [];
const particleMat = new THREE.MeshBasicMaterial({ color: 0xa8e9ea, transparent:true, opacity:.48 });
for(let i=0;i<85;i++){
const p = new THREE.Mesh(new THREE.SphereGeometry(.018 + Math.random()*.02, 6, 5), particleMat);
p.position.set((Math.random()-.5)*12, (Math.random()-.5)*5.8, (Math.random()-.5)*4.7);
p.userData.phase=Math.random()*6.28; tank.add(p); particles.push(p);
}
const rockMat = new THREE.MeshStandardMaterial({color:0x345957, roughness:1});
for(let i=0;i<18;i++){
const r = new THREE.Mesh(new THREE.IcosahedronGeometry(.22+Math.random()*.38,0), rockMat);
r.position.set(-5.7+i*.65, -3.12+Math.random()*.13, 1.8+(Math.random()-.5)*1.1);
r.scale.set(1.25,.65,.9); tank.add(r);
}
// Sea grass
const greenMat = new THREE.MeshStandardMaterial({color:0x237f71, roughness:.75, emissive:0x082d2c});
for(let i=0;i<12;i++){
const x=-5.6+i*.36;
for(let j=0;j<3;j++){
const h=.7+Math.random()*1.4;
const blade=new THREE.Mesh(new THREE.ConeGeometry(.105,h,5),greenMat);
blade.position.set(x+(Math.random()-.5)*.35,-3.0+h*.48,1.6+(Math.random()-.5)*.7);
blade.rotation.z=(Math.random()-.5)*.3; tank.add(blade);
}
}
function makeFish(color, size=1, accent=0xffe3a2) {
const g = new THREE.Group();
const bodyMat = new THREE.MeshStandardMaterial({color, roughness:.34, metalness:.08, emissive:color, emissiveIntensity:.08});
const finMat = new THREE.MeshStandardMaterial({color:accent, roughness:.38, transparent:true, opacity:.85, side:THREE.DoubleSide});
const body = new THREE.Mesh(new THREE.SphereGeometry(1,24,16), bodyMat);
body.scale.set(.72,.37,.3); g.add(body);
const tailShape = new THREE.Shape();
tailShape.moveTo(-.55,0); tailShape.quadraticCurveTo(-1.02,.45,-1.18,.36); tailShape.quadraticCurveTo(-1.04,0,-1.18,-.36); tailShape.quadraticCurveTo(-.92,-.4,-.55,0);
const tail = new THREE.Mesh(new THREE.ShapeGeometry(tailShape,12), finMat);
tail.position.z=.015; g.add(tail); g.userData.tail=tail;
const dorsal = new THREE.Mesh(new THREE.ConeGeometry(.24,.34,3),finMat);
dorsal.position.set(-.05,.35,0); dorsal.rotation.z=Math.PI/2; g.add(dorsal);
const pectoral = new THREE.Mesh(new THREE.ConeGeometry(.18,.28,3),finMat);
pectoral.position.set(.12,-.08,.28); pectoral.rotation.z=-.35; g.add(pectoral);
const eyeWhite = new THREE.Mesh(new THREE.SphereGeometry(.07,12,10),new THREE.MeshBasicMaterial({color:0xffffff}));
eyeWhite.position.set(.42,.1,.25); g.add(eyeWhite);
const pupil = new THREE.Mesh(new THREE.SphereGeometry(.035,10,8),new THREE.MeshBasicMaterial({color:0x10212b}));
pupil.position.set(.445,.1,.306); g.add(pupil);
g.scale.setScalar(size);
g.userData.size=size;
return g;
}
const specs=[
[0xff8b45,.9,0xffd26d,-3.2,.65,.4],
[0x29c6c8,.72,0x9ff2dc,-1.1,-.55,-.8],
[0xffd45e,.66,0xfff0aa,1.25,.2,.8],
[0xef668b,.82,0xffb3b5,3.1,-.8,-.5],
[0x83b8fa,.58,0xb6e9ff,4.0,.8,1.1],
[0xffa65e,.56,0xffe2a4,-4.2,-1.25,-1.1],
[0x7de0a6,.48,0xc4f4c8,2.1,1.15,-1.35]
];
const fish=specs.map((s,i)=>{
const f=makeFish(s[0],s[1],s[2]); tank.add(f);
f.position.set(s[3],s[4],s[5]);
f.userData.base=new THREE.Vector3(s[3],s[4],s[5]);
f.userData.phase=i*1.73; f.userData.speed=.35+Math.random()*.2; f.userData.flee=new THREE.Vector3();
return f;
});
const mouse = new THREE.Vector2(99,99);
const raycaster = new THREE.Raycaster();
const plane = new THREE.Plane(new THREE.Vector3(0,0,1),0);
const mouseWorld = new THREE.Vector3();
let hasPointer=false;
renderer.domElement.addEventListener('pointermove',e=>{
const r=renderer.domElement.getBoundingClientRect();
mouse.x=((e.clientX-r.left)/r.width)*2-1;
mouse.y=-((e.clientY-r.top)/r.height)*2+1;
raycaster.setFromCamera(mouse,camera);
raycaster.ray.intersectPlane(plane,mouseWorld);
hasPointer=true;
});
renderer.domElement.addEventListener('pointerleave',()=>{hasPointer=false;});
const clock=new THREE.Clock();
function animate(){
requestAnimationFrame(animate);
const t=clock.getElapsedTime();
for(const f of fish){
const b=f.userData.base, phase=f.userData.phase;
const homeX=b.x+Math.sin(t*.38+phase)*.62;
const homeY=b.y+Math.sin(t*.7+phase)*.22;
const homeZ=b.z+Math.cos(t*.31+phase)*.3;
const away=new THREE.Vector3();
if(hasPointer){
const dx=homeX-mouseWorld.x, dy=homeY-mouseWorld.y;
const d=Math.sqrt(dx*dx+dy*dy);
if(d<2.25){
const strength=(2.25-d)/2.25;
away.set(dx,dy,0).normalize().multiplyScalar(strength*1.5);
}
}
f.userData.flee.lerp(away,.055);
f.position.set(homeX+f.userData.flee.x,homeY+f.userData.flee.y,homeZ);
const drift=Math.cos(t*.45+phase);
const direction=Math.sin(t*.32+phase);
f.rotation.y=direction*.18;
f.rotation.z=Math.sin(t*1.5+phase)*.045;
f.userData.tail.rotation.y=Math.sin(t*10+phase)*.42;
// swim mostly across the tank, turning gently
f.scale.x=Math.abs(f.userData.size)*(direction < -.86 ? -1 : 1);
}
particles.forEach(p=>{p.position.y+=Math.sin(t*.5+p.userData.phase)*.0008; p.position.x+=Math.sin(t*.25+p.userData.phase)*.0012;});
renderer.render(scene,camera);
}
animate();
addEventListener('resize',()=>{
camera.aspect=innerWidth/innerHeight;
camera.position.z=innerWidth<600?19:16.8;
camera.updateProjectionMatrix();
renderer.setSize(innerWidth,innerHeight);
});
</script>
</body>
</html>