MiniMax M3
by MiniMaxreasoning defaultClean
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>