Models 44

Muse Ember

Open in new window

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

How it went

Total time
10.5 s
Cost
$0.0028
Output tokens
5,554
Spent thinking
89 tokens
Speed
588.1 tok/s
Console errors
0
First token after
1.1 s
First visible text after
1.1 s
Prompt tokens
441
Code size
16.6 KB
Finish reason
stop
Served by
Meta
Model id
meta/muse-ember
Reasoning sent
{"effort":"minimal"}
Max output
943,718 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 · 317 lines

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8"/>
<meta name="viewport" content="width=device-width,initial-scale=1"/>
<title>3D Aquarium — 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;height:100%;overflow:hidden;background:#062a3f;font-family:Inter,system-ui,-apple-system,Segoe UI,Roboto,Arial,sans-serif;color:#eaf7ff}
  #app{position:fixed;inset:0}
  canvas{display:block;width:100%;height:100%}
  .ui{position:fixed;left:18px;top:18px;z-index:10;pointer-events:none;max-width:460px}
  .card{pointer-events:auto;background:linear-gradient(160deg,rgba(6,45,72,.82),rgba(4,26,44,.68));border:1px solid rgba(140,220,255,.28);backdrop-filter:blur(12px);border-radius:18px;padding:14px 16px 12px;box-shadow:0 18px 50px rgba(0,0,0,.35)}
  h1{margin:0;font-size:22px;letter-spacing:.2px;line-height:1.1}
  h1 span{color:#6ee7ff}
  p{margin:7px 0 0;font-size:13.5px;line-height:1.45;color:#cdeefb}
  .badges{display:flex;gap:8px;flex-wrap:wrap;margin-top:10px}
  .badge{font-size:11px;font-weight:700;letter-spacing:.4px;text-transform:uppercase;background:rgba(110,231,255,.13);border:1px solid rgba(110,231,255,.3);padding:6px 9px;border-radius:999px;color:#dff8ff}
  .controls{position:fixed;left:18px;bottom:18px;z-index:10;display:flex;gap:10px;flex-wrap:wrap;pointer-events:auto}
  button{border:1px solid rgba(140,220,255,.35);background:rgba(8,55,84,.85);color:white;padding:10px 14px;border-radius:999px;font-weight:700;cursor:pointer;box-shadow:0 8px 24px rgba(0,0,0,.25)}
  button:hover{background:#0b6b9b}
  button.primary{background:linear-gradient(135deg,#06b6d4,#2563eb)}
  .hint{position:fixed;right:18px;top:18px;z-index:10;background:rgba(3,25,42,.62);border:1px solid rgba(140,220,255,.25);backdrop-filter:blur(10px);padding:10px 12px;border-radius:14px;font-size:12.5px;line-height:1.4;max-width:260px;pointer-events:none}
  .hint b{color:#6ee7ff}
  .counter{position:fixed;right:18px;bottom:18px;z-index:10;background:rgba(3,25,42,.68);border:1px solid rgba(140,220,255,.25);backdrop-filter:blur(10px);padding:10px 13px;border-radius:14px;font-weight:800;font-size:13px;pointer-events:none}
  .counter i{font-style:normal;color:#6ee7ff}
  #fleeFlash{position:fixed;left:50%;top:50%;transform:translate(-50%,-50%);z-index:11;pointer-events:none;font-size:clamp(28px,5vw,56px);font-weight:900;letter-spacing:.5px;color:white;text-shadow:0 10px 40px rgba(0,190,255,.8);opacity:0;transition:opacity .18s,transform .18s}
  #fleeFlash.show{opacity:1;transform:translate(-50%,-58%) scale(1.03)}
  #startOverlay{position:fixed;inset:0;z-index:9;display:grid;place-items:center;background:radial-gradient(circle at 50% 40%,rgba(14,116,144,.22),rgba(2,18,32,.55));pointer-events:none}
  #startOverlay .inner{text-align:center;pointer-events:auto;background:rgba(3,30,52,.72);border:1px solid rgba(140,220,255,.32);backdrop-filter:blur(12px);padding:16px 20px;border-radius:18px;box-shadow:0 20px 60px rgba(0,0,0,.35)}
  #startOverlay h2{margin:0 0 6px;font-size:20px}
  #startOverlay p{margin:0;color:#cdeefb;font-size:13px}
  @media(max-width:640px){.ui{left:12px;top:12px;right:12px}.hint{display:none}.controls{left:12px;bottom:12px}.counter{right:12px;bottom:12px}h1{font-size:19px}}
</style>
</head>
<body>
<div id="app"></div>

<div class="ui">
  <div class="card">
    <h1>🫧 3D Aquarium <span>Live Tank</span></h1>
    <p>Move your mouse (or finger) close to a fish — it will dart away! Drag to orbit, scroll to zoom. Fish also wander, nibble plants and blow bubbles on their own.</p>
    <div class="badges"><span class="badge">Three.js WebGL</span><span class="badge">Flee AI</span><span class="badge">No downloads</span></div>
  </div>
</div>

<div class="hint"><b>How to play</b><br>• Hover near fish to scare them<br>• Drag background to orbit<br>• Scroll / pinch to zoom<br>• Press <b>F</b> to feed, <b>Space</b> to scatter</div>

<div class="controls">
  <button id="feedBtn" class="primary">🍤 Feed fish</button>
  <button id="scatterBtn">💨 Scatter burst</button>
  <button id="camBtn">🎥 Auto-orbit: ON</button>
</div>

<div class="counter">Fish scared: <i id="scared">0</i> &nbsp;•&nbsp; Bubbles: <i id="bubbles">0</i></div>
<div id="fleeFlash">💨 WHOOSH!</div>
<div id="startOverlay"><div class="inner"><h2>Click or press a key to start</h2><p>Then move your cursor near the fish — they flee!</p></div></div>

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

const app=document.getElementById('app');
const scene=new THREE.Scene();
scene.background=new THREE.Color(0x07395b);
scene.fog=new THREE.FogExp2(0x07395b,0.028);

const camera=new THREE.PerspectiveCamera(58,innerWidth/innerHeight,0.1,100);
camera.position.set(0,2.2,10.5);

const renderer=new THREE.WebGLRenderer({antialias:true});
renderer.setSize(innerWidth,innerHeight);
renderer.setPixelRatio(Math.min(devicePixelRatio,2));
renderer.shadowMap.enabled=true;
renderer.shadowMap.type=THREE.PCFSoftShadowMap;
app.appendChild(renderer.domElement);

const controls=new OrbitControls(camera,renderer.domElement);
controls.enableDamping=true; controls.dampingFactor=.06;
controls.target.set(0,0.2,0); controls.minDistance=5; controls.maxDistance=16;
controls.maxPolarAngle=Math.PI*0.62; controls.autoRotate=true; controls.autoRotateSpeed=.45;

scene.add(new THREE.AmbientLight(0xbfefff,.65));
const sun=new THREE.DirectionalLight(0xffffff,1.5); sun.position.set(5,10,6); sun.castShadow=true; sun.shadow.mapSize.set(2048,2048); scene.add(sun);
const blue=new THREE.PointLight(0x22d3ee,18,18); blue.position.set(-4,4,4); scene.add(blue);
const warm=new THREE.PointLight(0xffcc88,10,15); warm.position.set(5,2,-3); scene.add(warm);

// Tank bounds
const W=12,H=6.4,D=6;
const tank=new THREE.Group(); scene.add(tank);

// Back wall / water tint
const backGeo=new THREE.PlaneGeometry(W,H);
const backMat=new THREE.MeshStandardMaterial({color:0x0b5f86,roughness:.9,metalness:0});
const back=new THREE.Mesh(backGeo,backMat); back.position.set(0,H/2-1.2,-D/2); tank.add(back);
// Side walls subtle
[-W/2,W/2].forEach(x=>{const m=new THREE.Mesh(new THREE.PlaneGeometry(D,H),new THREE.MeshStandardMaterial({color:0x0a4a6b,roughness:1,transparent:true,opacity:.9}));m.position.set(x,H/2-1.2,0);m.rotation.y=x<0?Math.PI/2:-Math.PI/2;tank.add(m);});
// Sandy floor
const sand=new THREE.Mesh(new THREE.BoxGeometry(W,.7,D),new THREE.MeshStandardMaterial({color:0xe8d8a8,roughness:1}));
sand.position.y=-1.55; sand.receiveShadow=true; tank.add(sand);
// Glass edges
const glassMat=new THREE.MeshPhysicalMaterial({color:0xbfefff,transparent:true,opacity:.14,roughness:.08,metalness:0,clearcoat:1});
const glass=new THREE.Mesh(new THREE.BoxGeometry(W,H,D),glassMat); glass.position.y=H/2-1.2; tank.add(glass);
const frameMat=new THREE.MeshStandardMaterial({color:0x0f2f42,roughness:.4,metalness:.6});
[[W+.15,.18,D+.15,0,H/2-1.2+D/2-.09,0],[W+.15,.18,D+.15,0,H/2-1.2-D/2+.09,0]].forEach(([a,b,c,x,y,z])=>{const f=new THREE.Mesh(new THREE.BoxGeometry(a,b,c),frameMat);f.position.set(x,y,z);tank.add(f);});

// Rocks
const rockMat=new THREE.MeshStandardMaterial({color:0x6b7f8d,roughness:.95});
for(let i=0;i<14;i++){
  const s=.5+Math.random()*1.1;
  const r=new THREE.Mesh(new THREE.DodecahedronGeometry(s,1),rockMat);
  r.position.set((Math.random()*2-1)*(W/2-1),-1.15+Math.random()*.25,(Math.random()*2-1)*(D/2-1));
  r.rotation.set(Math.random()*3,Math.random()*3,Math.random()*3); r.castShadow=r.receiveShadow=true; tank.add(r);
}
// Plants
const plants=[];
function makePlant(x,z,scale,hue){
  const g=new THREE.Group();
  const mat=new THREE.MeshStandardMaterial({color:new THREE.Color().setHSL(hue,.65,.32),roughness:.7,side:THREE.DoubleSide});
  for(let i=0;i<9;i++){
    const leaf=new THREE.Mesh(new THREE.ConeGeometry(.09*(1+Math.random()*.6),1.4+Math.random()*1.6,6),mat);
    leaf.position.set((Math.random()-.5)*.7,.7,(Math.random()-.5)*.7);
    leaf.rotation.z=(Math.random()-.5)*.55; leaf.rotation.x=(Math.random()-.5)*.4;
    leaf.castShadow=true; g.add(leaf);
  }
  g.position.set(x,-1.2,z); g.scale.setScalar(scale); tank.add(g); plants.push({g,phase:Math.random()*10});
  return g;
}
for(let i=0;i<16;i++) makePlant((Math.random()*2-1)*(W/2-1.2),(Math.random()*2-1)*(D/2-1.2),.8+Math.random()*1.1, .32+Math.random()*.12);
makePlant(-4.8,-1.5,1.8,.38); makePlant(4.9,1.2,1.9,.35); makePlant(0,-2.2,1.5,.33);

// Bubbles from aerator
const bubbleGeo=new THREE.SphereGeometry(.09,10,10);
const bubbleMat=new THREE.MeshStandardMaterial({color:0xcff6ff,transparent:true,opacity:.55,roughness:.1,metalness:.1});
const bubbles=[];
for(let i=0;i<90;i++){
  const b=new THREE.Mesh(bubbleGeo,bubbleMat);
  b.position.set(-5.2+Math.random()*.4,-1+Math.random()*4.5,(Math.random()-.5)*1.2);
  b.userData={speed:.6+Math.random()*1.2,wob:Math.random()*10};
  const s=.5+Math.random()*1.4; b.scale.setScalar(s); tank.add(b); bubbles.push(b);
}
// Light rays
for(let i=0;i<6;i++){
  const ray=new THREE.Mesh(new THREE.PlaneGeometry(.7,H),new THREE.MeshBasicMaterial({color:0x9beeff,transparent:true,opacity:.06,side:THREE.DoubleSide,depthWrite:false}));
  ray.position.set(-4+i*1.6,1.5,-1); ray.rotation.z=.25; tank.add(ray);
}

// Fish factory
const fishes=[];
const palette=[0xff7a18,0xff3b7f,0xffd93b,0x28d17c,0x38bdf8,0xa78bfa,0xfb923c,0xf472b6,0x34d399,0x60a5fa,0xe879f9,0xfacc15,0x2dd4bf,0xfdba74];
function makeFish(color,i){
  const g=new THREE.Group();
  const mat=new THREE.MeshStandardMaterial({color,roughness:.35,metalness:.15});
  const body=new THREE.Mesh(new THREE.SphereGeometry(.34,22,16),mat);
  body.scale.set(1.45,.72,.5); body.castShadow=true; g.add(body);
  const tail=new THREE.Mesh(new THREE.ConeGeometry(.28,.55,4),mat);
  tail.position.x=-.62; tail.rotation.z=Math.PI/2; tail.scale.z=.35; g.add(tail);
  const fin=new THREE.Mesh(new THREE.ConeGeometry(.16,.32,4),mat);
  fin.position.set(.05,.28,0); fin.rotation.x=.2; fin.scale.z=.3; g.add(fin);
  const eyeMat=new THREE.MeshBasicMaterial({color:0x111111});
  [-.18,.18].forEach(z=>{const e=new THREE.Mesh(new THREE.SphereGeometry(.055,10,10),eyeMat);e.position.set(.38,.08,z);e.scale.z=.5;g.add(e);});
  // stripes for some
  if(i%3===0){const stripe=new THREE.Mesh(new THREE.TorusGeometry(.26,.035,8,20),new THREE.MeshStandardMaterial({color:0xffffff}));stripe.position.x=.05;stripe.rotation.y=Math.PI/2;stripe.scale.set(1,.7,.5);g.add(stripe);}
  g.position.set((Math.random()*2-1)*4,Math.random()*3-0.5,(Math.random()*2-1)*1.8);
  scene.add(g);
  const fish={g,body,tail,vel:new THREE.Vector3(),target:new THREE.Vector3(),speed:.9+Math.random()*.9,flee:0,phase:Math.random()*10,scared:false};
  fish.target.copy(g.position); fishes.push(fish); return fish;
}
for(let i=0;i<18;i++) makeFish(palette[i%palette.length],i);

// Food pellets
const foods=[];
function feed(){
  for(let i=0;i<26;i++){
    const f=new THREE.Mesh(new THREE.SphereGeometry(.07,8,8),new THREE.MeshStandardMaterial({color:0xffb347}));
    f.position.set((Math.random()*2-1)*3,3.2+Math.random(),(Math.random()*2-1)*1.5);
    f.userData={vy:-.35-Math.random()*.3,life:8+Math.random()*5}; scene.add(f); foods.push(f);
  }
  fishes.forEach(f=>{f.target.set((Math.random()*2-1)*4,Math.random()*2+.5,(Math.random()*2-1)*1.5);});
}

// Mouse / pointer -> 3D point on tank plane
const raycaster=new THREE.Raycaster();
const pointerNDC=new THREE.Vector2(10,10);
const pointer3D=new THREE.Vector3(999,999,999);
const pointerActive=false;
let hasPointer=false;
let scaredCount=0;
const flash=document.getElementById('fleeFlash');
let flashT=null;

function updatePointer(e){
  const x=e.clientX??e.touches?.[0]?.clientX, y=e.clientY??e.touches?.[0]?.clientY;
  if(x==null) return;
  pointerNDC.x=(x/innerWidth)*2-1; pointerNDC.y=-(y/innerHeight)*2+1;
  hasPointer=true; hideStart();
}
addEventListener('pointermove',updatePointer,{passive:true});
addEventListener('touchmove',updatePointer,{passive:true});
addEventListener('pointerdown',updatePointer,{passive:true});

function hideStart(){document.getElementById('startOverlay').style.display='none';}
addEventListener('keydown',hideStart);
renderer.domElement.addEventListener('pointerdown',hideStart);

document.getElementById('feedBtn').onclick=feed;
document.getElementById('scatterBtn').onclick=scatter;
function scatter(){ fishes.forEach(f=>{f.flee=1.2; f.vel.add(new THREE.Vector3((Math.random()-.5)*4,(Math.random())*2,(Math.random()-.5)*4)); flashIt();}); }
document.getElementById('camBtn').onclick=(e)=>{controls.autoRotate=!controls.autoRotate; e.target.textContent='🎥 Auto-orbit: '+(controls.autoRotate?'ON':'OFF');};
addEventListener('keydown',e=>{ if(e.code==='KeyF') feed(); if(e.code==='Space'){e.preventDefault(); scatter();}});
function flashIt(){ flash.classList.add('show'); clearTimeout(flashT); flashT=setTimeout(()=>flash.classList.remove('show'),450); scaredCount++; document.getElementById('scared').textContent=scaredCount; }

// initial demo feed so something happens immediately
setTimeout(feed,600);

const clock=new THREE.Clock();
const tmpV=new THREE.Vector3(), tmp2=new THREE.Vector3();

function animate(){
  requestAnimationFrame(animate);
  const dt=Math.min(clock.getDelta(),.05);
  const t=clock.elapsedTime;

  // update pointer 3D: intersect a virtual plane at z=0 and also closest approach
  if(hasPointer){
    raycaster.setFromCamera(pointerNDC,camera);
    // intersect plane z=0 for a stable pointer point inside tank
    const plane=new THREE.Plane(new THREE.Vector3(0,0,1),0);
    raycaster.ray.intersectPlane(plane,pointer3D);
    pointer3D.x=THREE.MathUtils.clamp(pointer3D.x,-W/2+ .5,W/2-.5);
    pointer3D.y=THREE.MathUtils.clamp(pointer3D.y,-1,3.8);
    pointer3D.z=THREE.MathUtils.clamp(pointer3D.z,-D/2+.5,D/2-.5);
  }

  // Plants sway
  plants.forEach(p=>{p.g.rotation.z=Math.sin(t*1.1+p.phase)*.06; p.g.rotation.x=Math.cos(t*.8+p.phase)*.04;});

  // Bubbles
  bubbles.forEach(b=>{
    b.position.y+=b.userData.speed*dt;
    b.position.x+=Math.sin(t*2+b.userData.wob)*.008;
    if(b.position.y>3.9){b.position.y=-1; b.position.x=-5.2+Math.random()*.4;}
  });
  document.getElementById('bubbles').textContent=bubbles.length;

  // Foods sink
  for(let i=foods.length-1;i>=0;i--){const f=foods[i]; f.position.y+=f.userData.vy*dt; f.userData.life-=dt; if(f.position.y<-.9||f.userData.life<=0){scene.remove(f); foods.splice(i,1);}}

  // Fish AI
  fishes.forEach((fish,idx)=>{
    const pos=fish.g.position;
    // distance to pointer
    let fleeing=false;
    if(hasPointer){
      const d=pos.distanceTo(pointer3D);
      if(d<2.4){
        fleeing=true;
        if(!fish.scared){ flashIt(); }
        fish.scared=true; fish.flee=1;
        tmpV.copy(pos).sub(pointer3D).normalize();
        // add upward/outward bias
        tmpV.y+=.55; tmpV.z+=(Math.random()-.5)*.4;
        tmpV.normalize().multiplyScalar((2.4-d)*3.2+1.2);
        fish.vel.lerp(tmpV,.25);
      } else if(d>3.2){ fish.scared=false; }
    }
    if(!fleeing){
      // wander / seek food
      if(pos.distanceTo(fish.target)<.6 || Math.random()<.005){
        fish.target.set((Math.random()*2-1)*(W/2-1.2),Math.random()*3-.4,(Math.random()*2-1)*(D/2-1.2));
        if(foods.length){ const f=foods[Math.floor(Math.random()*foods.length)]; fish.target.copy(f.position); }
      }
      tmpV.copy(fish.target).sub(pos).normalize().multiplyScalar(fish.speed);
      // gentle sine wander
      tmpV.x+=Math.sin(t*1.2+fish.phase)*.25; tmpV.y+=Math.cos(t*1.5+fish.phase)*.15;
      fish.vel.lerp(tmpV, fleeing? .1 : .06);
    } else {
      fish.vel.multiplyScalar(1.02); // burst
    }
    // clamp speed
    if(fish.vel.length()>5.5) fish.vel.setLength(5.5);
    if(fish.vel.length()<.35 && !fleeing) fish.vel.setLength(.35);
    pos.addScaledVector(fish.vel,dt);

    // keep inside tank with soft bounce
    const mx=W/2-.8, myTop=3.6, myBot=-.7, mz=D/2-.8;
    if(pos.x>mx){pos.x=mx; fish.vel.x*=-.8; fish.target.x=-mx;}
    if(pos.x<-mx){pos.x=-mx; fish.vel.x*=-.8; fish.target.x=mx;}
    if(pos.y>myTop){pos.y=myTop; fish.vel.y*=-.8;}
    if(pos.y<myBot){pos.y=myBot; fish.vel.y*=-.6;}
    if(pos.z>mz){pos.z=mz; fish.vel.z*=-.8;}
    if(pos.z<-mz){pos.z=-mz; fish.vel.z*=-.8;}

    // orient fish along velocity
    if(fish.vel.lengthSq()>.001){
      tmp2.copy(pos).add(fish.vel);
      fish.g.lookAt(tmp2);
      fish.g.rotateY(Math.PI); // because body built +x forward? adjust
      // tail wag
      fish.tail.rotation.y=Math.sin(t*14+fish.phase)*.55;
      fish.body.position.y=Math.sin(t*8+fish.phase)*.03;
    }
  });

  controls.update();
  renderer.render(scene,camera);
}
animate();

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