Models 44

Dots3-Note Preview (free)

by Dots StudioReasoningClean
Open in new window

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

How it went

Total time
23.4 s
Cost
$0
Output tokens
2,303
Spent thinking
0 tokens
Speed
101.8 tok/s
Console errors
0
First token after
725 ms
First visible text after
725 ms
Prompt tokens
430
Code size
7.3 KB
Finish reason
stop
Served by
AtlasCloud
Model id
dots-studio/dots-3-note-preview:free
Reasoning sent
{"effort":"none"}
Max output
32,000 tokens
Generated
Nov 9, 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 · 266 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 – Fish Flee from Mouse</title>
<style>
  html, body { margin: 0; padding: 0; overflow: hidden; background: #001018; }
  #info {
    position: absolute; top: 12px; left: 12px; color: #cfe8ff;
    font: 14px/1.4 system-ui, sans-serif; pointer-events: none;
    text-shadow: 0 1px 2px #000;
  }
  #start {
    position: absolute; inset: 0; display: flex; align-items: center;
    justify-content: center; color: #eaf6ff; font: 20px system-ui, sans-serif;
    background: rgba(0,0,0,0.35); cursor: pointer; z-index: 10;
  }
</style>
</head>
<body>
<div id="info">Move the mouse near the fish — they will swim away.</div>
<div id="start">Click or press a key to start</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';
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';

// ---------- Scene, Camera, Renderer ----------
const scene = new THREE.Scene();
scene.background = new THREE.Color(0x001018);
scene.fog = new THREE.Fog(0x001018, 18, 45);

const camera = new THREE.PerspectiveCamera(60, innerWidth / innerHeight, 0.1, 200);
camera.position.set(0, 6, 14);

const renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setPixelRatio(Math.min(devicePixelRatio, 2));
renderer.setSize(innerWidth, innerHeight);
renderer.toneMapping = THREE.ACESFilmicToneMapping;
renderer.toneMappingExposure = 1.1;
document.body.appendChild(renderer.domElement);

const controls = new OrbitControls(camera, renderer.domElement);
controls.enableDamping = true;
controls.dampingFactor = 0.06;
controls.target.set(0, 0, 0);
controls.minDistance = 6;
controls.maxDistance = 30;
controls.maxPolarAngle = Math.PI * 0.52; // keep above ground

// ---------- Lighting ----------
scene.add(new THREE.AmbientLight(0x406080, 0.6));
const sun = new THREE.DirectionalLight(0xbfe3ff, 1.1);
sun.position.set(8, 12, 6);
scene.add(sun);
const fill = new THREE.DirectionalLight(0x406080, 0.5);
fill.position.set(-8, 4, -6);
scene.add(fill);

// ---------- Ground / Water floor ----------
const ground = new THREE.Mesh(
  new THREE.PlaneGeometry(60, 60),
  new THREE.MeshStandardMaterial({ color: 0x0a1a2a, roughness: 1, metalness: 0 })
);
ground.rotation.x = -Math.PI / 2;
ground.position.y = -4;
scene.add(ground);

// ---------- Water surface (subtle ripple plane) ----------
const water = new THREE.Mesh(
  new THREE.PlaneGeometry(60, 60),
  new THREE.MeshStandardMaterial({
    color: 0x103050,
    transparent: true,
    opacity: 0.35,
    roughness: 0.05,
    metalness: 0.2,
    side: THREE.DoubleSide
  })
);
water.rotation.x = -Math.PI / 2;
water.position.y = 0;
scene.add(water);

// ---------- Mouse ray ----------
const mouse = new THREE.Vector2(0.5, 0.5); // normalized device coords
const raycaster = new THREE.Raycaster();
const mouse3D = new THREE.Vector3(); // world position projected to y=0 plane
const mousePlane = new THREE.Plane(new THREE.Vector3(0,1,0), 0);
const mouseDir = new THREE.Vector3();

function updateMouse3D() {
  raycaster.setFromCamera(mouse, camera);
  raycaster.ray.intersectPlane(mousePlane, mouse3D);
}

