Models 44

DeepSeek V4.1 Flash 1017

by DeepSeekReasoningClean
Open in new window

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

How it went

Total time
17.7 s
Cost
$0.0030
Output tokens
6,032
Spent thinking
0 tokens
Speed
347.5 tok/s
Console errors
0
First token after
355 ms
First visible text after
355 ms
Prompt tokens
435
Code size
17.3 KB
Finish reason
stop
Served by
Wafer
Model id
deepseek/deepseek-v4.1-flash-1017
Reasoning sent
{"effort":"none"}
Max output
64,000 tokens
Generated
Nov 11, 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 · 508 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</title>
<style>
  * { margin: 0; padding: 0; box-sizing: border-box; }
  html, body { width: 100%; height: 100%; overflow: hidden; background: #001420; }
  #app { position: fixed; inset: 0; }
  canvas { display: block; }
  #overlay {
    position: fixed; inset: 0; z-index: 10;
    display: flex; align-items: center; justify-content: center;
    pointer-events: none;
    font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
    color: #eaf6ff;
  }
  #msg {
    background: rgba(4, 30, 48, 0.55);
    border: 1px solid rgba(140, 220, 255, 0.35);
    backdrop-filter: blur(6px);
    padding: 14px 26px;
    border-radius: 999px;
    font-size: 15px;
    letter-spacing: 0.4px;
    box-shadow: 0 6px 30px rgba(0,0,0,0.4);
    transition: opacity 0.5s ease, transform 0.5s ease;
    text-align: center;
    max-width: 90vw;
  }
  #msg.hide { opacity: 0; transform: translateY(-8px); }
  #hint {
    position: fixed; left: 50%; bottom: 18px; transform: translateX(-50%);
    z-index: 9; pointer-events: none;
    font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
    font-size: 12.5px; letter-spacing: 0.6px; color: rgba(200, 235, 255, 0.55);
    text-align: center;
  }
  @media (max-width: 480px) {
    #msg { font-size: 13px; padding: 11px 18px; }
    #hint { font-size: 11px; bottom: 12px; }
  }
</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="app"></div>
<div id="overlay"><div id="msg">Click or press a key to start &mdash; move your mouse to scare the fish</div></div>
<div id="hint">Mouse near the fish &rarr; they dart away</div>

<script type="module">
import * as THREE from 'three';

// ---------- Scene ----------
const app = document.getElementById('app');
const scene = new THREE.Scene();
scene.background = new THREE.Color(0x02121f);
scene.fog = new THREE.FogExp2(0x03202f, 0.018);

const camera = new THREE.PerspectiveCamera(55, window.innerWidth / window.innerHeight, 0.1, 400);
camera.position.set(0, 4.5, 34);
camera.lookAt(0, 2, 0);

const renderer = new THREE.WebGLRenderer({ antialias: true, alpha: false });
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.toneMapping = THREE.ACESFilmicToneMapping;
renderer.toneMappingExposure = 1.05;
app.appendChild(renderer.domElement);

// ---------- Lights ----------
const hemi = new THREE.HemisphereLight(0x9fe4ff, 0x051a26, 1.15);
scene.add(hemi);

const keyLight = new THREE.DirectionalLight(0xbdefff, 1.6);
keyLight.position.set(10, 30, 18);
scene.add(keyLight);

const rimLight = new THREE.DirectionalLight(0x2f8fbf, 0.7);
rimLight.position.set(-15, 8, -20);
scene.add(rimLight);

// Caustic-ish point lights from above
const glow = new THREE.PointLight(0x66d9ff, 90, 90, 2);
glow.position.set(0, 20, 4);
scene.add(glow);

// ---------- Aquarium volume ----------
const BOUNDS = new THREE.Vector3(30, 18, 20); // half-extents
const halfW = BOUNDS.x, halfH = BOUNDS.y * 0.5, halfD = BOUNDS.z;
const floorY = -halfH;

// Floor sand
const sandGeo = new THREE.PlaneGeometry(halfW * 2, halfD * 2, 60, 40);
{
  const pos = sandGeo.attributes.position;
  for (let i = 0; i < pos.count; i++) {
    const x = pos.getX(i), y = pos.getY(i);
    pos.setZ(i, Math.sin(x * 0.35) * 0.35 + Math.cos(y * 0.5) * 0.3 + Math.sin((x + y) * 0.2) * 0.4);
  }
  sandGeo.computeVertexNormals();
}
const sandMat = new THREE.MeshStandardMaterial({ color: 0x2a4a56, roughness: 1, metalness: 0.0, flatShading: true });
const sand = new THREE.Mesh(sandGeo, sandMat);
sand.rotation.x = -Math.PI / 2;
sand.position.y = floorY - 0.4;
scene.add(sand);

