Models 44

North Mini Code (free)

by CohereReasoningClean
Open in new window

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

How it went

Total time
13.0 s
Cost
$0
Output tokens
3,889
Spent thinking
0 tokens
Speed
308.3 tok/s
Console errors
0
First token after
384 ms
First visible text after
384 ms
Prompt tokens
541
Code size
12.8 KB
Finish reason
stop
Served by
Cohere
Model id
cohere/north-mini-code:free
Reasoning sent
{"effort":"none"}
Max output
32,000 tokens
Generated
Nov 9, 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 · 380 lines

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Campfire Night Scene</title>
  <style>
    body { margin: 0; overflow: hidden; background: #000; }
    canvas { display: block; }
    #overlay {
      position: absolute;
      top: 0; left: 0; right: 0; bottom: 0;
      background: rgba(0,0,0,0.6);
      color: #fff;
      font-family: sans-serif;
      display: flex;
      align-items: center;
      justify-content: center;
      font-size: 24px;
      pointer-events: all;
      z-index: 10;
    }
  </style>
  <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>
</head>
<body>
<div id="overlay">Click or press a key to start</div>

<script type="module">
  import * as THREE from 'three';
  import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
  import { RGBELoader } from 'three/addons/loaders/RGBELoader.js';

  let scene, camera, renderer, controls;
  let fireMesh, flameGeometry, flameMaterial, flameParticles;
  let sparkGeo, sparkMat, sparks;
  let stars, moon;
  let overlays = [];

  // Initial state
  let started = false;
  const startBtn = document.getElementById('overlay');
  startBtn.addEventListener('click', start);
  window.addEventListener('keydown', (e) => { if (!started) start(); });

  function start() {
    startBtn.style.display = 'none';
    started = true;
    init();
  }

  function init() {
    scene = new THREE.Scene();
    scene.fog = new THREE.FogExp2(0x000511, 0.02);

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

    // Camera
    camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000);
    camera.position.set(0, 10, 30);
    camera.lookAt(0, 0, 0);

    // Controls
    controls = new OrbitControls(camera, renderer.domElement);
    controls.enableDamping = true;
    controls.dampingFactor = 0.05;
    controls.minDistance = 5;
    controls.maxDistance = 80;
    controls.maxPolarAngle = Math.PI / 2 - 0.1; // keep above ground

    // Lighting
    const ambientLight = new THREE.AmbientLight(0x404040, 0.6);
    scene.add(ambientLight);
    const dirLight = new THREE.DirectionalLight(0xffffff, 1);
    dirLight.position.set(10, 20, 10);
    dirLight.castShadow = true;
    dirLight.shadow.mapSize.width = 2048;
    dirLight.shadow.mapSize.height = 2048;
    scene.add(dirLight);

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

    // Low‑poly rocks and logs
    const rockMat = new THREE.MeshStandardMaterial({ color: 0x333333 });
    const logMat = new THREE.MeshStandardMaterial({ color: 0x5a3e2b });
    const mats = [rockMat, logMat];

    function makeLowPoly(points, scale, color = 0xffffff, metalness = 0, roughness = 1) {
      const shape = new THREE.Shape(points);
      const geo = new THREE.ExtrudeGeometry(shape, { depth: 0.5, bevelEnabled: false });
      const mesh = new THREE.Mesh(geo, new THREE.MeshStandardMaterial({ color, metalness, roughness }));
      mesh.scale.set(scale, scale, scale);
      mesh.castShadow = true;
      mesh.receiveShadow = true;
      return mesh;
    }

    // Place a few random rocks and logs
    for (let i = 0; i < 15; i++) {
      const radius = Math.random() * 30 + 10;
      const angle = Math.random() * Math.PI * 2;
      const x = Math.cos(angle) * radius;
      const z = Math.sin(angle) * radius;
      const y = 0.1;
      const size = Math.random() * 2 + 0.5;
      const shape = [];
      const sides = Math.floor(Math.random() * 4 + 3);
      for (let j = 0; j <= sides; j++) {
        const a = (j / sides) * Math.PI * 2;
        const r = Math.random() * 0.8 + 0.5;
        shape.push(new THREE.Vector2(Math.cos(a) * r, Math.sin(a) * r));
      }
      const mesh = makeLowPoly(shape, size, mats[i % 2].color);
      mesh.position.set(x, y, z);
      scene.add(mesh);
    }

    // Logs (cylinders approximated with low-poly extrusion)
    for (let i = 0; i < 5; i++) {
      const radius = Math.random() * 1.5 + 0.5;
      const height = Math.random() * 1.5 + 0.5;
      const geo = new THREE.CylinderGeometry(radius, radius, height, 6);
      const mesh = new THREE.Mesh(geo, logMat);
      const angle = Math.random() * Math.PI * 2;
      const r = Math.random() * 25 + 5;
      mesh.position.set(Math.cos(angle) * r, height / 2, Math.sin(angle) * r);
      mesh.rotation.y = angle;
      mesh.castShadow = true;
      scene.add(mesh);
    }

    // Trees
    const treeGeo = new THREE.IcosahedronGeometry(0.5, 1);
    const treeMat = new THREE.MeshStandardMaterial({ color: 0x006600 });
    const treeTrunkGeo = new THREE.CylinderGeometry(0.2, 0.2, 1, 8);
    const treeTrunkMat = new THREE.MeshStandardMaterial({ color: 0x3b2f1f });

    for (let i = 0; i < 30; i++) {
      const angle = Math.random() * Math.PI * 2;
      const r = Math.random() * 40 + 10;
      const x = Math.cos(angle) * r;
      const z = Math.sin(angle) * r;
      const trunk = new THREE.Mesh(treeTrunkGeo, treeTrunkMat);
      trunk.position.set(x, 0.5, z);
      scene.add(trunk);
      for (let j = 0; j < 3; j++) {
        const tree = new THREE.Mesh(treeGeo, treeMat);
        tree.position.set(x, 0.5 + j * 0.6, z);
        tree.scale.setScalar(Math.random() * 0.8 + 0.6);
        scene.add(tree);
      }
    }

    // Fire base (mesh)
    const fireBaseGeo = new THREE.CylinderGeometry(1.5, 2, 2, 8);
    const fireBaseMat = new THREE.MeshStandardMaterial({ color: 0x332211 });
    const fireBase = new THREE.Mesh(fireBaseGeo, fireBaseMat);
    fireBase.position.set(0, 0.5, 0);
    fireBase.castShadow = true;
    scene.add(fireBase);

    // Animated flame particles
    flameGeometry = new THREE.BufferGeometry();
    const flameCount = 200;
    const flamePositions = new Float32Array(flameCount * 3);
    const flameColors = new Float32Array(flameCount * 3);
    const flameSizes = new Float32Array(flameCount);
    const color1 = new THREE.Color(0xff4400);
    const color2 = new THREE.Color(0xffff00);
    for (let i = 0; i < flameCount; i++) {
      const i3 = i * 3;
      flamePositions[i3] = (Math.random() - 0.5) * 2;
      flamePositions[i3 + 1] = Math.random() * 3 + 0.5;
      flamePositions[i3 + 2] = (Math.random() - 0.5) * 2;
      const mix = Math.random();
      const c = color1.lerpColors(color1, color2, mix);
      flameColors[i3] = c.r;
      flameColors[i3 + 1] = c.g;
      flameColors[i3 + 2] = c.b;
      flameSizes[i] = Math.random() * 0.8 + 0.2;
    }
    flameGeometry.setAttribute('position', new THREE.BufferAttribute(flamePositions, 3));
    flameGeometry.setAttribute('color', new THREE.BufferAttribute(flameColors, 3));
    flameGeometry.setAttribute('size', new THREE.BufferAttribute(flameSizes, 1));

    flameMaterial = new THREE.PointsMaterial({
      size: 0.2,
      transparent: true,
      opacity: 0.9,
      blending: THREE.AdditiveBlending,
      vertexColors: true
    });

    fireMesh = new THREE.Points(flameGeometry, flameMaterial);
    fireMesh.position.set(0, 2.2, 0);
    scene.add(fireMesh);

    // Sparks particle system
    sparkGeo = new THREE.BufferGeometry();
    const sparkCount = 50;
    const sparkPos = new Float32Array(sparkCount * 3);
    const sparkCol = new Float32Array(sparkCount * 3);
    for (let i = 0; i < sparkCount; i++) {
      const i3 = i * 3;
      sparkPos[i3] = (Math.random() - 0.5) * 0.5;
      sparkPos[i3 + 1] = Math.random() * 2 + 2;
      sparkPos[i3 + 2] = (Math.random() - 0.5) * 0.5;
      sparkCol[i3] = 1;
      sparkCol[i3 + 1] = 0.8 + Math.random() * 0.2;
      sparkCol[i3 + 2] = 0;
    }
    sparkGeo.setAttribute('position', new THREE.BufferAttribute(sparkPos, 3));
    sparkGeo.setAttribute('color', new THREE.BufferAttribute(sparkCol, 3));

    sparkMat = new THREE.PointsMaterial({
      size: 0.15,
      transparent: true,
      opacity: 0.8,
      blending: THREE.AdditiveBlending,
      vertexColors: true
    });

    sparks = new THREE.Points(sparkGeo, sparkMat);
    scene.add(sparks);

    // Warm point light (flickering)
    const pointLight = new THREE.PointLight(0xff6600, 3, 30);
    pointLight.position.set(0, 3, 0);
    pointLight.castShadow = true;
    scene.add(pointLight);

    // Stars
    const starGeo = new THREE.BufferGeometry();
    const starCount = 800;
    const sPos = new Float32Array(starCount * 3);
    const sCol = new Float32Array(starCount * 3);
    for (let i = 0; i < starCount; i++) {
      const i3 = i * 3;
      sPos[i3] = (Math.random() - 0.5) * 200;
      sPos[i3 + 1] = Math.random() * 100 - 10;
      sPos[i3 + 2] = (Math.random() - 0.5) * 200;
      const bright = Math.random() * 0.5 + 0.5;
      sCol[i3] = bright;
      sCol[i3 + 1] = bright * 0.9;
      sCol[i3 + 2] = bright * 0.8;
    }
    starGeo.setAttribute('position', new THREE.BufferAttribute(sPos, 3));
    starGeo.setAttribute('color', new THREE.BufferAttribute(sCol, 3));
    const starMat = new THREE.PointsMaterial({
      size: 0.3,
      transparent: true,
      opacity: 0.8,
      vertexColors: true
    });
    stars = new THREE.Points(starGeo, starMat);
    scene.add(stars);

    // Moon (simple sprite)
    const canvas = document.createElement('canvas');
    canvas.width = 64;
    canvas.height = 64;
    const ctx = canvas.getContext('2d');
    ctx.beginPath();
    ctx.arc(32, 32, 30, 0, Math.PI * 2);
    ctx.fillStyle = '#ffeeaa';
    ctx.fill();
    const moonTex = new THREE.CanvasTexture(canvas);
    const moonMat = new THREE.SpriteMaterial({ map: moonTex, transparent: true, opacity: 0.8 });
    moon = new THREE.Sprite(moonMat);
    moon.scale.set(10, 10, 1);
    moon.position.set(40, 30, -50);
    scene.add(moon);

    // Overlays for UI (none needed after start)
    const info = document.createElement('div');
    info.style.position = 'absolute';
    info.style.bottom = '10px';
    info.style.left = '10px';
    info.style.color = '#fff';
    info.style.fontFamily = 'sans-serif';
    info.style.fontSize = '14px';
    info.innerHTML = 'WASD/Arrows to move, mouse to rotate | Scroll to zoom';
    document.body.appendChild(info);
    overlays.push(info);

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

    // Start animation loop
    animate();
  }

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

  const clock = new THREE.Clock();
  let time = 0;

  function animate() {
    requestAnimationFrame(animate);
    const delta = clock.getDelta();
    time += delta;

    // Flicker flame positions
    const positions = flameGeometry.attributes.position.array;
    const colors = flameGeometry.attributes.color.array;
    for (let i = 0; i < 200; i++) {
      const i3 = i * 3;
      // Upward sway
      positions[i3 + 1] = Math.sin(time * 3 + i) * 0.3 + 0.5 + Math.random() * 0.5;
      // Slight horizontal drift
      positions[i3] = (Math.random() - 0.5) * 2;
      positions[i3 + 2] = (Math.random() - 0.5) * 2;
      // Color variation
      const r = 1 + Math.sin(time * 5 + i) * 0.2;
      colors[i3] = Math.min(r, 1);
      colors[i3 + 1] = Math.min(r * 0.9, 1);
      colors[i3 + 2] = Math.min(r * 0.7, 1);
    }
    flameGeometry.attributes.position.needsUpdate = true;
    flameGeometry.attributes.color.needsUpdate = true;

    // Spark animation (rise and fade)
    const sparkPos = sparkGeo.attributes.position.array;
    const sparkCol = sparkGeo.attributes.color.array;
    for (let i = 0; i < 50; i++) {
      const i3 = i * 3;
      // Move up
      sparkPos[i3 + 1] += 2 * delta;
      // Fade out at top
      const y = sparkPos[i3 + 1];
      const alpha = Math.max(0, 1 - y / 10);
      sparkCol[i3] = 1 * alpha;
      sparkCol[i3 + 1] = 0.8 * alpha;
      sparkCol[i3 + 2] = 0 * alpha;
      if (y > 12) {
        // Reset spark
        sparkPos[i3] = (Math.random() - 0.5) * 0.5;
        sparkPos[i3 + 1] = Math.random() * 2 + 2;
        sparkPos[i3 + 2] = (Math.random() - 0.5) * 0.5;
        sparkCol[i3] = 1;
        sparkCol[i3 + 1] = 0.8 + Math.random() * 0.2;
        sparkCol[i3 + 2] = 0;
      }
    }
    sparkGeo.attributes.position.needsUpdate = true;
    sparkGeo.attributes.color.needsUpdate = true;

    // Moon slow rotation (around itself)
    moon.rotation.y = time * 0.05;
    moon.position.y = 30 + Math.sin(time * 0.5) * 2;

    controls.update();

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