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
13.6 s
Cost
$0.021
Output tokens
4,119
Spent thinking
0 tokens
Speed
321 tok/s
Console errors
0
First token after
724 ms
First visible text after
724 ms
Prompt tokens
614
Code size
12.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
Build a low-poly 3D scene of a campfire in a forest clearing at night, with Three.js in a single HTML file. Load Three.js only through this import map (do not use any other URL or version): <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> Requirements: - A ground with a few low-poly rocks and logs around a campfire in the center. - At least 30 low-poly trees placed randomly around the clearing (not on the fire). - The campfire has animated flames and a warm point light that flickers and casts shadows. - Sparks rising from the fire as a simple particle system. - A dark night sky with stars and a moon, plus fog that fades the distant trees. - OrbitControls to look around, with limits so the camera stays above the ground. - The renderer fills the window and handles resizing correctly.
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 · 322 lines

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Low-Poly Campfire Scene</title>
    <style>
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
        }
        body {
            width: 100%;
            height: 100vh;
            overflow: hidden;
            background: #000;
            font-family: Arial, sans-serif;
        }
        canvas {
            display: block;
            width: 100%;
            height: 100%;
        }
        #info {
            position: absolute;
            top: 20px;
            left: 20px;
            color: #fff;
            font-size: 14px;
            background: rgba(0, 0, 0, 0.7);
            padding: 15px;
            border-radius: 8px;
            max-width: 300px;
            z-index: 10;
        }
    </style>
