Models 44

GPT-6.1 Terra

by OpenAIReasoningClean
Open in new window

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

How it went

Total time
1 min 25 s
Cost
$0.035
Output tokens
6,974
Spent thinking
1,351 tokens
Speed
88.3 tok/s
Console errors
0
First token after
5.8 s
First visible text after
31.2 s
Prompt tokens
555
Code size
16.2 KB
Finish reason
stop
Served by
OpenAI
Model id
openai/gpt-6.1-terra
Reasoning sent
{"effort":"medium"}
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 · 396 lines

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>The Quiet Hours</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 { width: 100%; height: 100%; margin: 0; overflow: hidden; background: #080f18; }
  body { font-family: Arial, sans-serif; color: #f2e9d7; }
  #scene { position: fixed; inset: 0; }
  canvas { display: block; }
  .overlay { position: fixed; inset: 0; pointer-events: none; background: linear-gradient(180deg, rgba(3,9,17,.42), transparent 25%, transparent 72%, rgba(3,8,12,.52)); }
  .top { position: absolute; top: 35px; left: 42px; right: 42px; display: flex; justify-content: space-between; align-items: flex-start; }
  .eyebrow, .status, .hint, .bottom-label { font-size: 9px; letter-spacing: .24em; text-transform: uppercase; font-weight: 600; }
  .eyebrow { color: #d8a76a; margin-bottom: 9px; }
  h1 { font-family: Georgia, serif; font-size: 28px; font-weight: 400; letter-spacing: .025em; margin: 0; color: #f4efdf; }
  .subtitle { color: #aeb9b2; font-family: Georgia, serif; font-style: italic; font-size: 13px; margin-top: 7px; }
  .status { color: #aab8b0; display: flex; align-items: center; gap: 9px; padding-top: 5px; }
  .dot { width: 6px; height: 6px; border-radius: 50%; background: #d6a45e; box-shadow: 0 0 10px #ef9f42; }
  .bottom { position: absolute; left: 42px; right: 42px; bottom: 31px; display: flex; justify-content: space-between; align-items: end; gap: 20px; }
  .bottom-label { color: #d8a76a; margin-bottom: 7px; }
  .bottom-copy { font-family: Georgia, serif; color: #c3c7b9; font-size: 13px; font-style: italic; }
  .hint { color: #aab6af; text-align: right; line-height: 1.8; }
  .hint span { color: #d5d7c9; }
  @media (max-width: 600px) {
    .top { top: 25px; left: 24px; right: 24px; }
    h1 { font-size: 23px; }
    .subtitle { font-size: 12px; }
    .status { font-size: 8px; letter-spacing: .14em; }
    .bottom { left: 24px; right: 24px; bottom: 24px; }
    .hint { font-size: 8px; letter-spacing: .14em; }
    .bottom-copy { font-size: 12px; }
  }
</style>
</head>
<body>
<div id="scene"></div>
<div class="overlay">
  <div class="top">
    <div>
      <div class="eyebrow">A moment in the wilderness</div>
      <h1>The Quiet Hours</h1>
      <div class="subtitle">Somewhere beneath the pines</div>
    </div>
    <div class="status"><span class="dot"></span> Nightfall</div>
  </div>
  <div class="bottom">
    <div>
      <div class="bottom-label">The clearing &nbsp; / &nbsp; 01</div>
      <div class="bottom-copy">Stay a while by the fire.</div>
    </div>
    <div class="hint"><span>Drag</span> to look around<br><span>Scroll</span> to move closer</div>
  </div>
</div>
<script type="module">
import * as THREE from 'three';
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';

const container = document.getElementById('scene');
const scene = new THREE.Scene();
scene.background = new THREE.Color(0x0b1723);
scene.fog = new THREE.Fog(0x0b1723, 20, 58);

const camera = new THREE.PerspectiveCamera(43, innerWidth / innerHeight, 0.1, 150);
camera.position.set(13, 8.7, 20);
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.1;
container.appendChild(renderer.domElement);

const controls = new OrbitControls(camera, renderer.domElement);
controls.target.set(0, 1.5, 0);
controls.enableDamping = true;
controls.dampingFactor = 0.045;
controls.minDistance = 8;
controls.maxDistance = 38;
controls.maxPolarAngle = Math.PI / 2 - 0.035;
controls.minPolarAngle = 0.22;
controls.enablePan = false;
controls.update();

// Repeatable placement keeps the clearing balanced on every load.
let seed = 48691;
function random() { seed = (seed * 1664525 + 1013904223) >>> 0; return seed / 4294967296; }
function rand(a, b) { return a + random() * (b - a); }

scene.add(new THREE.HemisphereLight(0x8fa8b5, 0x18251c, 1.05));
const moonlight = new THREE.DirectionalLight(0x839db5, 1.15);
moonlight.position.set(-14, 23, -12);
scene.add(moonlight);

const firelight = new THREE.PointLight(0xff8a35, 95, 18, 2);
firelight.position.set(0, 2.1, 0);
firelight.castShadow = true;
firelight.shadow.mapSize.set(1024, 1024);
firelight.shadow.camera.near = 0.3;
firelight.shadow.camera.far = 19;
firelight.shadow.bias = -0.003;
firelight.shadow.normalBias = 0.035;
scene.add(firelight);
const fireFill = new THREE.PointLight(0xffa14b, 20, 10, 2);
fireFill.position.set(0, 0.7, 0);
scene.add(fireFill);

const groundMat = new THREE.MeshStandardMaterial({ color: 0x26352c, roughness: 1, flatShading: true });
const ground = new THREE.Mesh(new THREE.CircleGeometry(65, 64), groundMat);
ground.rotation.x = -Math.PI / 2;
ground.receiveShadow = true;
scene.add(ground);

// An irregular, triangulated patch of earth for the clearing.
function clearingPatch(radius, segments) {
  const positions = [0, 0.012, 0];
  const colors = [0.27, 0.25, 0.19];
  const points = [];
  for (let i = 0; i < segments; i++) {
    const a = i / segments * Math.PI * 2;
    const r = radius * rand(0.90, 1.08);
    points.push([Math.cos(a) * r, Math.sin(a) * r]);
  }
  const vertices = [], vertexColors = [];
  for (let i = 0; i < segments; i++) {
    const variation = rand(0.83, 1.15);
    const c = new THREE.Color(0x59513a).multiplyScalar(variation);
    vertices.push(0, 0.015, 0, points[i][0], 0.015, points[i][1], points[(i + 1) % segments][0], 0.015, points[(i + 1) % segments][1]);
    for (let j = 0; j < 3; j++) vertexColors.push(c.r, c.g, c.b);
  }
  const geo = new THREE.BufferGeometry();
  geo.setAttribute('position', new THREE.Float32BufferAttribute(vertices, 3));
  geo.setAttribute('color', new THREE.Float32BufferAttribute(vertexColors, 3));
  geo.computeVertexNormals();
  const mesh = new THREE.Mesh(geo, new THREE.MeshStandardMaterial({ vertexColors: true, roughness: 1, side: THREE.DoubleSide, flatShading: true }));
  mesh.receiveShadow = true;
  scene.add(mesh);
}
clearingPatch(8.5, 32);

const bark = new THREE.MeshStandardMaterial({ color: 0x4b3528, roughness: 1, flatShading: true });
const barkLight = new THREE.MeshStandardMaterial({ color: 0x755039, roughness: 1, flatShading: true });
const cutWood = new THREE.MeshStandardMaterial({ color: 0xa67b50, roughness: 1, flatShading: true });
const pineMats = [0x243d32, 0x2a4638, 0x20392f, 0x324b3c, 0x1e352d].map(color =>
  new THREE.MeshStandardMaterial({ color, roughness: 1, flatShading: true })
);
const trunkGeo = new THREE.CylinderGeometry(0.17, 0.29, 1, 6);
const coneGeo = new THREE.ConeGeometry(1, 1, 7, 1);

function tree(x, z, scale) {
  const group = new THREE.Group();
  const trunk = new THREE.Mesh(trunkGeo, bark);
  trunk.scale.set(scale, 2.0 * scale, scale);
  trunk.position.y = scale;
  trunk.castShadow = true;
  trunk.receiveShadow = true;
  group.add(trunk);
  const mat = pineMats[Math.floor(random() * pineMats.length)];
  for (let i = 0; i < 3; i++) {
    const cone = new THREE.Mesh(coneGeo, mat);
    const w = (1.85 - i * 0.31) * scale;
    const h = (3.05 - i * 0.18) * scale;
    cone.scale.set(w, h, w);
    cone.position.y = (2.5 + i * 1.33) * scale;
    cone.rotation.y = random() * Math.PI;
    cone.castShadow = true;
    cone.receiveShadow = true;
    group.add(cone);
  }
  group.position.set(x, 0, z);
  group.rotation.y = random() * Math.PI * 2;
  scene.add(group);
}

// Several staggered rings, keeping the near camera side of the clearing open.
for (let ring = 0; ring < 3; ring++) {
  const count = [17, 23, 27][ring];
  for (let i = 0; i < count; i++) {
    const angle = (i + rand(-0.35, 0.35)) / count * Math.PI * 2;
    const radius = [11.2, 18.5, 27.5][ring] + rand(-1.5, 1.5);
    const x = Math.cos(angle) * radius, z = Math.sin(angle) * radius;
    const facingCamera = (x * 0.55 + z * 0.84) / radius;
    if (ring === 0 && facingCamera > 0.65) continue;
    if (ring === 1 && facingCamera > 0.89) continue;
    tree(x, z, rand(0.8, 1.25) * (ring === 2 ? 1.1 : 1));
  }
}

const rockMaterials = [0x77796c, 0x686e62, 0x888276, 0x565e56].map(color =>
  new THREE.MeshStandardMaterial({ color, roughness: 1, flatShading: true })
);
const rockGeo = new THREE.DodecahedronGeometry(1, 0);
function rock(x, z, sx, sy, sz, material) {
  const mesh = new THREE.Mesh(rockGeo, material || rockMaterials[Math.floor(random() * rockMaterials.length)]);
  mesh.position.set(x, sy * 0.62, z);
  mesh.scale.set(sx, sy, sz);
  mesh.rotation.set(rand(-0.2, 0.2), rand(0, Math.PI), rand(-0.2, 0.2));
  mesh.castShadow = true;
  mesh.receiveShadow = true;
  scene.add(mesh);
  return mesh;
}

// The hearth's uneven stone ring.
for (let i = 0; i < 13; i++) {
  const a = i * Math.PI * 2 / 13;
  const r = rand(1.32, 1.46);
  rock(Math.cos(a) * r, Math.sin(a) * r, rand(0.34, 0.49), rand(0.22, 0.34), rand(0.30, 0.43));
}
for (const p of [[-5.9,-1.6],[5.8,-2.8],[-5.2,4.1],[5.5,4.7],[-8,-4],[7.3,0.7],[-3.6,-7]]) {
  rock(p[0], p[1], rand(0.45, 0.8), rand(0.25, 0.5), rand(0.4, 0.75));
}

function log(x, y, z, length, radius, angle, material = barkLight) {
  const group = new THREE.Group();
  const cylinder = new THREE.Mesh(new THREE.CylinderGeometry(radius * 0.95, radius, length, 7), material);
  cylinder.rotation.z = Math.PI / 2;
  cylinder.castShadow = true;
  cylinder.receiveShadow = true;
  group.add(cylinder);
  for (const side of [-1, 1]) {
    const end = new THREE.Mesh(new THREE.CircleGeometry(radius * 0.92, 7), cutWood);
    end.position.x = side * (length / 2 + 0.005);
    end.rotation.y = side * Math.PI / 2;
    group.add(end);
  }
  group.position.set(x, y, z);
  group.rotation.y = angle;
  scene.add(group);
  return group;
}
log(0, .25, 0, 2.1, .20, .3, bark);
log(0, .3, 0, 2.2, .22, 1.5, barkLight);
log(.1, .46, 0, 1.85, .19, -0.65, bark);
log(-4.5, .39, 1.3, 3.0, .38, -0.4);
log(4.2, .36, 2.0, 2.8, .35, 0.48);
log(-2.8, .27, -4.4, 2.2, .26, -0.6, bark);

// Small tufts add texture without cluttering the clearing.
const grassMat = new THREE.MeshStandardMaterial({ color: 0x63745a, roughness: 1, side: THREE.DoubleSide });
const grassGeo = new THREE.ConeGeometry(0.075, 0.55, 3);
for (let i = 0; i < 115; i++) {
  const a = rand(0, Math.PI * 2), r = rand(5.2, 21);
  const x = Math.cos(a) * r, z = Math.sin(a) * r;
  const tuft = new THREE.Group();
  for (let j = 0; j < 3; j++) {
    const blade = new THREE.Mesh(grassGeo, grassMat);
    blade.position.set(rand(-.14,.14), rand(.14,.23), rand(-.14,.14));
    blade.rotation.z = rand(-.4,.4);
    blade.scale.setScalar(rand(.65,1.15));
    tuft.add(blade);
  }
  tuft.position.set(x, 0.02, z);
  scene.add(tuft);
}

// Soft procedural glow textures, generated locally.
function glowTexture(r, g, b) {
  const c = document.createElement('canvas');
  c.width = c.height = 128;
  const ctx = c.getContext('2d');
  const grad = ctx.createRadialGradient(64,64,0,64,64,64);
  grad.addColorStop(0, `rgba(${r},${g},${b},0.8)`);
  grad.addColorStop(.18, `rgba(${r},${g},${b},0.38)`);
  grad.addColorStop(.5, `rgba(${r},${g},${b},0.08)`);
  grad.addColorStop(1, `rgba(${r},${g},${b},0)`);
  ctx.fillStyle = grad;
  ctx.fillRect(0,0,128,128);
  return new THREE.CanvasTexture(c);
}
const fireGlow = new THREE.Sprite(new THREE.SpriteMaterial({
  map: glowTexture(255, 113, 28), color: 0xffa343, transparent: true,
  blending: THREE.AdditiveBlending, depthWrite: false, fog: false, opacity: 0.58
}));
fireGlow.position.set(0, 1.4, 0);
fireGlow.scale.set(7, 7, 1);
scene.add(fireGlow);

// A faceted, tapered flame shape, layered in three warm colors.
function flameGeometry() {
  const verts = [];
  const rings = [
    { y: 0, r: .24, x: 0 },
    { y: .28, r: .39, x: 0 },
    { y: .72, r: .30, x: .06 },
    { y: 1.13, r: .19, x: -.06 },
    { y: 1.48, r: .09, x: .08 },
    { y: 1.85, r: 0, x: .17 }
  ];
  const sides = 7;
  for (let j = 0; j < rings.length - 1; j++) {
    for (let i = 0; i < sides; i++) {
      const a = i * Math.PI * 2 / sides, b = (i + 1) * Math.PI * 2 / sides;
      const p = (ring, angle) => [ring.x + Math.cos(angle) * ring.r, ring.y, Math.sin(angle) * ring.r];
      const a1 = p(rings[j], a), b1 = p(rings[j], b), a2 = p(rings[j+1], a), b2 = p(rings[j+1], b);
      verts.push(...a1,...b1,...a2, ...b1,...b2,...a2);
    }
  }
  const geo = new THREE.BufferGeometry();
  geo.setAttribute('position', new THREE.Float32BufferAttribute(verts, 3));
  geo.computeVertexNormals();
  return geo;
}
const flameGeo = flameGeometry();
const flameMats = [0xff4b0c, 0xff8a12, 0xffd252, 0xffed9b].map(color =>
  new THREE.MeshBasicMaterial({ color, side: THREE.DoubleSide, toneMapped: false })
);
const flames = [];
function addFlame(x, z, scale, mat, phase) {
  const mesh = new THREE.Mesh(flameGeo, flameMats[mat]);
  mesh.position.set(x, .27, z);
  mesh.scale.set(scale, scale, scale);
  mesh.rotation.y = phase;
  scene.add(mesh);
  flames.push({ mesh, scale, phase });
}
addFlame(0, 0, 1.35, 0, 0);
addFlame(-.33, .02, .95, 1, 2);
addFlame(.28, -.12, 1.08, 1, 4);
addFlame(.08, .19, .88, 2, 1);
addFlame(-.15, .25, .62, 3, 3);
addFlame(.4, .18, .6, 2, 5);

// Rising embers.
const sparkCount = 100;
const sparkPositions = new Float32Array(sparkCount * 3);
const sparks = [];
for (let i = 0; i < sparkCount; i++) {
  sparks.push({ x: rand(-.42,.42), z: rand(-.42,.42), y: rand(.5,5.8), speed: rand(.35,1.1), drift: rand(-.25,.25), phase: rand(0, 6.28) });
}
const sparkGeo = new THREE.BufferGeometry();
sparkGeo.setAttribute('position', new THREE.BufferAttribute(sparkPositions, 3));
const sparkMat = new THREE.PointsMaterial({ color: 0xffb34e, size: .065, transparent: true, opacity: .9, blending: THREE.AdditiveBlending, depthWrite: false, fog: false });
const sparkPoints = new THREE.Points(sparkGeo, sparkMat);
scene.add(sparkPoints);

// Distant stars and a softly haloed moon.
const starsArray = [];
for (let i = 0; i < 400; i++) {
  const a = rand(0, Math.PI * 2);
  const radius = rand(65, 100);
  starsArray.push(Math.cos(a) * radius, rand(3, 62), Math.sin(a) * radius);
}
const starGeo = new THREE.BufferGeometry();
starGeo.setAttribute('position', new THREE.Float32BufferAttribute(starsArray, 3));
const starMat = new THREE.PointsMaterial({ color: 0xd9e4da, size: .14, sizeAttenuation: true, transparent: true, opacity: .8, fog: false });
scene.add(new THREE.Points(starGeo, starMat));

const moon = new THREE.Mesh(new THREE.SphereGeometry(1.9, 20, 16), new THREE.MeshBasicMaterial({ color: 0xe8e5ca, fog: false, toneMapped: false }));
moon.position.set(-40, 14, -28);
scene.add(moon);
const moonGlow = new THREE.Sprite(new THREE.SpriteMaterial({ map: glowTexture(185, 207, 202), transparent: true, opacity: .32, depthWrite: false, fog: false }));
moonGlow.position.copy(moon.position);
moonGlow.scale.set(15,15,1);
scene.add(moonGlow);

const clock = new THREE.Clock();
function animate() {
  requestAnimationFrame(animate);
  const t = clock.getElapsedTime();
  const flicker = Math.sin(t * 8.7) * .10 + Math.sin(t * 13.1) * .05 + Math.sin(t * 4.3) * .06;
  firelight.intensity = 95 * (1 + flicker);
  firelight.position.x = Math.sin(t * 4.2) * .12;
  fireFill.intensity = 20 * (1 + flicker);
  fireGlow.material.opacity = .53 + flicker * .35;
  flames.forEach(({mesh, scale, phase}) => {
    mesh.scale.set(scale * (1 + .08 * Math.sin(t * 8 + phase)), scale * (1 + .13 * Math.sin(t * 7 + phase)), scale * (1 + .06 * Math.cos(t * 9 + phase)));
    mesh.rotation.y = phase + Math.sin(t * 2.8 + phase) * .22;
    mesh.rotation.z = Math.sin(t * 5 + phase) * .06;
  });
  for (let i = 0; i < sparkCount; i++) {
    const s = sparks[i];
    const y = .5 + ((s.y + t * s.speed) % 5.6);
    sparkPositions[i*3] = s.x + Math.sin(t * 1.4 + s.phase + y) * .15 + s.drift * y;
    sparkPositions[i*3+1] = y;
    sparkPositions[i*3+2] = s.z + Math.cos(t + s.phase + y) * .14;
  }
  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,351 tokens)
**Creating a polished scene**

I need to create a visually polished scene, ensuring all three imports are exact. The camera should be set at (13,10,18), looking towards (0,2,0). The terrain features a dark forest floor with a central clearing, and I'll place 40 trees in a ring while preventing any obstructions to the camera's front angle. The scene will have navy background fog, with a moon positioned at (-12,22,-30). I also need to incorporate subtle UI overlays, ensuring they enhance the artistic experience without being intrusive.**Designing a dynamic scene**

I'm creating a ground circle with a radius of 64 and 55 segments, incorporating irregular patches of rocks and small grass tufts. There will be a fire ring made of rocks and 5 logs arranged star-like around the center. The animated flames will use custom triangulated cone geometries in vibrant yellow, orange, and red colors. For lighting, I'll use a glowing sprite with a canvas-generated radial texture, along with smoke particles and dynamic sparks. The moon will be a basic pale sphere, and fog can be used to affect star visibility.**Adjusting camera perspective**

I need to set the moon behind the trees with a camera positioned at (-18, 24, -50) and target slightly at y = 2. I'm considering projecting the view at y = 24, which is quite high. The camera will have a downward angle of about 20 degrees and a distance of 60, meaning I need to compute the view based on height. The field of view is 45 degrees, so I'll have to account for the trees blocking the moon at (-16, 10, -45) since it's positioned above.**Planning visual elements**

I’m thinking about adding orange bloom sprites at a specific vertical position. I'll generate a glowing canvas and consider the placement of stars relative to the camera's position in the sky. I aim to create points in a spherical area that have random horizontal coordinates, but they’ll be projected properly. I have to check if the moon might be hidden by trees and then decide on its color and clouds as I start coding.