// Distant back wall gradient plane (subtle)
const wallMat = new THREE.MeshBasicMaterial({ color: 0x041d2c, transparent: true, opacity: 0.6 });
const backWall = new THREE.Mesh(new THREE.PlaneGeometry(halfW * 2.4, halfH * 2.4), wallMat);
backWall.position.set(0, 2, -halfD - 2);
scene.add(backWall);

// ---------- Helper textures ----------
function makeBubbleTexture() {
  const c = document.createElement('canvas');
  c.width = c.height = 64;
  const ctx = c.getContext('2d');
  const g = ctx.createRadialGradient(32, 32, 4, 32, 32, 30);
  g.addColorStop(0, 'rgba(220,245,255,0.9)');
  g.addColorStop(0.55, 'rgba(160,225,255,0.35)');
  g.addColorStop(1, 'rgba(120,200,255,0)');
  ctx.fillStyle = g;
  ctx.beginPath(); ctx.arc(32, 32, 30, 0, Math.PI * 2); ctx.fill();
  const t = new THREE.CanvasTexture(c);
  t.colorSpace = THREE.SRGBColorSpace;
  return t;
}
const bubbleTex = makeBubbleTexture();

// ---------- Seaweed ----------
const weedMat = new THREE.MeshStandardMaterial({ color: 0x1d6b52, roughness: 0.85, side: THREE.DoubleSide });
const weedGroup = new THREE.Group();
const weedData = [];
function makeWeed(x, z) {
  const segs = 6 + Math.floor(Math.random() * 4);
  const g = new THREE.Group();
  for (let i = 0; i < segs; i++) {
    const h = 0.9 + Math.random() * 0.5;
    const blade = new THREE.Mesh(new THREE.ConeGeometry(0.14, h, 4, 1, true), weedMat);
    blade.position.y = i * h * 0.8;
    blade.rotation.y = Math.random() * Math.PI;
    blade.castShadow = false;
    g.add(blade);
  }
  g.position.set(x, floorY - 0.2, z);
  g.userData.phase = Math.random() * Math.PI * 2;
  g.userData.baseSway = 0;
  weedGroup.add(g);
  weedData.push(g);
  return g;
}
for (let i = 0; i < 26; i++) {
  const x = (Math.random() - 0.5) * (halfW * 1.8);
  const z = -halfD * 0.5 - Math.random() * halfD * 0.55;
  makeWeed(x, z);
}
scene.add(weedGroup);

// Rocks
const rockMat = new THREE.MeshStandardMaterial({ color: 0x21414d, roughness: 1, flatShading: true });
for (let i = 0; i < 14; i++) {
  const r = 0.8 + Math.random() * 2.2;
  const rock = new THREE.Mesh(new THREE.DodecahedronGeometry(r, 0), rockMat);
  rock.position.set(
    (Math.random() - 0.5) * halfW * 1.9,
    floorY + r * 0.35 - 0.3,
    -halfD * 0.4 - Math.random() * halfD * 0.65
  );
  rock.rotation.set(Math.random() * 3, Math.random() * 3, Math.random() * 3);
  rock.scale.y = 0.55 + Math.random() * 0.4;
  scene.add(rock);
}

// ---------- Bubbles ----------
const bubbleCount = 220;
const bubbleGeo = new THREE.BufferGeometry();
const bubblePos = new Float32Array(bubbleCount * 3);
const bubbleVel = new Float32Array(bubbleCount);
const bubbleScale = new Float32Array(bubbleCount);
for (let i = 0; i < bubbleCount; i++) {
  bubblePos[i * 3] = (Math.random() - 0.5) * halfW * 2;
  bubblePos[i * 3 + 1] = floorY + Math.random() * halfH * 2;
  bubblePos[i * 3 + 2] = (Math.random() - 0.5) * halfD * 2;
  bubbleVel[i] = 1.2 + Math.random() * 2.5;
  bubbleScale[i] = 0.15 + Math.random() * 0.4;
}
bubbleGeo.setAttribute('position', new THREE.BufferAttribute(bubblePos, 3));
const bubbleMat = new THREE.PointsMaterial({
  map: bubbleTex, size: 0.9, transparent: true, opacity: 0.7,
  depthWrite: false, blending: THREE.AdditiveBlending, sizeAttenuation: true
});
const bubbles = new THREE.Points(bubbleGeo, bubbleMat);
scene.add(bubbles);

