GPT-6.1 Terra
by OpenAIReasoningClean
Running live in a sandboxed frame. Click inside it before using the keyboard.
How it went
- Total time
- 1 min 20 s
- Cost
- $0.034
- Output tokens
- 6,712
- Spent thinking
- 1,298 tokens
- Speed
- 98.5 tok/s
- Console errors
- 0
- First token after
- 12.3 s
- First visible text after
- 29.9 s
- Prompt tokens
- 555
- Code size
- 15.9 KB
- Finish reason
- stop
- Served by
- OpenAI
- Model id
openai/gpt-6.1-terra- Reasoning sent
model default- Max output
- 128,000 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 · 383 lines
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>The Quiet Clearing</title>
<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>
<style>
* { box-sizing: border-box; }
html, body { margin: 0; width: 100%; height: 100%; overflow: hidden; background: #081019; }
body { font-family: Arial, Helvetica, sans-serif; color: #f4eee1; }
canvas { display: block; width: 100%; height: 100%; }
.overlay { position: fixed; inset: 0; pointer-events: none; }
.heading { position: absolute; top: 38px; left: 44px; text-shadow: 0 2px 20px #050b11; }
.eyebrow { color: #dcb67c; font-size: 10px; font-weight: 700; letter-spacing: .24em; text-transform: uppercase; }
h1 { margin: 10px 0 8px; font-family: Georgia, 'Times New Roman', serif; font-size: clamp(29px, 3vw, 43px); font-weight: 400; letter-spacing: -.03em; }
.subtitle { color: #b9c3c3; font-size: 12px; letter-spacing: .035em; }
.bottom { position: absolute; left: 44px; right: 44px; bottom: 34px; display: flex; justify-content: space-between; align-items: end; gap: 20px; }
.instructions { display: flex; align-items: center; gap: 10px; color: #b8c4c6; font-size: 10px; font-weight: 700; letter-spacing: .15em; text-transform: uppercase; }
.mouse { width: 15px; height: 21px; border: 1px solid #91a2a3; border-radius: 8px; position: relative; opacity: .85; }
.mouse:after { content: ''; position: absolute; width: 1px; height: 5px; background: #91a2a3; top: 4px; left: 6px; }
.status { display: flex; align-items: center; gap: 9px; color: #d0c4ad; font-size: 10px; font-weight: 700; letter-spacing: .16em; text-transform: uppercase; }
.dot { width: 6px; height: 6px; border-radius: 50%; background: #ffae51; box-shadow: 0 0 12px #ff8c36; }
.vignette { position: absolute; inset: 0; background: radial-gradient(ellipse at 50% 48%, transparent 35%, rgba(3,8,13,.30) 100%); }
@media (max-width: 600px) {
.heading { top: 25px; left: 23px; }
.bottom { left: 23px; right: 23px; bottom: 24px; }
.subtitle { max-width: 220px; line-height: 1.5; }
.instructions { font-size: 9px; letter-spacing: .1em; }
.status { font-size: 9px; }
}
</style>
</head>
<body>
<div class="overlay">
<div class="vignette"></div>
<div class="heading">
<div class="eyebrow">A little place to wander</div>
<h1>The quiet clearing</h1>
<div class="subtitle">A campfire under the forest sky.</div>
</div>
<div class="bottom">
<div class="instructions"><span class="mouse"></span><span>Drag to orbit · Scroll to zoom</span></div>
<div class="status"><span class="dot"></span> Fire is burning</div>
</div>
</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(0x0a1420);
scene.fog = new THREE.Fog(0x101b26, 23, 58);
const camera = new THREE.PerspectiveCamera(45, innerWidth / innerHeight, 0.1, 180);
camera.position.set(12.5, 9, 18.5);
const renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setPixelRatio(Math.min(devicePixelRatio, 2));
renderer.setSize(innerWidth, innerHeight);
renderer.shadowMap.enabled = true;
renderer.shadowMap.type = THREE.PCFSoftShadowMap;
renderer.outputColorSpace = THREE.SRGBColorSpace;
renderer.toneMapping = THREE.ACESFilmicToneMapping;
renderer.toneMappingExposure = 1.05;
document.body.prepend(renderer.domElement);
const controls = new OrbitControls(camera, renderer.domElement);
controls.target.set(0, 1.25, 0);
controls.enableDamping = true;
controls.dampingFactor = 0.055;
controls.minDistance = 9;
controls.maxDistance = 37;
controls.maxPolarAngle = Math.PI / 2 - 0.045;
controls.minPolarAngle = 0.2;
controls.update();
let seed = 32694;
function rand() { seed = (seed * 1664525 + 1013904223) >>> 0; return seed / 4294967296; }
function between(a, b) { return a + rand() * (b - a); }
function mat(color, extra = {}) { return new THREE.MeshStandardMaterial({ color, flatShading: true, ...extra }); }
scene.add(new THREE.HemisphereLight(0x809bb6, 0x222b25, 0.75));
const moonlight = new THREE.DirectionalLight(0x9cb9d2, 1.1);
moonlight.position.set(-12, 25, -15);
scene.add(moonlight);
const fireLight = new THREE.PointLight(0xff8a33, 32, 19, 2);
fireLight.position.set(0, 1.5, 0);
fireLight.castShadow = true;
fireLight.shadow.mapSize.set(1024, 1024);
fireLight.shadow.camera.near = 0.1;
fireLight.shadow.camera.far = 22;
fireLight.shadow.bias = -0.001;
fireLight.shadow.normalBias = 0.04;
scene.add(fireLight);
const ground = new THREE.Mesh(new THREE.CircleGeometry(75, 64), mat(0x1c302d));
ground.rotation.x = -Math.PI / 2;
ground.receiveShadow = true;
scene.add(ground);
// Irregular earth of the clearing.
function patch(radius, count, color, y, variation = .12) {
const vertices = [0, y, 0];
for (let i = 0; i <= count; i++) {
const a = i / count * Math.PI * 2;
const r = radius * (1 + (i === count ? 0 : between(-variation, variation)));
vertices.push(Math.cos(a) * r, y, Math.sin(a) * r);
}
const indices = [];
for (let i = 1; i <= count; i++) indices.push(0, i + 1, i);
const geo = new THREE.BufferGeometry();
geo.setAttribute('position', new THREE.Float32BufferAttribute(vertices, 3));
geo.setIndex(indices);
geo.computeVertexNormals();
const m = new THREE.Mesh(geo, mat(color));
m.receiveShadow = true;
scene.add(m);
}
patch(7.5, 36, 0x354139, .012, .11);
patch(5.2, 32, 0x53473a, .025, .13);
patch(2.5, 24, 0x604a39, .035, .10);
// Ground flecks, kept subtle and angular.
const flecks = [];
for (let i = 0; i < 500; i++) {
const a = rand() * Math.PI * 2, r = between(3.5, 30);
const x = Math.cos(a) * r, z = Math.sin(a) * r;
const s = between(.07, .3);
flecks.push(x, .045, z, x + s, .045, z + s * .28, x - s * .2, .045, z + s * .65);
}
const fleckGeo = new THREE.BufferGeometry();
fleckGeo.setAttribute('position', new THREE.Float32BufferAttribute(flecks, 3));
fleckGeo.computeVertexNormals();
scene.add(new THREE.Mesh(fleckGeo, new THREE.MeshBasicMaterial({ color: 0x526455, side: THREE.DoubleSide, transparent: true, opacity: .28, fog: true })));
const trunkMats = [mat(0x4b3930), mat(0x584337), mat(0x3d3530)];
const leafMats = [mat(0x1b3a35), mat(0x24453d), mat(0x1c3937), mat(0x29463e), mat(0x253d38)];
const trunkGeo = new THREE.CylinderGeometry(.23, .39, 1, 6);
const coneGeo = new THREE.ConeGeometry(1, 1, 7);
function addTree(x, z, scale) {
const tree = new THREE.Group();
tree.position.set(x, 0, z);
tree.rotation.y = between(0, Math.PI * 2);
const trunkHeight = 2.3 * scale;
const trunk = new THREE.Mesh(trunkGeo, trunkMats[Math.floor(rand() * trunkMats.length)]);
trunk.scale.set(scale, trunkHeight, scale);
trunk.position.y = trunkHeight / 2;
trunk.castShadow = true;
trunk.receiveShadow = true;
tree.add(trunk);
const leafMat = leafMats[Math.floor(rand() * leafMats.length)];
const heights = [3.5, 3.1, 2.7];
const radii = [1.65, 1.34, 1.03];
for (let j = 0; j < 3; j++) {
const cone = new THREE.Mesh(coneGeo, leafMat);
cone.scale.set(radii[j] * scale, heights[j] * scale, radii[j] * scale);
cone.position.y = (2.2 + j * 1.25) * scale;
cone.castShadow = true;
cone.receiveShadow = true;
tree.add(cone);
}
scene.add(tree);
}
// A loose ring of trees, with a clear view from the initial camera.
for (let i = 0; i < 68; i++) {
const a = i * 2.39996 + between(-.19, .19);
const r = 8.4 + Math.sqrt(rand()) * 24;
const x = Math.cos(a) * r, z = Math.sin(a) * r;
const towardCamera = (x * 12.5 + z * 18.5) / (r * Math.hypot(12.5, 18.5));
if (towardCamera > .78 && r < 17) continue;
addTree(x, z, between(.85, 1.45) * (r > 22 ? 1.1 : 1));
}
const rockMats = [mat(0x6d706a), mat(0x5e655f), mat(0x77766c), mat(0x535e5a)];
const rockGeo = new THREE.DodecahedronGeometry(1, 0);
function rock(x, z, size, sy = .65) {
const mesh = new THREE.Mesh(rockGeo, rockMats[Math.floor(rand() * rockMats.length)]);
mesh.position.set(x, size * sy * .58, z);
mesh.scale.set(size, size * sy, size * between(.75, 1.15));
mesh.rotation.set(between(-.3, .3), between(0, 6.28), between(-.3, .3));
mesh.castShadow = true;
mesh.receiveShadow = true;
scene.add(mesh);
}
for (let i = 0; i < 11; i++) {
const a = i * Math.PI * 2 / 11 + .05;
rock(Math.cos(a) * 1.3, Math.sin(a) * 1.3, between(.31, .42), .65);
}
for (let i = 0; i < 23; i++) {
const a = rand() * 6.283, r = between(4.5, 12);
rock(Math.cos(a) * r, Math.sin(a) * r, between(.18, .65), between(.45, .8));
}
const bark = mat(0x553a29);
const cutWood = mat(0xa17b51);
function log(x, z, length, radius, angle, y = radius) {
const group = new THREE.Group();
const body = new THREE.Mesh(new THREE.CylinderGeometry(radius * .9, radius, length, 8), bark);
body.rotation.z = Math.PI / 2;
body.castShadow = true;
body.receiveShadow = true;
group.add(body);
for (const side of [-1, 1]) {
const end = new THREE.Mesh(new THREE.CircleGeometry(radius * .9, 8), cutWood);
end.position.x = side * (length / 2 + .006);
end.rotation.y = side * Math.PI / 2;
group.add(end);
const ring = new THREE.Mesh(new THREE.CircleGeometry(radius * .56, 8), mat(0x806043));
ring.position.x = side * (length / 2 + .009);
ring.rotation.y = side * Math.PI / 2;
group.add(ring);
}
group.position.set(x, y, z);
group.rotation.y = angle;
scene.add(group);
return group;
}
log(-3.55, 2.5, 2.8, .39, -.45);
log(3.1, -2.65, 2.5, .35, .45);
log(3.9, 2.25, 2.2, .31, -1.05);
for (let i = 0; i < 5; i++) {
log(0, 0, 2.1, .17, i * Math.PI / 5, .22 + (i % 2) * .12);
}
// A soft pool of firelight on the ground and an atmospheric glow.
function radialTexture(inner, outer) {
const c = document.createElement('canvas');
c.width = c.height = 128;
const ctx = c.getContext('2d');
const g = ctx.createRadialGradient(64, 64, 0, 64, 64, 64);
g.addColorStop(0, inner);
g.addColorStop(1, outer);
ctx.fillStyle = g;
ctx.fillRect(0, 0, 128, 128);
return new THREE.CanvasTexture(c);
}
const groundGlow = new THREE.Mesh(
new THREE.PlaneGeometry(12, 12),
new THREE.MeshBasicMaterial({ map: radialTexture('rgba(255,135,49,0.36)', 'rgba(255,99,20,0)'), transparent: true, depthWrite: false, blending: THREE.AdditiveBlending })
);
groundGlow.rotation.x = -Math.PI / 2;
groundGlow.position.y = .055;
scene.add(groundGlow);
const glow = new THREE.Sprite(new THREE.SpriteMaterial({
map: radialTexture('rgba(255,142,44,0.48)', 'rgba(255,92,10,0)'),
transparent: true, depthWrite: false, blending: THREE.AdditiveBlending, fog: false
}));
glow.position.set(0, 1.25, 0);
glow.scale.set(5, 5, 1);
scene.add(glow);
// Faceted flame tongues with a warm gradient from base to tip.
function flameGeometry() {
const geo = new THREE.BufferGeometry();
const pos = [], colors = [];
const rings = [
{ y: 0, r: .35, shift: 0 },
{ y: .25, r: .48, shift: 0 },
{ y: .65, r: .34, shift: .08 },
{ y: 1.05, r: .19, shift: -.04 },
{ y: 1.5, r: .015, shift: .16 }
];
const palette = [new THREE.Color(0xffe58a), new THREE.Color(0xffb42e), new THREE.Color(0xff751c), new THREE.Color(0xf34a12), new THREE.Color(0xe54b16)];
const n = 7;
function vertex(ring, j) {
const a = (j % n) / n * Math.PI * 2;
const q = rings[ring];
pos.push(Math.cos(a) * q.r + q.shift, q.y, Math.sin(a) * q.r);
const c = palette[ring];
colors.push(c.r, c.g, c.b);
}
for (let k = 0; k < rings.length - 1; k++) {
for (let j = 0; j < n; j++) {
vertex(k, j); vertex(k, j + 1); vertex(k + 1, j);
vertex(k, j + 1); vertex(k + 1, j + 1); vertex(k + 1, j);
}
}
geo.setAttribute('position', new THREE.Float32BufferAttribute(pos, 3));
geo.setAttribute('color', new THREE.Float32BufferAttribute(colors, 3));
geo.computeVertexNormals();
return geo;
}
const flameGeo = flameGeometry();
const flameMat = new THREE.MeshBasicMaterial({ vertexColors: true, side: THREE.DoubleSide });
const flames = [];
for (let i = 0; i < 7; i++) {
const mesh = new THREE.Mesh(flameGeo, flameMat);
const a = i * Math.PI * 2 / 6;
const dist = i === 0 ? 0 : .37;
mesh.position.set(Math.cos(a) * dist, .25 + (i % 2) * .08, Math.sin(a) * dist);
mesh.scale.set(i === 0 ? 1.05 : .6, i === 0 ? 1.35 : between(.7, 1.12), i === 0 ? 1.05 : .6);
mesh.rotation.y = a;
mesh.userData.base = mesh.scale.y;
mesh.userData.phase = i * 1.7;
scene.add(mesh);
flames.push(mesh);
}
// Ember particles rise and drift away from the fire.
const sparkCount = 85;
const sparkPositions = new Float32Array(sparkCount * 3);
const sparksData = [];
function resetSpark(i, initial = false) {
const a = rand() * 6.283, r = rand() * .5;
sparkPositions[i * 3] = Math.cos(a) * r;
sparkPositions[i * 3 + 1] = initial ? between(.3, 5.2) : between(.4, 1);
sparkPositions[i * 3 + 2] = Math.sin(a) * r;
sparksData[i] = { speed: between(.65, 1.7), drift: between(-.22, .22), limit: between(2, 6), phase: rand() * 6.28 };
}
for (let i = 0; i < sparkCount; i++) resetSpark(i, true);
const sparkGeo = new THREE.BufferGeometry();
sparkGeo.setAttribute('position', new THREE.BufferAttribute(sparkPositions, 3));
const sparks = new THREE.Points(sparkGeo, new THREE.PointsMaterial({
color: 0xffb24c, size: .075, transparent: true, opacity: .9,
blending: THREE.AdditiveBlending, depthWrite: false, sizeAttenuation: true
}));
scene.add(sparks);
// Stars are outside the fog, spread over the upper hemisphere.
const starPositions = [], starColors = [];
for (let i = 0; i < 700; i++) {
const a = rand() * Math.PI * 2;
const elevation = between(.08, 1.45);
const r = 90;
starPositions.push(Math.cos(a) * Math.cos(elevation) * r, Math.sin(elevation) * r, Math.sin(a) * Math.cos(elevation) * r);
const b = between(.45, 1);
starColors.push(b * .8, b * .88, b);
}
const starGeo = new THREE.BufferGeometry();
starGeo.setAttribute('position', new THREE.Float32BufferAttribute(starPositions, 3));
starGeo.setAttribute('color', new THREE.Float32BufferAttribute(starColors, 3));
scene.add(new THREE.Points(starGeo, new THREE.PointsMaterial({ size: .18, vertexColors: true, fog: false, transparent: true, opacity: .85, depthWrite: false })));
const moon = new THREE.Mesh(new THREE.SphereGeometry(1.35, 20, 16), new THREE.MeshBasicMaterial({ color: 0xe9e9cd, fog: false }));
moon.position.set(-14, 14, -30);
scene.add(moon);
const moonHalo = new THREE.Sprite(new THREE.SpriteMaterial({
map: radialTexture('rgba(193,216,222,0.25)', 'rgba(160,195,210,0)'),
transparent: true, depthWrite: false, fog: false, blending: THREE.AdditiveBlending
}));
moonHalo.position.copy(moon.position);
moonHalo.scale.set(8, 8, 1);
scene.add(moonHalo);
const clock = new THREE.Clock();
function animate() {
requestAnimationFrame(animate);
const dt = Math.min(clock.getDelta(), .05);
const t = clock.elapsedTime;
fireLight.intensity = 30 + Math.sin(t * 8.3) * 3 + Math.sin(t * 13.7) * 2.5 + Math.sin(t * 3.1) * 2;
fireLight.position.x = Math.sin(t * 3) * .12;
glow.material.opacity = .8 + Math.sin(t * 7) * .1;
groundGlow.material.opacity = .8 + Math.sin(t * 8) * .1;
flames.forEach((f, i) => {
f.scale.y = f.userData.base * (1 + .13 * Math.sin(t * 8 + f.userData.phase) + .05 * Math.sin(t * 15 + i));
f.rotation.z = .1 * Math.sin(t * 5 + f.userData.phase);
f.rotation.x = .08 * Math.cos(t * 4 + f.userData.phase);
});
for (let i = 0; i < sparkCount; i++) {
const d = sparksData[i], p = i * 3;
sparkPositions[p + 1] += d.speed * dt;
sparkPositions[p] += (d.drift + Math.sin(t * 2 + d.phase) * .1) * dt;
sparkPositions[p + 2] += Math.cos(t * 1.5 + d.phase) * .09 * dt;
if (sparkPositions[p + 1] > d.limit) resetSpark(i);
}
sparkGeo.attributes.position.needsUpdate = true;
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>Reasoning trace (1,298 tokens)
**Considering flame geometry design** I need to create flame geometry shapes that incorporate ring sections and taper. I also want to make sure they have lean, dynamic scaling and rotation to ensure an appealing visual effect. I'm thinking about how to balance the shapes and their proportions while maintaining a sense of movement. It's an interesting challenge that blends creativity with technical aspects, and I want to get it just right!**Considering visibility of stars** I’m thinking about whether the stars are visible in the upper portion of the sky. It's interesting that when you have trees around, they can block some of the view. I wonder how much we miss out on because of those trees. It’s fascinating to think about how our surroundings can affect what we see, especially when it comes to something as beautiful as the stars!**Calculating fire geometry** I’m working on creating fire geometry based on the moon’s position and size. I need to confirm that the moon’s position is adjusted correctly on the x and z axes. I’m also visualizing a foggy scene with trees fading into the background. For the campfire flames, I'll define their geometry, using cone-shaped rings that vary in color from yellow to orange with a transparent effect. Additionally, I'll animate the flame tips for realistic movement, ensuring they look dynamic!**Setting up particle effects** I need to work with THREE.Points to create a particle system where I'll set positions, velocity, and manage resets for each frame. I'm aiming for a random distribution of stars across the dome using xz coordinates and a positive y to ensure visibility. The star point size should be 0.18, adjusting for size attenuation so they appear small. I'll include trees of various species with dark green leaves, and the ground will have grass in triangular patches. Finally, I’m designing a dodecahedron for rock geometry. Time to code this all up!