</head>
<body>
    <div id="info">
        <strong>Low-Poly Campfire Scene</strong><br>
        Use mouse to rotate view<br>
        Scroll to zoom in/out
    </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 setup
        const scene = new THREE.Scene();
        scene.background = new THREE.Color(0x0a0a1a);
        scene.fog = new THREE.Fog(0x0a0a1a, 80, 150);

        const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
        camera.position.set(30, 20, 30);

        const renderer = new THREE.WebGLRenderer({ antialias: true });
        renderer.setSize(window.innerWidth, window.innerHeight);
        renderer.shadowMap.enabled = true;
        renderer.shadowMap.type = THREE.PCFShadowShadowMap;
        document.body.appendChild(renderer.domElement);

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

        // Flickering campfire light
        const fireLight = new THREE.PointLight(0xff6600, 1.5, 50);
        fireLight.position.set(0, 3, 0);
        fireLight.castShadow = true;
        fireLight.shadow.mapSize.width = 2048;
        fireLight.shadow.mapSize.height = 2048;
        fireLight.shadow.camera.near = 0.5;
        fireLight.shadow.camera.far = 100;
        scene.add(fireLight);

        // Moon
        const moonGeometry = new THREE.SphereGeometry(20, 32, 32);
        const moonMaterial = new THREE.MeshBasicMaterial({ color: 0xeeeeee });
        const moon = new THREE.Mesh(moonGeometry, moonMaterial);
        moon.position.set(-100, 80, -100);
        scene.add(moon);

        // Stars
        const starsGeometry = new THREE.BufferGeometry();
        const starsMaterial = new THREE.PointsMaterial({ color: 0xffffff, size: 0.5 });
        const starsVertices = [];
        for (let i = 0; i < 200; i++) {
            const x = (Math.random() - 0.5) * 400;
            const y = Math.random() * 150 + 50;
            const z = (Math.random() - 0.5) * 400;
            starsVertices.push(x, y, z);
        }
        starsGeometry.setAttribute('position', new THREE.BufferAttribute(new Float32Array(starsVertices), 3));
        const stars = new THREE.Points(starsGeometry, starsMaterial);
        scene.add(stars);

        // Ground
        const groundGeometry = new THREE.PlaneGeometry(200, 200);
        const groundMaterial = new THREE.MeshLambertMaterial({ color: 0x2a3a2a });
        const ground = new THREE.Mesh(groundGeometry, groundMaterial);
        ground.rotation.x = -Math.PI / 2;
        ground.receiveShadow = true;
        scene.add(ground);

        // Helper function to create low-poly trees
        function createLowPolyTree(x, z) {
            const trunkGeometry = new THREE.ConeGeometry(1.5, 12, 4);
            const trunkMaterial = new THREE.MeshLambertMaterial({ color: 0x4a3728 });
            const trunk = new THREE.Mesh(trunkGeometry, trunkMaterial);
            trunk.position.set(x, 6, z);
            trunk.castShadow = true;
            trunk.receiveShadow = true;

            const foliageGeometry = new THREE.ConeGeometry(8, 20, 6);
            const foliageMaterial = new THREE.MeshLambertMaterial({ color: 0x1a3a1a });
            const foliage = new THREE.Mesh(foliageGeometry, foliageMaterial);
            foliage.position.set(x, 18, z);
            foliage.castShadow = true;
            foliage.receiveShadow = true;

            const group = new THREE.Group();
            group.add(trunk);
            group.add(foliage);
            return group;
        }

        // Plant trees around the clearing (avoid center)
        for (let i = 0; i < 35; i++) {
            let x, z, distance;
            do {
                x = (Math.random() - 0.5) * 200;
                z = (Math.random() - 0.5) * 200;
                distance = Math.sqrt(x * x + z * z);
            } while (distance < 25); // Keep clear around campfire

            const tree = createLowPolyTree(x, z);
            scene.add(tree);
        }

        // Low-poly rocks around campfire
        function createRock(x, z, scale = 1) {
            const rockGeometry = new THREE.DodecahedronGeometry(2 * scale, 0);
            const rockMaterial = new THREE.MeshLambertMaterial({ color: 0x5a5a5a });
            const rock = new THREE.Mesh(rockGeometry, rockMaterial);
            rock.position.set(x, 2 * scale, z);
            rock.rotation.x = Math.random() * Math.PI;
            rock.rotation.z = Math.random() * Math.PI;
            rock.castShadow = true;
            rock.receiveShadow = true;
            return rock;
        }

        scene.add(createRock(-5, -8, 1.2));
        scene.add(createRock(8, -5, 0.9));
        scene.add(createRock(6, 6, 1.1));
        scene.add(createRock(-7, 5, 0.8));

        // Logs
        function createLog(x, z, rotation = 0) {
            const logGeometry = new THREE.CylinderGeometry(1, 1, 12, 6);
            const logMaterial = new THREE.MeshLambertMaterial({ color: 0x3a2818 });
            const log = new THREE.Mesh(logGeometry, logMaterial);
            log.position.set(x, 1, z);
            log.rotation.z = rotation;
            log.castShadow = true;
            log.receiveShadow = true;
            return log;
        }

        scene.add(createLog(-8, 0, 0.3));
        scene.add(createLog(8, 0, -0.3));
        scene.add(createLog(0, -8, Math.PI / 2));

        // Campfire - wooden base and logs
        const fireGroupGeometry = new THREE.TetrahedronGeometry(0.5, 1);
        const fireGroupMaterial = new THREE.MeshLambertMaterial({ color: 0x8b4513 });

        const fireGroup = new THREE.Group();
        fireGroup.position.y = 0.2;

        // Center fireplace with low-poly logs
        for (let i = 0; i < 4; i++) {
            const angle = (i / 4) * Math.PI * 2;
            const campLogGeometry = new THREE.CylinderGeometry(0.5, 0.5, 6, 4);
            const campLogMaterial = new THREE.MeshLambertMaterial({ color: 0x5a3a2a });
            const campLog = new THREE.Mesh(campLogGeometry, campLogMaterial);
            campLog.position.x = Math.cos(angle) * 2.5;
            campLog.position.z = Math.sin(angle) * 2.5;
            campLog.rotation.z = 0.5;
            campLog.castShadow = true;
            campLog.receiveShadow = true;
            fireGroup.add(campLog);
        }
        scene.add(fireGroup);

        // Flames (animated)
        const flameGroup = new THREE.Group();
        flameGroup.position.set(0, 3, 0);

        function createFlame(offsetX = 0, offsetZ = 0, scale = 1) {
            const flameGeometry = new THREE.ConeGeometry(1.5 * scale, 5 * scale, 4);
            const flameMaterial = new THREE.MeshBasicMaterial({ color: 0xff6633 });
            const flame = new THREE.Mesh(flameGeometry, flameMaterial);
            flame.position.set(offsetX, 0, offsetZ);
            flame.scale.y = 0.8;
            return flame;
        }

        const flame1 = createFlame(0, 0, 0.8);
        const flame2 = createFlame(1, 0.5, 0.6);
        const flame3 = createFlame(-1, -0.5, 0.7);
        flameGroup.add(flame1);
        flameGroup.add(flame2);
        flameGroup.add(flame3);
        scene.add(flameGroup);

        // Particle system for sparks
        const particlesGeometry = new THREE.BufferGeometry();
        const particleCount = 150;
        const positionArray = new Float32Array(particleCount * 3);
        const velocityArray = new Float32Array(particleCount * 3);

        for (let i = 0; i < particleCount * 3; i += 3) {
            positionArray[i] = (Math.random() - 0.5) * 2;
            positionArray[i + 1] = Math.random() * 2;
            positionArray[i + 2] = (Math.random() - 0.5) * 2;

            velocityArray[i] = (Math.random() - 0.5) * 0.1;
            velocityArray[i + 1] = Math.random() * 0.15 + 0.05;
            velocityArray[i + 2] = (Math.random() - 0.5) * 0.1;
        }

        particlesGeometry.setAttribute('position', new THREE.BufferAttribute(positionArray, 3));
        const particlesMaterial = new THREE.PointsMaterial({
            color: 0xffaa33,
            size: 0.15,
            sizeAttenuation: true
        });
        const particles = new THREE.Points(particlesGeometry, particlesMaterial);
        particles.position.y = 3;
        scene.add(particles);

        // OrbitControls
        const controls = new OrbitControls(camera, renderer.domElement);
        controls.target.set(0, 5, 0);
        controls.minDistance = 15;
        controls.maxDistance = 100;
        controls.maxPolarAngle = Math.PI * 0.9;
        controls.minPolarAngle = Math.PI * 0.1;
        controls.autoRotate = false;
        controls.update();

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

        function animate() {
            requestAnimationFrame(animate);

            const elapsedTime = clock.getElapsedTime();

            // Animate flames
            flame1.scale.y = 0.8 + Math.sin(elapsedTime * 3) * 0.2;
            flame1.position.y = Math.sin(elapsedTime * 2.5) * 0.3;

            flame2.scale.y = 0.6 + Math.sin(elapsedTime * 3.5 + 1) * 0.15;
            flame2.position.y = Math.cos(elapsedTime * 2.8 + 0.5) * 0.2;

            flame3.scale.y = 0.7 + Math.sin(elapsedTime * 3.2 + 2) * 0.18;
            flame3.position.y = Math.cos(elapsedTime * 2.3 + 1) * 0.25;

            // Flicker fire light
            fireLight.intensity = 1.5 + Math.sin(elapsedTime * 2) * 0.3 + Math.sin(elapsedTime * 5) * 0.2;
            fireLight.color.setHSL(0.05, 1, 0.5 + Math.sin(elapsedTime * 2) * 0.1);

            // Animate particles
            const positions = particles.geometry.attributes.position.array;
            for (let i = 0; i < particleCount; i++) {
                const i3 = i * 3;

                positions[i3] += velocityArray[i3];
                positions[i3 + 1] += velocityArray[i3 + 1];
                positions[i3 + 2] += velocityArray[i3 + 2];

                // Gravity and air resistance
                velocityArray[i3] *= 0.98;
                velocityArray[i3 + 1] -= 0.002;
                velocityArray[i3 + 2] *= 0.98;

                // Reset particles that go too high
                if (positions[i3 + 1] > 10) {
                    positions[i3] = (Math.random() - 0.5) * 2;
                    positions[i3 + 1] = 0;
                    positions[i3 + 2] = (Math.random() - 0.5) * 2;

                    velocityArray[i3] = (Math.random() - 0.5) * 0.1;
                    velocityArray[i3 + 1] = Math.random() * 0.15 + 0.05;
                    velocityArray[i3 + 2] = (Math.random() - 0.5) * 0.1;
                }
            }
            particles.geometry.attributes.position.needsUpdate = true;

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

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

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