// ---------- Fish ----------
const fishColors = [
  0xff8a3d, 0xffd166, 0xef476f, 0x06d6a0, 0x118ab2,
  0xf78c6b, 0xa0e7ff, 0xffb703, 0xff6b9d, 0x7b2cbf
];

function createFish(colorHex, size) {
  const group = new THREE.Group();
  const bodyMat = new THREE.MeshStandardMaterial({ color: colorHex, roughness: 0.45, metalness: 0.15, flatShading: false });
  const finMat = new THREE.MeshStandardMaterial({
    color: new THREE.Color(colorHex).offsetHSL(0, -0.1, -0.12),
    roughness: 0.6, side: THREE.DoubleSide, transparent: true, opacity: 0.92
  });

  // Body: sphere scaled
  const body = new THREE.Mesh(new THREE.SphereGeometry(0.5, 14, 10), bodyMat);
  body.scale.set(1.4, 1.0, 0.72);
  group.add(body);

  // Tail (cone) — pointing -Z (behind fish), fish faces +Z
  const tail = new THREE.Mesh(new THREE.ConeGeometry(0.42, 0.75, 8), finMat);
  tail.rotation.x = -Math.PI / 2;
  tail.position.z = -0.85;
  tail.scale.set(1, 1, 0.35);
  group.add(tail);

  // Top dorsal fin
  const dorsal = new THREE.Mesh(new THREE.ConeGeometry(0.28, 0.5, 4), finMat);
  dorsal.position.set(0, 0.48, -0.1);
  dorsal.scale.set(1, 1, 0.4);
  group.add(dorsal);

  // Side fins
  const finL = new THREE.Mesh(new THREE.ConeGeometry(0.18, 0.5, 4), finMat);
  finL.position.set(0.28, 0.05, 0.15);
  finL.rotation.z = Math.PI / 2.6;
  finL.scale.set(1, 1, 0.35);
  group.add(finL);
  const finR = finL.clone();
  finR.position.x = -0.28;
  finR.rotation.z = -Math.PI / 2.6;
  group.add(finR);

  // Eyes
  const eyeGeo = new THREE.SphereGeometry(0.09, 8, 8);
  const eyeMat = new THREE.MeshStandardMaterial({ color: 0x0b0b0b, roughness: 0.2 });
  const eyeL = new THREE.Mesh(eyeGeo, eyeMat);
  eyeL.position.set(0.2, 0.16, 0.52);
  group.add(eyeL);
  const eyeR = eyeL.clone();
  eyeR.position.x = -0.2;
  group.add(eyeR);

  group.scale.setScalar(size);
  group.userData.tail = tail;
  group.userData.body = body;
  return group;
}

const fishes = [];
const FISH_COUNT = 34;
for (let i = 0; i < FISH_COUNT; i++) {
  const size = 0.55 + Math.random() * 0.9;
  const color = fishColors[i % fishColors.length];
  const fish = createFish(color, size);
  // random start pos
  fish.position.set(
    (Math.random() - 0.5) * halfW * 1.7,
    (Math.random() - 0.5) * halfH * 1.5,
    (Math.random() - 0.5) * halfD * 1.6
  );
  const dir = new THREE.Vector3(Math.random() - 0.5, (Math.random() - 0.5) * 0.2, Math.random() - 0.5).normalize();
  fish.userData.velocity = dir.multiplyScalar(1.5 + Math.random() * 1.5);
  fish.userData.baseSpeed = 2.0 + Math.random() * 1.6;
  fish.userData.size = size;
  fish.userData.wander = Math.random() * Math.PI * 2;
  fish.userData.wobble = Math.random() * Math.PI * 2;
  fish.userData.fear = 0;
  fish.userData.target = new THREE.Vector3();
  fish.userData.hasTarget = false;
  scene.add(fish);
  fishes.push(fish);
}

// ---------- Mouse interaction ----------
const mouse = new THREE.Vector2(0, 0);
const raycaster = new THREE.Raycaster();
let plane = new THREE.Plane(new THREE.Vector3(0, 0, 1), 0);
const mouseWorld = new THREE.Vector3(0, 0, 0);
let pointerActive = false;
let pointerIdleTimer = 0;
let pointerScreen = { x: 0, y: 0 };
let started = false;

