Models 44

Mistral Small 4

by MistralReasoningClean
Open in new window

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

How it went

Total time
19.8 s
Cost
$0.0023
Output tokens
3,340
Spent thinking
0 tokens
Speed
174.3 tok/s
Console errors
0
First token after
630 ms
First visible text after
630 ms
Prompt tokens
585
Code size
10.8 KB
Finish reason
stop
Served by
Mistral
Model id
mistralai/mistral-small-2603
Reasoning sent
model default
Max output
209,715 tokens
Generated
Nov 12, 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 · 338 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>
    body { margin: 0; overflow: hidden; }
    canvas { display: block; }
    #start { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); color: white; font-family: Arial, sans-serif; background: rgba(0,0,0,0.5); padding: 10px 20px; border-radius: 5px; cursor: pointer; }
  </style>
</head>
<body>
  <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';
    import { ImprovedNoise } from 'three/addons/math/ImprovedNoise.js';

    // Scene setup
    const scene = new THREE.Scene();
    scene.fog = new THREE.Fog(0x000000, 20, 80);

    // Camera
    const camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 0.1, 200);
    camera.position.set(0, 10, 20);

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

    // Controls
    const controls = new OrbitControls(camera, renderer.domElement);
    controls.maxPolarAngle = Math.PI * 0.9;
    controls.minDistance = 5;
    controls.maxDistance = 50;
    controls.enableDamping = true;
    controls.dampingFactor = 0.05;

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

    const directionalLight = new THREE.DirectionalLight(0xffeedd, 0.3);
    directionalLight.position.set(10, 20, 10);
    directionalLight.castShadow = true;
    directionalLight.shadow.mapSize.width = 1024;
    directionalLight.shadow.mapSize.height = 1024;
    directionalLight.shadow.camera.near = 0.5;
    directionalLight.shadow.camera.far = 50;
    scene.add(directionalLight);

    // Campfire
    const fireGroup = new THREE.Group();
    scene.add(fireGroup);

    // Fire base
    const fireBaseGeometry = new THREE.ConeGeometry(1.5, 0.5, 8);
    const fireBaseMaterial = new THREE.MeshStandardMaterial({
      color: 0x3a2a1a,
      roughness: 0.8,
      metalness: 0.1
    });
    const fireBase = new THREE.Mesh(fireBaseGeometry, fireBaseMaterial);
    fireBase.position.y = 0.25;
    fireBase.castShadow = true;
    fireGroup.add(fireBase);

    // Fire flames (animated)
    const flameGeometry = new THREE.ConeGeometry(1, 2, 8);
    const flameMaterial = new THREE.MeshStandardMaterial({
      color: 0xff4500,
      emissive: 0xff4500,
      emissiveIntensity: 2,
      transparent: true,
      opacity: 0.8
    });

    const flames = [];
    for (let i = 0; i < 5; i++) {
      const flame = new THREE.Mesh(flameGeometry, flameMaterial.clone());
      flame.position.y = 1.5 + i * 0.3;
      flame.scale.y = 0.5 + i * 0.2;
      flame.castShadow = true;
      fireGroup.add(flame);
      flames.push(flame);
    }

    // Fire light (flickering)
    const fireLight = new THREE.PointLight(0xff4500, 2, 15, 2);
    fireLight.castShadow = true;
    fireGroup.add(fireLight);

    // Sparks particle system
    const sparkGeometry = new THREE.BufferGeometry();
    const sparkMaterial = new THREE.PointsMaterial({
      color: 0xffaa33,
      size: 0.1,
      transparent: true,
      opacity: 0.8,
      blending: THREE.AdditiveBlending
    });

    const sparkCount = 100;
    const positions = new Float32Array(sparkCount * 3);
    const velocities = new Float32Array(sparkCount * 3);
    const lifetimes = new Float32Array(sparkCount);
    const maxLifetime = 2;

    for (let i = 0; i < sparkCount; i++) {
      positions[i * 3] = 0;
      positions[i * 3 + 1] = 0;
      positions[i * 3 + 2] = 0;

      velocities[i * 3] = (Math.random() - 0.5) * 0.2;
      velocities[i * 3 + 1] = Math.random() * 0.3 + 0.2;
      velocities[i * 3 + 2] = (Math.random() - 0.5) * 0.2;

      lifetimes[i] = Math.random() * maxLifetime;
    }

    sparkGeometry.setAttribute('position', new THREE.BufferAttribute(positions, 3));
    sparkGeometry.setAttribute('velocity', new THREE.BufferAttribute(velocities, 3));
    sparkGeometry.setAttribute('lifetime', new THREE.BufferAttribute(lifetimes, 1));

    const sparks = new THREE.Points(sparkGeometry, sparkMaterial);
    fireGroup.add(sparks);

    // Ground
    const groundGeometry = new THREE.PlaneGeometry(100, 100, 64, 64);
    const groundMaterial = new THREE.MeshStandardMaterial({
      color: 0x2a2a1a,
      roughness: 0.9,
      metalness: 0.0
    });
    const ground = new THREE.Mesh(groundGeometry, groundMaterial);
    ground.rotation.x = -Math.PI / 2;
    ground.receiveShadow = true;
    scene.add(ground);

    // Rocks
    const rockGeometry = new THREE.DodecahedronGeometry(0.5, 0);
    const rockMaterial = new THREE.MeshStandardMaterial({
      color: 0x5a4a3a,
      roughness: 0.7
    });

    for (let i = 0; i < 5; i++) {
      const rock = new THREE.Mesh(rockGeometry, rockMaterial);
      rock.position.x = (Math.random() - 0.5) * 20;
      rock.position.z = (Math.random() - 0.5) * 20;
      rock.position.y = 0.25;
      rock.rotation.x = Math.random() * Math.PI;
      rock.rotation.y = Math.random() * Math.PI;
      rock.rotation.z = Math.random() * Math.PI;
      rock.castShadow = true;
      scene.add(rock);
    }

    // Logs
    const logGeometry = new THREE.CylinderGeometry(0.3, 0.3, 2, 8);
    const logMaterial = new THREE.MeshStandardMaterial({
      color: 0x6a4a2a,
      roughness: 0.8
    });

    for (let i = 0; i < 3; i++) {
      const log = new THREE.Mesh(logGeometry, logMaterial);
      log.position.x = (Math.random() - 0.5) * 15;
      log.position.z = (Math.random() - 0.5) * 15;
      log.position.y = 1;
      log.rotation.x = Math.random() * Math.PI;
      log.rotation.z = Math.random() * Math.PI;
      log.castShadow = true;
      scene.add(log);
    }

    // Trees (30+ low-poly trees)
    const treeGeometry = new THREE.ConeGeometry(0.3, 1.5, 8);
    const treeMaterial = new THREE.MeshStandardMaterial({
      color: 0x2a5a2a,
      roughness: 0.7
    });

    const treeTopGeometry = new THREE.ConeGeometry(0.6, 1, 8);
    const treeTopMaterial = new THREE.MeshStandardMaterial({
      color: 0x1a4a1a,
      roughness: 0.7
    });

    for (let i = 0; i < 35; i++) {
      const distance = 20 + Math.random() * 30;
      const angle = Math.random() * Math.PI * 2;
      const x = Math.cos(angle) * distance;
      const z = Math.sin(angle) * distance;

      // Skip if too close to fire
      if (Math.abs(x) < 5 && Math.abs(z) < 5) continue;

      // Tree trunk
      const trunk = new THREE.Mesh(treeGeometry, treeMaterial);
      trunk.position.set(x, 0.75, z);
      trunk.castShadow = true;
      scene.add(trunk);

      // Tree top
      const top = new THREE.Mesh(treeTopGeometry, treeTopMaterial);
      top.position.set(x, 1.75, z);
      top.castShadow = true;
      scene.add(top);
    }

    // Moon and stars
    const moonGeometry = new THREE.SphereGeometry(2, 16, 16);
    const moonMaterial = new THREE.MeshStandardMaterial({
      color: 0xffffcc,
      emissive: 0xffffcc,
      emissiveIntensity: 0.5
    });
    const moon = new THREE.Mesh(moonGeometry, moonMaterial);
    moon.position.set(30, 40, -50);
    scene.add(moon);

    // Stars
    const starGeometry = new THREE.BufferGeometry();
    const starMaterial = new THREE.PointsMaterial({
      color: 0xffffff,
      size: 0.1,
      transparent: true
    });

    const starCount = 500;
    const starPositions = new Float32Array(starCount * 3);

    for (let i = 0; i < starCount; i++) {
      starPositions[i * 3] = (Math.random() - 0.5) * 100;
      starPositions[i * 3 + 1] = Math.random() * 50 + 20;
      starPositions[i * 3 + 2] = (Math.random() - 0.5) * 100;
    }

    starGeometry.setAttribute('position', new THREE.BufferAttribute(starPositions, 3));
    const stars = new THREE.Points(starGeometry, starMaterial);
    scene.add(stars);

    // Animation
    let clock = new THREE.Clock();
    let startTime = null;

    function animate() {
      requestAnimationFrame(animate);

      const delta = clock.getDelta();
      const time = clock.getElapsedTime();

      if (startTime === null) {
        startTime = time;
      }

      // Animate flames
      flames.forEach((flame, i) => {
        flame.position.y = 1.5 + Math.sin(time * 2 + i) * 0.2;
        flame.scale.y = 0.5 + i * 0.2 + Math.sin(time * 1.5 + i) * 0.1;
        flame.material.opacity = 0.6 + Math.sin(time * 2 + i) * 0.2;
      });

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

      // Update sparks
      const positions = sparkGeometry.attributes.position.array;
      const velocities = sparkGeometry.attributes.velocity.array;
      const lifetimes = sparkGeometry.attributes.lifetime.array;

      for (let i = 0; i < sparkCount; i++) {
        if (lifetimes[i] > 0) {
          // Update position
          positions[i * 3] += velocities[i * 3];
          positions[i * 3 + 1] += velocities[i * 3 + 1];
          positions[i * 3 + 2] += velocities[i * 3 + 2];

          // Update velocity (gravity)
          velocities[i * 3 + 1] -= 0.01;

          // Update lifetime
          lifetimes[i] -= delta;

          // Reset if lifetime expired
          if (lifetimes[i] <= 0) {
            positions[i * 3] = 0;
            positions[i * 3 + 1] = 0;
            positions[i * 3 + 2] = 0;
            velocities[i * 3] = (Math.random() - 0.5) * 0.2;
            velocities[i * 3 + 1] = Math.random() * 0.3 + 0.2;
            velocities[i * 3 + 2] = (Math.random() - 0.5) * 0.2;
            lifetimes[i] = Math.random() * maxLifetime;
          }
        }
      }

      sparkGeometry.attributes.position.needsUpdate = true;
      sparkGeometry.attributes.lifetime.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);
    });

    // Start animation on click/key
    document.getElementById('start').addEventListener('click', () => {
      document.getElementById('start').style.display = 'none';
      animate();
    });

    document.addEventListener('keydown', () => {
      if (startTime === null) {
        document.getElementById('start').style.display = 'none';
        animate();
      }
    });

    // Initial render
    renderer.render(scene, camera);
  </script>
</body>
</html>