Models 44

MiniMax M3

by MiniMaxreasoning defaultClean
Open in new window

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

How it went

Total time
22.4 s
Cost
$0.0054
Output tokens
5,461
Spent thinking
0 tokens
Speed
260.9 tok/s
Console errors
0
First token after
1.5 s
First visible text after
1.5 s
Prompt tokens
719
Code size
17.4 KB
Finish reason
stop
Served by
GMICloud
Model id
minimax/minimax-m3
Reasoning sent
model default
Max output
512,000 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 · 512 lines

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <title>Moonlit Campfire</title>
  <style>
    * { box-sizing: border-box; }
    html, body {
      width: 100%;
      height: 100%;
      margin: 0;
      overflow: hidden;
      background: #050914;
      color: #fff;
      font-family: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
    }
    canvas { display: block; width: 100%; height: 100%; }
    #vignette {
      position: fixed;
      inset: 0;
      pointer-events: none;
      background: radial-gradient(circle at center, transparent 42%, rgba(1, 4, 14, .48) 100%);
      z-index: 2;
    }
    #hud {
      position: fixed;
      left: 18px;
      bottom: 16px;
      z-index: 3;
      padding: 10px 13px;
      border: 1px solid rgba(255, 211, 130, .24);
      border-radius: 10px;
      background: rgba(5, 10, 20, .58);
      backdrop-filter: blur(8px);
      box-shadow: 0 8px 30px rgba(0,0,0,.3);
      color: #f4dfb6;
      font-size: 12px;
      letter-spacing: .04em;
      pointer-events: none;
      user-select: none;
    }
    #hud strong {
      display: block;
      color: #fff3d3;
      font-size: 14px;
      margin-bottom: 3px;
      letter-spacing: .08em;
    }
    #hint {
      position: fixed;
      right: 18px;
      bottom: 16px;
      z-index: 3;
      color: rgba(224, 235, 255, .62);
      font-size: 11px;
      pointer-events: none;
      user-select: none;
    }
    @media (max-width: 600px) {
      #hud { left: 10px; bottom: 10px; padding: 8px 10px; }
      #hud strong { font-size: 12px; }
      #hint { display: none; }
    }
  </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="vignette"></div>
  <div id="hud"><strong>MOONLIT CLEARING</strong>Drag to orbit · Scroll to zoom</div>
  <div id="hint">A quiet night beneath the pines</div>

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

    const scene = new THREE.Scene();
    scene.background = new THREE.Color(0x050914);
    scene.fog = new THREE.FogExp2(0x081120, 0.019);

    const camera = new THREE.PerspectiveCamera(48, innerWidth / innerHeight, 0.1, 220);
    camera.position.set(11, 7.5, 14);

    const renderer = new THREE.WebGLRenderer({ antialias: true, powerPreference: 'high-performance' });
    renderer.setSize(innerWidth, innerHeight);
    renderer.setPixelRatio(Math.min(devicePixelRatio, 2));
    renderer.shadowMap.enabled = true;
    renderer.shadowMap.type = THREE.PCFSoftShadowMap;
    renderer.outputColorSpace = THREE.SRGBColorSpace;
    renderer.toneMapping = THREE.ACESFilmicToneMapping;
    renderer.toneMappingExposure = 1.18;
    document.body.appendChild(renderer.domElement);

    const controls = new OrbitControls(camera, renderer.domElement);
    controls.target.set(0, 1.1, 0);
    controls.enableDamping = true;
    controls.dampingFactor = 0.055;
    controls.minDistance = 6;
    controls.maxDistance = 27;
    controls.minPolarAngle = 0.35;
    controls.maxPolarAngle = Math.PI * 0.46;
    controls.enablePan = false;

    const hemi = new THREE.HemisphereLight(0x7186b4, 0x10100c, 0.52);
    scene.add(hemi);

    const moonLight = new THREE.DirectionalLight(0x9ebaff, 1.35);
    moonLight.position.set(-18, 25, -15);
    moonLight.castShadow = true;
    moonLight.shadow.mapSize.set(2048, 2048);
    moonLight.shadow.camera.left = -35;
    moonLight.shadow.camera.right = 35;
    moonLight.shadow.camera.top = 35;
    moonLight.shadow.camera.bottom = -35;
    moonLight.shadow.camera.near = 1;
    moonLight.shadow.camera.far = 75;
    moonLight.shadow.bias = -0.0008;
    scene.add(moonLight);

    const fireLight = new THREE.PointLight(0xff7a18, 28, 19, 1.65);
    fireLight.position.set(0, 2.2, 0);
    fireLight.castShadow = true;
    fireLight.shadow.mapSize.set(1024, 1024);
    fireLight.shadow.camera.near = 0.2;
    fireLight.shadow.camera.far = 22;
    fireLight.shadow.bias = -0.003;
    scene.add(fireLight);

    const fireFill = new THREE.PointLight(0xffb044, 9, 8, 2);
    fireFill.position.set(0, 0.7, 0);
    scene.add(fireFill);

    const groundGeo = new THREE.CircleGeometry(70, 64);
    groundGeo.rotateX(-Math.PI / 2);
    const groundMat = new THREE.MeshStandardMaterial({
      color: 0x17251c,
      roughness: 0.96,
      metalness: 0,
      flatShading: true
    });
    const ground = new THREE.Mesh(groundGeo, groundMat);
    ground.receiveShadow = true;
    scene.add(ground);

    const clearingGeo = new THREE.CircleGeometry(7.2, 40);
    clearingGeo.rotateX(-Math.PI / 2);
    const clearing = new THREE.Mesh(
      clearingGeo,
      new THREE.MeshStandardMaterial({ color: 0x3a3020, roughness: 1, flatShading: true })
    );
    clearing.position.y = 0.012;
    clearing.receiveShadow = true;
    scene.add(clearing);

    const rng = (() => {
      let seed = 73921;
      return () => {
        seed = (seed * 1664525 + 1013904223) >>> 0;
        return seed / 4294967296;
      };
    })();

    function material(color, extra = {}) {
      return new THREE.MeshStandardMaterial({
        color,
        roughness: 0.92,
        flatShading: true,
        ...extra
      });
    }

    const rockMaterials = [
      material(0x555d62), material(0x444c52), material(0x646967), material(0x394249)
    ];
    const woodMaterials = [material(0x4b3020), material(0x5a3924), material(0x39271d)];

    function createRock(x, z, scale, y = 0) {
      const geo = new THREE.IcosahedronGeometry(1, 0);
      const pos = geo.attributes.position;
      for (let i = 0; i < pos.count; i++) {
        const vx = pos.getX(i), vy = pos.getY(i), vz = pos.getZ(i);
        const n = 0.82 + rng() * 0.32;
        pos.setXYZ(i, vx * n, vy * n * 0.72, vz * n);
      }
      geo.computeVertexNormals();
      const rock = new THREE.Mesh(geo, rockMaterials[Math.floor(rng() * rockMaterials.length)]);
      rock.position.set(x, y + scale * 0.42, z);
      rock.scale.set(scale * (0.9 + rng() * .3), scale, scale * (0.75 + rng() * .45));
      rock.rotation.set(rng(), rng() * Math.PI, rng() * .5);
      rock.castShadow = true;
      rock.receiveShadow = true;
      scene.add(rock);
    }

    for (let i = 0; i < 15; i++) {
      const a = rng() * Math.PI * 2;
      const r = 3.7 + rng() * 6.8;
      createRock(Math.cos(a) * r, Math.sin(a) * r, 0.28 + rng() * 0.72);
    }

    function cylinderBetween(a, b, radius, mat, radialSegments = 6) {
      const delta = new THREE.Vector3().subVectors(b, a);
      const length = delta.length();
      const geo = new THREE.CylinderGeometry(radius, radius * 1.08, length, radialSegments);
      const mesh = new THREE.Mesh(geo, mat);
      mesh.position.copy(a).add(b).multiplyScalar(0.5);
      mesh.quaternion.setFromUnitVectors(new THREE.Vector3(0, 1, 0), delta.normalize());
      mesh.castShadow = true;
      mesh.receiveShadow = true;
      return mesh;
    }

    const logGroup = new THREE.Group();
    const logEnds = [];
    const logSpecs = [
      [[-1.45, .55, -.15], [1.35, .75, .4]],
      [[-1.15, .78, .55], [1.45, .5, -.5]],
      [[-.9, .98, .1], [.8, .9, .95]]
    ];
    for (const spec of logSpecs) {
      const a = new THREE.Vector3(...spec[0]);
      const b = new THREE.Vector3(...spec[1]);
      const log = cylinderBetween(a, b, .28, woodMaterials[Math.floor(rng() * woodMaterials.length)], 7);
      logGroup.add(log);
      const capGeo = new THREE.CircleGeometry(.27, 7);
      for (const [point, normalSign] of [[a, -1], [b, 1]]) {
        const cap = new THREE.Mesh(capGeo, material(0x8b5730));
        cap.position.copy(point);
        const direction = new THREE.Vector3().subVectors(b, a).normalize().multiplyScalar(normalSign);
        cap.quaternion.setFromUnitVectors(new THREE.Vector3(0, 0, 1), direction);
        cap.castShadow = true;
        logGroup.add(cap);
      }
    }
    scene.add(logGroup);

    for (let i = 0; i < 8; i++) {
      const a = rng() * Math.PI * 2;
      const r = 2.6 + rng() * 4.4;
      const length = .6 + rng() * 1.2;
      const b = new THREE.Vector3(Math.cos(a) * r, .25 + rng() * .1, Math.sin(a) * r);
      const end = b.clone().add(new THREE.Vector3((rng() - .5) * length, rng() * .18, (rng() - .5) * length));
      const stick = cylinderBetween(b, end, .1 + rng() * .08, woodMaterials[i % 3], 5);
      scene.add(stick);
    }

    const treeCount = 42;
    const trunkMat = material(0x38271d);
    const foliageMats = [
      material(0x102d23), material(0x15372a), material(0x1a3b2c), material(0x0d2922)
    ];

    function createTree(x, z, scale) {
      const tree = new THREE.Group();
      const height = (5.5 + rng() * 4.5) * scale;
      const trunkGeo = new THREE.CylinderGeometry(.18 * scale, .34 * scale, height * .72, 6);
      const trunk = new THREE.Mesh(trunkGeo, trunkMat);
      trunk.position.y = height * .36;
      trunk.rotation.y = rng() * Math.PI;
      trunk.castShadow = true;
      trunk.receiveShadow = true;
      tree.add(trunk);

      const layers = 3 + Math.floor(rng() * 2);
      for (let j = 0; j < layers; j++) {
        const y = height * (.43 + j * .14);
        const radius = (2.05 - j * .28) * scale;
        const coneGeo = new THREE.ConeGeometry(radius, height * .36, 7, 1);
        const cone = new THREE.Mesh(coneGeo, foliageMats[Math.floor(rng() * foliageMats.length)]);
        cone.position.y = y;
        cone.rotation.y = rng() * Math.PI;
        cone.castShadow = true;
        cone.receiveShadow = true;
        tree.add(cone);
      }
      tree.position.set(x, 0, z);
      tree.rotation.y = rng() * Math.PI * 2;
      scene.add(tree);
    }

    let placed = 0;
    while (placed < treeCount) {
      const a = rng() * Math.PI * 2;
      const r = 9.5 + rng() * 43;
      const x = Math.cos(a) * r;
      const z = Math.sin(a) * r;
      if (Math.hypot(x, z) < 8.5) continue;
      createTree(x, z, .65 + rng() * .85);
      placed++;
    }

    const stoneRing = new THREE.Group();
    const stoneGeo = new THREE.DodecahedronGeometry(.42, 0);
    for (let i = 0; i < 12; i++) {
      const a = i / 12 * Math.PI * 2;
      const stone = new THREE.Mesh(stoneGeo, rockMaterials[i % rockMaterials.length]);
      stone.position.set(Math.cos(a) * 1.75, .28, Math.sin(a) * 1.75);
      stone.scale.set(.9, .65 + rng() * .25, .8);
      stone.rotation.set(rng(), rng(), rng());
      stone.castShadow = true;
      stone.receiveShadow = true;
      stoneRing.add(stone);
    }
    scene.add(stoneRing);

    const emberGeo = new THREE.IcosahedronGeometry(.07, 0);
    const emberMat = new THREE.MeshBasicMaterial({ color: 0xff5a0a });
    const embers = [];
    for (let i = 0; i < 22; i++) {
      const ember = new THREE.Mesh(emberGeo, emberMat);
      ember.position.set((rng() - .5) * 1.4, .5 + rng() * .4, (rng() - .5) * 1.4);
      ember.userData = {
        speed: .6 + rng() * 1.25,
        drift: (rng() - .5) * .4,
        phase: rng() * Math.PI * 2
      };
      embers.push(ember);
      scene.add(ember);
    }

    const flameGroup = new THREE.Group();
    const flameMat = new THREE.MeshBasicMaterial({
      color: 0xff6b00,
      transparent: true,
      opacity: .88,
      depthWrite: false,
      side: THREE.DoubleSide
    });
    const coreMat = new THREE.MeshBasicMaterial({
      color: 0xffe06a,
      transparent: true,
      opacity: .94,
      depthWrite: false,
      side: THREE.DoubleSide
    });
    const flameGeo = new THREE.ConeGeometry(.65, 2.6, 5, 1);
    const coreGeo = new THREE.ConeGeometry(.34, 1.75, 5, 1);
    const flames = [];
    for (let i = 0; i < 7; i++) {
      const flame = new THREE.Mesh(flameGeo, flameMat.clone());
      const core = new THREE.Mesh(coreGeo, coreMat.clone());
      flame.add(core);
      core.position.y = -.22;
      const angle = i / 7 * Math.PI * 2;
      flame.position.set(Math.cos(angle) * .28, 1.25, Math.sin(angle) * .28);
      flame.userData = {
        baseX: flame.position.x,
        baseZ: flame.position.z,
        phase: rng() * Math.PI * 2,
        speed: .9 + rng() * .6
      };
      flames.push(flame);
      flameGroup.add(flame);
    }
    scene.add(flameGroup);

    const sparkCount = 130;
    const sparkPositions = new Float32Array(sparkCount * 3);
    const sparkColors = new Float32Array(sparkCount * 3);
    const sparkData = [];
    for (let i = 0; i < sparkCount; i++) {
      sparkData.push({
        x: (rng() - .5) * 1.1,
        z: (rng() - .5) * 1.1,
        y: .6 + rng() * 4.8,
        speed: .55 + rng() * 1.4,
        life: rng(),
        phase: rng() * Math.PI * 2
      });
      const c = new THREE.Color().setHSL(.02 + rng() * .11, 1, .55 + rng() * .25);
      sparkColors[i * 3] = c.r;
      sparkColors[i * 3 + 1] = c.g;
      sparkColors[i * 3 + 2] = c.b;
    }
    const sparkGeo = new THREE.BufferGeometry();
    sparkGeo.setAttribute('position', new THREE.BufferAttribute(sparkPositions, 3));
    sparkGeo.setAttribute('color', new THREE.BufferAttribute(sparkColors, 3));
    const sparkMat = new THREE.PointsMaterial({
      size: .095,
      vertexColors: true,
      transparent: true,
      opacity: .95,
      depthWrite: false,
      blending: THREE.AdditiveBlending,
      sizeAttenuation: true
    });
    const sparks = new THREE.Points(sparkGeo, sparkMat);
    scene.add(sparks);

    const starCount = 850;
    const starPositions = new Float32Array(starCount * 3);
    const starColors = new Float32Array(starCount * 3);
    for (let i = 0; i < starCount; i++) {
      const theta = rng() * Math.PI * 2;
      const y = 18 + rng() * 80;
      const radius = 95 + rng() * 25;
      starPositions[i * 3] = Math.cos(theta) * radius;
      starPositions[i * 3 + 1] = y;
      starPositions[i * 3 + 2] = Math.sin(theta) * radius;
      const tint = rng();
      starColors[i * 3] = .75 + tint * .25;
      starColors[i * 3 + 1] = .8 + tint * .2;
      starColors[i * 3 + 2] = 1;
    }
    const starGeo = new THREE.BufferGeometry();
    starGeo.setAttribute('position', new THREE.BufferAttribute(starPositions, 3));
    starGeo.setAttribute('color', new THREE.BufferAttribute(starColors, 3));
    const starField = new THREE.Points(
      starGeo,
      new THREE.PointsMaterial({
        size: .34,
        vertexColors: true,
        transparent: true,
        opacity: .9,
        sizeAttenuation: true,
        fog: false
      })
    );
    scene.add(starField);

    const moon = new THREE.Mesh(
      new THREE.SphereGeometry(3.6, 16, 12),
      new THREE.MeshBasicMaterial({ color: 0xe9f1ff, fog: false })
    );
    moon.position.set(-28, 31, -45);
    scene.add(moon);

    const moonHalo = new THREE.Sprite(
      new THREE.SpriteMaterial({
        color: 0xa9c5ff,
        transparent: true,
        opacity: .18,
        depthWrite: false,
        blending: THREE.AdditiveBlending,
        fog: false
      })
    );
    moonHalo.position.copy(moon.position);
    moonHalo.scale.set(13, 13, 1);
    scene.add(moonHalo);

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

    function animate() {
      requestAnimationFrame(animate);
      const dt = Math.min(clock.getDelta(), .04);
      elapsed += dt;

      for (const flame of flames) {
        const d = flame.userData;
        const flicker = Math.sin(elapsed * d.speed * 7 + d.phase) * .5 + Math.sin(elapsed * 11 + d.phase) * .22;
        flame.scale.set(
          .82 + flicker * .14,
          .86 + Math.abs(flicker) * .3 + Math.sin(elapsed * 5 + d.phase) * .1,
          .82 - flicker * .13
        );
        flame.position.x = d.baseX + Math.sin(elapsed * 2.7 + d.phase) * .12;
        flame.position.z = d.baseZ + Math.cos(elapsed * 2.2 + d.phase) * .1;
        flame.rotation.y += dt * (.25 + d.speed * .12);
      }

      const pulse = .82 + Math.sin(elapsed * 8.4) * .1 + Math.sin(elapsed * 13.1) * .07;
      fireLight.intensity = 27 * pulse;
      fireLight.position.y = 2.15 + Math.sin(elapsed * 7) * .12;
      fireFill.intensity = 8.5 * pulse;

      for (const ember of embers) {
        const d = ember.userData;
        ember.position.y += dt * d.speed;
        ember.position.x += Math.sin(elapsed * 1.8 + d.phase) * dt * d.drift;
        ember.position.z += Math.cos(elapsed * 1.5 + d.phase) * dt * d.drift;
        ember.scale.setScalar(Math.max(.1, 1 - (ember.position.y - .5) / 4));
        if (ember.position.y > 4.8) {
          ember.position.set((rng() - .5) * 1.2, .5, (rng() - .5) * 1.2);
        }
      }

      for (let i = 0; i < sparkCount; i++) {
        const d = sparkData[i];
        d.y += dt * d.speed;
        d.life += dt * (.18 + d.speed * .05);
        if (d.life > 1 || d.y > 7) {
          d.life = 0;
          d.y = .65 + Math.random() * .35;
          d.x = (Math.random() - .5) * .9;
          d.z = (Math.random() - .5) * .9;
          d.speed = .55 + Math.random() * 1.45;
        }
        sparkPositions[i * 3] = d.x + Math.sin(elapsed * 1.3 + d.phase) * (.12 + d.life * .3);
        sparkPositions[i * 3 + 1] = d.y;
        sparkPositions[i * 3 + 2] = d.z + Math.cos(elapsed * 1.1 + d.phase) * (.1 + d.life * .22);
      }
      sparkGeo.attributes.position.needsUpdate = true;

      starField.rotation.y += dt * .002;
      controls.update();
      renderer.render(scene, camera);
    }
    animate();

    addEventListener('resize', () => {
      camera.aspect = innerWidth / innerHeight;
      camera.updateProjectionMatrix();
      renderer.setSize(innerWidth, innerHeight);
      renderer.setPixelRatio(Math.min(devicePixelRatio, 2));
    });
  </script>
</body>
</html>