const msgEl = document.getElementById('msg');

function startInteraction() {
  if (!started) {
    started = true;
    msgEl.classList.add('hide');
    setTimeout(() => { msgEl.style.display = 'none'; }, 600);
  }
}

window.addEventListener('pointermove', (e) => {
  pointerScreen.x = (e.clientX / window.innerWidth) * 2 - 1;
  pointerScreen.y = -(e.clientY / window.innerHeight) * 2 + 1;
  pointerActive = true;
  pointerIdleTimer = 0;
  startInteraction();
});
window.addEventListener('pointerdown', startInteraction);
window.addEventListener('keydown', startInteraction);
window.addEventListener('touchstart', startInteraction, { passive: true });
window.addEventListener('touchmove', (e) => {
  if (e.touches.length) {
    const t = e.touches[0];
    pointerScreen.x = (t.clientX / window.innerWidth) * 2 - 1;
    pointerScreen.y = -(t.clientY / window.innerHeight) * 2 + 1;
    pointerActive = true;
    pointerIdleTimer = 0;
  }
}, { passive: true });

function updateMouseWorld() {
  raycaster.setFromCamera(pointerScreen, camera);
  // Compute intersection with a plane parallel to camera through origin
  const normal = new THREE.Vector3();
  camera.getWorldDirection(normal);
  plane.setFromNormalAndCoplanarPoint(normal, new THREE.Vector3(0, 2, 0));
  raycaster.ray.intersectPlane(plane, mouseWorld);
}

// ---------- Animation ----------
const clock = new THREE.Clock();
const tmpVec = new THREE.Vector3();
const tmpVec2 = new THREE.Vector3();
const up = new THREE.Vector3(0, 1, 0);

function updateFish(dt, t) {
  // update mouse world + activity
  if (pointerActive) {
    updateMouseWorld();
    pointerIdleTimer += dt;
    if (pointerIdleTimer > 2.5) {
      pointerActive = false;
    }
  }

  const mouseActive = pointerActive && started;
  const fearRadius = 7.0;

  for (let i = 0; i < fishes.length; i++) {
    const fish = fishes[i];
    const ud = fish.userData;
    const v = ud.velocity;

    // Wander: gently rotate velocity with noise
    ud.wander += dt * (0.6 + Math.sin(t * 0.7 + i) * 0.3);
    const wanderStrength = 2.5;
    v.x += Math.cos(ud.wander + i) * wanderStrength * dt;
    v.y += Math.sin(ud.wander * 1.3 + i * 0.7) * wanderStrength * 0.35 * dt;
    v.z += Math.sin(ud.wander * 0.8 + i * 1.3) * wanderStrength * dt;

    // Mouse fear
    if (mouseActive) {
      tmpVec.copy(fish.position).sub(mouseWorld);
      const dist = tmpVec.length();
      if (dist < fearRadius) {
        const strength = (1 - dist / fearRadius);
        ud.fear = Math.min(1, ud.fear + dt * 6 * strength);
        // flee direction (away from mouse)
        tmpVec.normalize();
        // add a bit of vertical evade to look lively
        tmpVec.y += (Math.random() - 0.5) * 0.3;
        v.addScaledVector(tmpVec, strength * 42 * dt);
      }
    }
    // fear decay
    ud.fear *= Math.pow(0.12, dt);
    if (ud.fear < 0.001) ud.fear = 0;

    // Speed clamp
    const speed = v.length();
    const maxSpeed = ud.baseSpeed + ud.fear * 12;
    if (speed > maxSpeed) {
      v.multiplyScalar(maxSpeed / speed);
    } else if (speed < ud.baseSpeed * 0.55) {
      // keep moving
      if (speed > 0.0001) v.multiplyScalar((ud.baseSpeed * 0.55) / speed);
      else v.set(Math.random() - 0.5, 0, Math.random() - 0.5).normalize().multiplyScalar(ud.baseSpeed);
    }

    // Steer away from walls (soft bounds)
    const margin = 4.0;
    const steer = 24 * dt;
    const x = fish.position.x, y = fish.position.y, z = fish.position.z;
    if (x > halfW - margin) v.x -= steer * (x - (halfW - margin)) / margin;
    if (x < -halfW + margin) v.x += steer * ((-halfW + margin) - x) / margin;
    if (y > halfH * 0.85 - 0.5) v.y -= steer * (y - (halfH * 0.85 - 0.5)) / margin;
    if (y < -halfH * 0.85 + 1.0) v.y += steer * ((-halfH * 0.85 + 1.0) - y) / margin;
    if (z > halfD - margin) v.z -= steer * (z - (halfD - margin)) / margin;
    if (z < -halfD + margin) v.z += steer * ((-halfD + margin) - z) / margin;

    // Apply velocity
    fish.position.addScaledVector(v, dt);

    // Orientation: fish model faces +Z. Build quaternion aligning +Z with velocity.
    if (speed > 0.01) {
      tmpVec2.copy(v).normalize();
      const targetQuat = new THREE.Quaternion().setFromUnitVectors(new THREE.Vector3(0, 0, 1), tmpVec2);
      fish.quaternion.slerp(targetQuat, Math.min(1, dt * 6));
    }

    // Tail wiggle
    ud.wobble += dt * (8 + ud.fear * 20 + speed * 1.2);
    const tail = ud.tail;
    if (tail) {
      tail.rotation.y = Math.sin(ud.wobble) * 0.5;
      tail.rotation.x = -Math.PI / 2 + Math.sin(ud.wobble * 1.3) * 0.15;
    }
    // slight body roll
    fish.rotateZ(Math.sin(ud.wobble * 0.5) * 0.02);
  }
}

