Models 44

Claude Haiku 4.5

by AnthropicReasoningClean
Open in new window

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

How it went

Total time
11.4 s
Cost
$0.018
Output tokens
3,416
Spent thinking
0 tokens
Speed
317.8 tok/s
Console errors
0
First token after
667 ms
First visible text after
667 ms
Prompt tokens
462
Code size
11.1 KB
Finish reason
stop
Served by
Amazon Bedrock
Model id
anthropic/claude-haiku-4.5
Reasoning sent
{"effort":"none"}
Max output
32,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 · 342 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;
        }

        body {
            width: 100%;
            height: 100vh;
            overflow: hidden;
            font-family: Arial, sans-serif;
            background: #1a1a1a;
        }

        #canvas {
            display: block;
            width: 100%;
            height: 100%;
        }

        #info {
            position: absolute;
            top: 20px;
            left: 20px;
            color: #fff;
            font-size: 14px;
            text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.8);
            pointer-events: none;
        }

        #info p {
            margin: 5px 0;
        }
    </style>
</head>
<body>
    <div id="info">
        <p>🐠 3D Aquarium</p>
        <p>Move your mouse to scare the fish</p>
    </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';

        let scene, camera, renderer;
        let fish = [];
        const mousePos = new THREE.Vector2(0, 0);
        const TANK_SIZE = 100;
        const FISH_COUNT = 12;
        const SCARE_DISTANCE = 25;

        function init() {
            // Scene setup
            scene = new THREE.Scene();
            scene.background = new THREE.Color(0x0a3d62);
            scene.fog = new THREE.Fog(0x0a3d62, 150, 300);

            // Camera setup
            camera = new THREE.PerspectiveCamera(
                75,
                window.innerWidth / window.innerHeight,
                0.1,
                1000
            );
            camera.position.set(0, 0, 60);

            // Renderer setup
            renderer = new THREE.WebGLRenderer({ antialias: true });
            renderer.setSize(window.innerWidth, window.innerHeight);
            renderer.setPixelRatio(window.devicePixelRatio);
            renderer.shadowMap.enabled = true;
            document.body.appendChild(renderer.domElement);

            // Lighting
            const ambientLight = new THREE.AmbientLight(0xffffff, 0.6);
            scene.add(ambientLight);

            const directionalLight = new THREE.DirectionalLight(0xffffff, 0.8);
            directionalLight.position.set(50, 50, 50);
            directionalLight.castShadow = true;
            scene.add(directionalLight);

            const pointLight = new THREE.PointLight(0x00aaff, 0.5);
            pointLight.position.set(-30, 30, 30);
            scene.add(pointLight);

            // Create tank
            createTank();

            // Create fish
            for (let i = 0; i < FISH_COUNT; i++) {
                createFish();
            }

            // Event listeners
            window.addEventListener('mousemove', onMouseMove);
            window.addEventListener('resize', onWindowResize);

            // Start animation loop
            animate();
        }

        function createTank() {
            const size = TANK_SIZE;
            const thickness = 2;

            // Tank walls material
            const wallMaterial = new THREE.MeshStandardMaterial({
                color: 0x1a5f7a,
                metalness: 0.3,
                roughness: 0.4,
                transparent: true,
                opacity: 0.3,
            });

            // Front and back walls
            const frontBack = new THREE.BoxGeometry(size, size, thickness);
            const frontWall = new THREE.Mesh(frontBack, wallMaterial);
            frontWall.position.z = size / 2;
            scene.add(frontWall);

            const backWall = new THREE.Mesh(frontBack, wallMaterial);
            backWall.position.z = -size / 2;
            scene.add(backWall);

            // Left and right walls
            const leftRight = new THREE.BoxGeometry(thickness, size, size);
            const leftWall = new THREE.Mesh(leftRight, wallMaterial);
            leftWall.position.x = -size / 2;
            scene.add(leftWall);

            const rightWall = new THREE.Mesh(leftRight, wallMaterial);
            rightWall.position.x = size / 2;
            scene.add(rightWall);

            // Bottom
            const bottom = new THREE.BoxGeometry(size, thickness, size);
            const bottomMesh = new THREE.Mesh(bottom, wallMaterial);
            bottomMesh.position.y = -size / 2;
            scene.add(bottomMesh);

            // Add bubbles for atmosphere
            for (let i = 0; i < 30; i++) {
                const bubbleGeom = new THREE.SphereGeometry(
                    Math.random() * 0.8 + 0.3,
                    8,
                    8
                );
                const bubbleMat = new THREE.MeshStandardMaterial({
                    color: 0x4dd0e1,
                    metalness: 0.8,
                    roughness: 0.2,
                    emissive: 0x1a7f8a,
                });
                const bubble = new THREE.Mesh(bubbleGeom, bubbleMat);
                bubble.position.set(
                    (Math.random() - 0.5) * size * 1.5,
                    (Math.random() - 0.5) * size * 1.5,
                    (Math.random() - 0.5) * size * 1.5
                );
                bubble.userData.floatSpeed = Math.random() * 0.3 + 0.1;
                bubble.userData.floatAmount = Math.random() * 2 + 1;
                scene.add(bubble);
            }
        }

        function createFish() {
            const fishGroup = new THREE.Group();

            // Fish body
            const bodyGeom = new THREE.ConeGeometry(1.5, 4, 8);
            const bodyMat = new THREE.MeshStandardMaterial({
                color: new THREE.Color().setHSL(Math.random(), 0.7, 0.5),
                metalness: 0.4,
                roughness: 0.5,
                emissive: new THREE.Color().setHSL(Math.random(), 0.5, 0.2),
            });
            const body = new THREE.Mesh(bodyGeom, bodyMat);
            body.castShadow = true;
            body.receiveShadow = true;
            fishGroup.add(body);

            // Fish tail
            const tailGeom = new THREE.ConeGeometry(1.2, 1.5, 6);
            const tailMat = new THREE.MeshStandardMaterial({
                color: bodyMat.color,
                metalness: 0.3,
                roughness: 0.6,
            });
            const tail = new THREE.Mesh(tailGeom, tailMat);
            tail.position.x = -2.5;
            tail.rotation.z = Math.random() * 0.5;
            tail.castShadow = true;
            fishGroup.add(tail);

            // Fish eye
            const eyeGeom = new THREE.SphereGeometry(0.3, 8, 8);
            const eyeMat = new THREE.MeshStandardMaterial({
                color: 0xffffff,
                emissive: 0xffff00,
            });
            const eye = new THREE.Mesh(eyeGeom, eyeMat);
            eye.position.set(1.8, 0.4, 1);
            fishGroup.add(eye);

            // Randomize position
            fishGroup.position.set(
                (Math.random() - 0.5) * TANK_SIZE * 0.8,
                (Math.random() - 0.5) * TANK_SIZE * 0.8,
                (Math.random() - 0.5) * TANK_SIZE * 0.8
            );

            scene.add(fishGroup);

            fish.push({
                group: fishGroup,
                velocity: new THREE.Vector3(
                    (Math.random() - 0.5) * 0.3,
                    (Math.random() - 0.5) * 0.2,
                    (Math.random() - 0.5) * 0.3
                ),
                targetVelocity: new THREE.Vector3(),
                scared: false,
                scareTimer: 0,
                tailWave: 0,
            });
        }

        function onMouseMove(event) {
            mousePos.x = (event.clientX / window.innerWidth) * 2 - 1;
            mousePos.y = -(event.clientY / window.innerHeight) * 2 + 1;
        }

        function onWindowResize() {
            camera.aspect = window.innerWidth / window.innerHeight;
            camera.updateProjectionMatrix();
            renderer.setSize(window.innerWidth, window.innerHeight);
        }

        function updateFish(f, deltaTime) {
            const mouseWorldPos = new THREE.Vector3(
                mousePos.x * 40,
                mousePos.y * 30,
                30
            );

            const distance = f.group.position.distanceTo(mouseWorldPos);

            if (distance < SCARE_DISTANCE) {
                f.scared = true;
                f.scareTimer = 2;

                const escapeDir = new THREE.Vector3()
                    .subVectors(f.group.position, mouseWorldPos)
                    .normalize();

                f.targetVelocity.copy(escapeDir).multiplyScalar(0.5);
            } else {
                f.scareTimer -= deltaTime;
                if (f.scareTimer <= 0) {
                    f.scared = false;
                }
            }

            if (!f.scared) {
                if (Math.random() < 0.01) {
                    f.targetVelocity.set(
                        (Math.random() - 0.5) * 0.2,
                        (Math.random() - 0.5) * 0.15,
                        (Math.random() - 0.5) * 0.2
                    );
                }
            }

            f.velocity.lerp(f.targetVelocity, 0.05);
            f.group.position.add(f.velocity);

            // Boundary wrapping
            const boundary = TANK_SIZE / 2 - 2;
            if (f.group.position.x > boundary) f.group.position.x = -boundary;
            if (f.group.position.x < -boundary) f.group.position.x = boundary;
            if (f.group.position.y > boundary) f.group.position.y = -boundary;
            if (f.group.position.y < -boundary) f.group.position.y = boundary;
            if (f.group.position.z > boundary) f.group.position.z = -boundary;
            if (f.group.position.z < -boundary) f.group.position.z = boundary;

            // Face direction of movement
            if (f.velocity.length() > 0.01) {
                const targetRotation = Math.atan2(f.velocity.y, f.velocity.x);
                f.group.rotation.z = targetRotation - Math.PI / 2;
                f.group.rotation.y = Math.atan2(f.velocity.z, f.velocity.x);
            }

            // Tail animation
            f.tailWave += 0.1;
            if (f.group.children[1]) {
                f.group.children[1].rotation.z = Math.sin(f.tailWave) * 0.3;
            }
        }

        function animate() {
            requestAnimationFrame(animate);

            const deltaTime = 1 / 60;

            fish.forEach((f) => updateFish(f, deltaTime));

            // Animate bubbles
            scene.children.forEach((child) => {
                if (child.userData.floatSpeed) {
                    child.position.y += child.userData.floatSpeed;
                    child.position.x += Math.sin(Date.now() * 0.001) * 0.05;

                    if (child.position.y > TANK_SIZE / 2) {
                        child.position.y = -TANK_SIZE / 2;
                    }
                }
            });

            renderer.render(scene, camera);
        }

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