Models 44

Gemma 4 31B

by Googlereasoning defaultClean
Open in new window

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

How it went

Total time
46.5 s
Cost
$0.0012
Output tokens
3,257
Spent thinking
0 tokens
Speed
71 tok/s
Console errors
0
First token after
663 ms
First visible text after
663 ms
Prompt tokens
610
Code size
10.2 KB
Finish reason
stop
Served by
CoreWeave
Model id
google/gemma-4-31b-it
Reasoning sent
model default
Max output
16,384 tokens
Generated
Nov 13, 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 · 278 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 Night</title>
    <style>
        body { margin: 0; overflow: hidden; background-color: #050508; font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; }
        canvas { display: block; }
        #ui {
            position: absolute;
            top: 20px;
            left: 20px;
            color: #ddd;
            pointer-events: none;
            text-shadow: 1px 1px 2px black;
        }
        .hint {
            position: absolute;
            bottom: 20px;
            width: 100%;
            text-align: center;
            color: rgba(255,255,255,0.6);
            font-size: 14px;
            pointer-events: none;
        }
    </style>
</head>
<body>
    <div id="ui">
        <h1 style="margin:0; font-size: 24px;">Midnight Clearing</h1>
        <p style="margin:5px 0;">Low-Poly Ambient Scene</p>
    </div>
    <div class="hint">Drag to rotate • Scroll to zoom</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';

        // --- Setup ---
        const scene = new THREE.Scene();
        scene.background = new THREE.Color(0x020205);
        scene.fog = new THREE.FogExp2(0x020205, 0.07);

        const camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 0.1, 1000);
        camera.position.set(8, 5, 8);

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

        const controls = new OrbitControls(camera, renderer.domElement);
        controls.enableDamping = true;
        controls.maxPolarAngle = Math.PI / 2.1; // Stop camera from going underground
        controls.minDistance = 4;
        controls.maxDistance = 25;

        // --- Lighting ---
        const ambientLight = new THREE.AmbientLight(0x101020, 0.5);
        scene.add(ambientLight);

        const moonLight = new THREE.DirectionalLight(0x445577, 0.3);
        moonLight.position.set(10, 20, 10);
        scene.add(moonLight);

        // Fire Light
        const fireLight = new THREE.PointLight(0xff6600, 4, 15);
        fireLight.position.set(0, 0.5, 0);
        fireLight.castShadow = true;
        fireLight.shadow.mapSize.width = 512;
        fireLight.shadow.mapSize.height = 512;
        scene.add(fireLight);

        // --- Environment ---
        
        // Ground
        const groundGeo = new THREE.PlaneGeometry(50, 50);
        const groundMat = new THREE.MeshStandardMaterial({ color: 0x1a2a1a, roughness: 0.8 });
        const ground = new THREE.Mesh(groundGeo, groundMat);
        ground.rotation.x = -Math.PI / 2;
        ground.receiveShadow = true;
        scene.add(ground);

        // Low Poly Trees
        function createTree(x, z) {
            const group = new THREE.Group();
            
            // Trunk
            const trunkGeo = new THREE.CylinderGeometry(0.2, 0.3, 1.5, 6);
            const trunkMat = new THREE.MeshStandardMaterial({ color: 0x3d2817 });
            const trunk = new THREE.Mesh(trunkGeo, trunkMat);
            trunk.position.y = 0.75;
            trunk.castShadow = true;
            trunk.receiveShadow = true;
            group.add(trunk);

            // Leaves (Conical)
            const leavesMat = new THREE.MeshStandardMaterial({ color: 0x1a3a1a, flatShading: true });
            for(let i=0; i<3; i++) {
                const leavesGeo = new THREE.ConeGeometry(1.2 - i*0.3, 1.5, 6);
                const leaves = new THREE.Mesh(leavesGeo, leavesMat);
                leaves.position.y = 1.5 + i * 0.8;
                leaves.castShadow = true;
                leaves.receiveShadow = true;
                group.add(leaves);
            }

            group.position.set(x, 0, z);
            scene.add(group);
        }

        // Distribute trees randomly, avoiding the center
        for(let i=0; i<40; i++) {
            const angle = Math.random() * Math.PI * 2;
            const dist = 6 + Math.random() * 15;
            createTree(Math.cos(angle) * dist, Math.sin(angle) * dist);
        }

        // Rocks and Logs
        function createRock(x, z) {
            const geo = new THREE.DodecahedronGeometry(0.3 + Math.random() * 0.4, 0);
            const mat = new THREE.MeshStandardMaterial({ color: 0x555555 });
            const rock = new THREE.Mesh(geo, mat);
            rock.position.set(x, 0.2, z);
            rock.rotation.set(Math.random(), Math.random(), Math.random());
            rock.castShadow = true;
            rock.receiveShadow = true;
            scene.add(rock);
        }

        function createLog(x, z) {
            const geo = new THREE.CylinderGeometry(0.15, 0.15, 1.2, 6);
            const mat = new THREE.MeshStandardMaterial({ color: 0x4b3621 });
            const log = new THREE.Mesh(geo, mat);
            log.position.set(x, 0.15, z);
            log.rotation.set(Math.random() * 0.5, Math.random() * Math.PI, Math.random() * 0.5);
            log.castShadow = true;
            log.receiveShadow = true;
            scene.add(log);
        }

        // Scatter debris around the fire
        for(let i=0; i<8; i++) {
            const angle = Math.random() * Math.PI * 2;
            const dist = 1.5 + Math.random() * 2;
            createRock(Math.cos(angle)*dist, Math.sin(angle)*dist);
            createLog(Math.cos(angle+1)*dist, Math.sin(angle+1)*dist);
        }

        // --- Campfire ---
        
        // Firewood logs in the center
        const woodGroup = new THREE.Group();
        for(let i=0; i<4; i++) {
            const log = new THREE.Mesh(
                new THREE.CylinderGeometry(0.1, 0.1, 0.8, 6),
                new THREE.MeshStandardMaterial({ color: 0x4b3621 })
            );
            log.rotation.set(0, 0, (i * Math.PI/2) + 0.5);
            log.position.y = 0.1;
            log.castShadow = true;
            woodGroup.add(log);
        }
        scene.add(woodGroup);

        // Animated Flame
        const flameGeo = new THREE.ConeGeometry(0.3, 0.8, 6);
        const flameMat = new THREE.MeshStandardMaterial({ 
            color: 0xff4400, 
            emissive: 0xff2200, 
            emissiveIntensity: 2 
        });
        const flame = new THREE.Mesh(flameGeo, flameMat);
        flame.position.y = 0.4;
        scene.add(flame);

        // Sparks Particle System
        const sparkCount = 20;
        const sparksGeo = new THREE.BufferGeometry();
        const sparksPos = new Float32Array(sparkCount * 3);
        const sparksVel = [];
        
        for(let i=0; i<sparkCount; i++) {
            sparksPos[i*3] = 0;
            sparksPos[i*3+1] = 0.5;
            sparksPos[i*3+2] = 0;
            sparksVel.push(new THREE.Vector3(
                (Math.random() - 0.5) * 0.02, 
                0.05 + Math.random() * 0.05, 
                (Math.random() - 0.5) * 0.02
            ));
        }
        sparksGeo.setAttribute('position', new THREE.BufferAttribute(sparksPos, 3));
        const sparksMat = new THREE.PointsMaterial({ color: 0xffaa00, size: 0.05 });
        const sparks = new THREE.Points(sparksGeo, sparksMat);
        scene.add(sparks);

        // --- Sky/Stars ---
        const starGeo = new THREE.BufferGeometry();
        const starPos = new Float32Array(1000 * 3);
        for(let i=0; i<1000 * 3; i++) {
            starPos[i] = (Math.random() - 0.5) * 100;
        }
        starGeo.setAttribute('position', new THREE.BufferAttribute(starPos, 3));
        const starMat = new THREE.PointsMaterial({ color: 0xffffff, size: 0.1 });
        const starField = new THREE.Points(starGeo, starMat);
        scene.add(starField);

        const moonGeo = new THREE.SphereGeometry(0.5, 8, 8);
        const moonMat = new THREE.MeshStandardMaterial({ color: 0xeeeeee, emissive: 0xaaaaaa });
        const moon = new THREE.Mesh(moonGeo, moonMat);
        moon.position.set(20, 20, -20);
        scene.add(moon);

        // --- Animation loop ---
        let time = 0;
        function animate() {
            time += 0.05;
            requestAnimationFrame(animate);

            // Flicker fire light
            fireLight.intensity = 3 + Math.sin(time * 4) * 1 + Math.random() * 0.5;
            
            // Animate flame size/tilt
            flame.scale.set(
                1 + Math.sin(time * 5) * 0.1,
                1 + Math.cos(time * 6) * 0.2,
                1 + Math.sin(time * 5) * 0.1
            );
            flame.rotation.z = Math.sin(time * 3) * 0.1;

            // Animate sparks
            const positions = sparks.geometry.attributes.position.array;
            for(let i=0; i<sparkCount; i++) {
                positions[i*3] += sparksVel[i].x;
                positions[i*3+1] += sparksVel[i].y;
                positions[i*3+2] += sparksVel[i].z;

                // Reset spark if it goes too high or falls
                if(positions[i*3+1] > 3 || Math.random() > 0.98) {
                    positions[i*3] = 0;
                    positions[i*3+1] = 0.5;
                    positions[i*3+2] = 0;
                    sparksVel[i].set(
                        (Math.random() - 0.5) * 0.02, 
                        0.05 + Math.random() * 0.05, 
                        (Math.random() - 0.5) * 0.02
                    );
                }
            }
            sparks.geometry.attributes.position.needsUpdate = true;

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

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

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