function updateWeeds(t, dt) {
  for (let i = 0; i < weedData.length; i++) {
    const w = weedData[i];
    const ph = w.userData.phase;
    w.children.forEach((seg, idx) => {
      const sway = Math.sin(t * 1.1 + ph + idx * 0.5) * (0.04 + idx * 0.012);
      seg.rotation.z = sway;
    });
  }
}

function updateBubbles(dt, t) {
  const pos = bubbleGeo.attributes.position;
  for (let i = 0; i < bubbleCount; i++) {
    let y = pos.getY(i) + bubbleVel[i] * dt;
    let x = pos.getX(i) + Math.sin(t * 1.3 + i) * 0.006;
    let z = pos.getZ(i) + Math.cos(t * 1.1 + i * 0.7) * 0.006;
    if (y > halfH + 1.5) {
      y = floorY - 0.5;
      x = (Math.random() - 0.5) * halfW * 2;
      z = (Math.random() - 0.5) * halfD * 2;
    }
    pos.setX(i, x); pos.setY(i, y); pos.setZ(i, z);
  }
  pos.needsUpdate = true;
}

// Subtle camera drift, plus slight follow of pointer
let camBaseX = 0, camBaseY = 4.5, camBaseZ = 34;
function updateCamera(t) {
  const targetX = pointerActive ? pointerScreen.x * 3.5 : 0;
  const targetY = pointerActive ? 4.5 - pointerScreen.y * 2.0 : 4.5;
  camera.position.x += (targetX - camera.position.x) * 0.02;
  camera.position.y += (targetY - camera.position.y) * 0.02;
  camera.position.z = 34 + Math.sin(t * 0.15) * 1.2;
  camera.lookAt(0, 2.2 + Math.sin(t * 0.3) * 0.3, 0);
}

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

  updateFish(dt, t);
  updateWeeds(t, dt);
  updateBubbles(dt, t);
  updateCamera(t);

  // gentle light pulsing
  glow.intensity = 80 + Math.sin(t * 0.9) * 20;

  renderer.render(scene, camera);
}

// Auto-demo behaviour: if user hasn't interacted, simulate a moving pointer so fish are visibly spooked
let demoTimer = 0;
let demoActive = true;
const demoPointer = { x: 0, y: 0 };
window.addEventListener('pointermove', () => { demoActive = false; }, { once: true });

// Patch updateMouseWorld usage: if demo, we drive pointerScreen
const origUpdateFish = updateFish;
updateFish = function(dt, t) {
  if (demoActive) {
    // move pointer in a lissajous around fishes
    demoTimer += dt;
    demoPointer.x = Math.sin(demoTimer * 0.55) * 0.55;
    demoPointer.y = Math.sin(demoTimer * 0.83 + 1.0) * 0.35;
    pointerScreen.x = demoPointer.x;
    pointerScreen.y = demoPointer.y;
    pointerActive = true;
  }
  origUpdateFish(dt, t);
};

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

animate();
</script>
</body>
</html>