// ---------- Fish factory ----------
function makeFish() {
  const group = new THREE.Group();

  // Body
  const body = new THREE.Mesh(
    new THREE.SphereGeometry(0.35, 16, 12),
    new THREE.MeshStandardMaterial({ color: 0xffcc88, roughness: 0.4, metalness: 0.1 })
  );
  body.scale.set(1, 0.7, 1.6);
  group.add(body);

  // Tail
  const tail = new THREE.Mesh(
    new THREE.ConeGeometry(0.25, 0.6, 12),
    new THREE.MeshStandardMaterial({ color: 0xffaa66, roughness: 0.5 })
  );
  tail.rotation.x = Math.PI / 2;
  tail.position.z = -0.7;
  group.add(tail);

  // Fin
  const fin = new THREE.Mesh(
    new THREE.SphereGeometry(0.18, 10, 8),
    new THREE.MeshStandardMaterial({ color: 0xffbb88, roughness: 0.5, transparent: true, opacity: 0.9 })
  );
  fin.position.y = 0.25;
  fin.scale.set(0.6, 0.4, 0.4);
  group.add(fin);

  // Eye
  const eye = new THREE.Mesh(
    new THREE.SphereGeometry(0.05, 8, 6),
    new THREE.MeshStandardMaterial({ color: 0x111, roughness: 0.2 })
  );
  eye.position.z = 0.5;
  eye.position.y = 0.1;
  group.add(eye);

  // Store references for animation
  group.userData = {
    tail,
    speed: 0.6 + Math.random() * 0.4,
    dir: new THREE.Vector3(
      (Math.random() - 0.5),
      0,
      (Math.random() - 0.5)
    ).normalize(),
    fleeRange: 2.5,
    fleeStrength: 4.0,
    originalY: -1 + Math.random() * 1.5
  };

  // Random position within bounds
  group.position.set(
    (Math.random() - 0.5) * 16,
    -3 + Math.random() * 2,
    (Math.random() - 0.5) * 16
  );

  // Face direction
  group.userData.dir.set(group.position.x > 0 ? -1 : 1, 0, 0);
  group.lookAt(group.position.clone().add(group.userData.dir));

  return group;
}

// ---------- Populate fish ----------
const fishCount = 24;
const fish = [];
for (let i = 0; i < fishCount; i++) {
  const f = makeFish();
  scene.add(f);
  fish.push(f);
}

// ---------- Input ----------
addEventListener('pointermove', (e) => {
  mouse.x = (e.clientX / innerWidth) * 2 - 1;
  mouse.y = -(e.clientY / innerHeight) * 2 + 1;
  updateMouse3D();
});

// ---------- Start overlay ----------
const startScreen = document.getElementById('start');
let started = false;
function begin() {
  if (started) return;
  started = true;
  startScreen.style.display = 'none';
}
startScreen.addEventListener('pointerdown', begin);
addEventListener('keydown', begin);

// ---------- Animation ----------
const clock = new THREE.Clock();

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

  // gentle water ripple
  water.rotation.z += dt * 0.2;

  // Update fish
  for (const f of fish) {
    const d = f.userData;
    const pos = f.position;

    // Flee behavior
    const dist = pos.distanceTo(mouse3D);
    if (dist < d.fleeRange) {
      const away = new THREE.Vector3()
        .subVectors(pos, mouse3D)
        .setY(0)
        .normalize();
      d.dir.lerp(away, 0.2).normalize();
    } else {
      // wander slowly
      const wander = new THREE.Vector3(
        Math.sin(performance.now() * 0.001 + pos.x) * 0.5,
        0,
        Math.cos(performance.now() * 0.001 + pos.z) * 0.5
      ).normalize();
      d.dir.lerp(wander, 0.02).normalize();
    }

    // Move
    pos.addScaledVector(d.dir, d.speed * dt);

    // Boundaries
    const limit = 9;
    if (Math.abs(pos.x) > limit) { pos.x = Math.sign(pos.x) * limit; d.dir.x *= -1; }
    if (Math.abs(pos.z) > limit) { pos.z = Math.sign(pos.z) * limit; d.dir.z *= -1; }

    // Keep within water column
    pos.y = Math.max(-3.5, Math.min(-0.5, pos.y + (d.originalY - pos.y) * 0.02));

    // Orient fish
    f.lookAt(pos.clone().add(d.dir));

    // Tail animation
    d.tail.rotation.y = Math.sin(performance.now() * 0.008 + pos.x) * 0.4;
  }

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

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

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