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
4 min 31 s
Cost
$0.100
Output tokens
19,819
Spent thinking
11,094 tokens
Speed
76.5 tok/s
Console errors
0
First token after
11.8 s
First visible text after
3 min 13 s
Prompt tokens
555
Code size
24.7 KB
Finish reason
stop
Served by
OpenAI
Model id
openai/gpt-6.1-terra
Reasoning sent
{"effort":"xhigh"}
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 · 634 lines

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>A Little Light in the Wild</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; }
  body {
    background: #0b1b22;
    color: #f3eee1;
    font-family: Arial, Helvetica, sans-serif;
  }
  #scene { position: fixed; inset: 0; }
  canvas { display: block; width: 100%; height: 100%; }
  .veil {
    position: fixed;
    inset: 0;
    pointer-events: none;
    background:
      linear-gradient(90deg, rgba(4,12,17,.36), transparent 36%, transparent 72%, rgba(4,12,17,.13)),
      linear-gradient(180deg, rgba(3,10,16,.27), transparent 27%, transparent 72%, rgba(3,10,13,.49));
  }
  .interface { position: fixed; inset: 0; pointer-events: none; }
  .intro { position: absolute; top: 47px; left: 55px; }
  .eyebrow {
    display: flex;
    align-items: center;
    gap: 10px;
    color: #e1bb83;
    font-size: 9px;
    font-weight: 700;
    letter-spacing: .22em;
    text-transform: uppercase;
  }
  .eyebrow .dot {
    width: 7px; height: 7px; border-radius: 50%;
    background: #e7a957;
    box-shadow: 0 0 12px #f5a650;
  }
  h1 {
    margin: 19px 0 12px;
    color: #f2efe6;
    font: 400 43px/1.06 Georgia, 'Times New Roman', serif;
    letter-spacing: -.035em;
    text-shadow: 0 2px 22px rgba(0,0,0,.25);
  }
  .description {
    margin: 0;
    color: rgba(229,236,226,.65);
    font-size: 12px;
    letter-spacing: .02em;
    line-height: 1.6;
  }
  .top-right {
    position: absolute; top: 49px; right: 55px;
    color: rgba(226,234,226,.58);
    font-size: 9px; font-weight: 700; letter-spacing: .2em;
    text-transform: uppercase;
  }
  .top-right span { color: #dfbb83; margin-right: 9px; }
  .bottom-left {
    position: absolute; left: 55px; bottom: 43px;
    display: flex; align-items: center; gap: 13px;
  }
  .icon {
    display: grid; place-items: center;
    width: 40px; height: 40px;
    border: 1px solid rgba(230,213,177,.34);
    border-radius: 50%;
    color: #e9bc80;
  }
  .place-label {
    color: #d9b77f; font-size: 9px; font-weight: 700;
    letter-spacing: .18em; text-transform: uppercase;
    margin-bottom: 6px;
  }
  .place-name { color: rgba(239,241,231,.77); font: 14px Georgia, serif; }
  .instructions {
    position: absolute; right: 55px; bottom: 47px;
    display: flex; align-items: center; gap: 10px;
    color: rgba(224,235,226,.68);
    font-size: 9px; font-weight: 700; letter-spacing: .15em;
    text-transform: uppercase;
  }
  .instructions svg { color: #d1b586; flex: none; }
  @media (max-width: 600px) {
    .intro { top: 29px; left: 25px; }
    h1 { font-size: 35px; margin-top: 15px; }
    .description { font-size: 11px; }
    .top-right { display: none; }
    .bottom-left { left: 25px; bottom: 27px; }
    .instructions { right: 24px; bottom: 37px; font-size: 8px; letter-spacing: .1em; }
    .instructions .extra { display: none; }
    .icon { width: 35px; height: 35px; }
    .place-name { font-size: 12px; }
  }
</style>
</head>
<body>
<div id="scene"></div>
<div class="veil"></div>
<div class="interface">
  <div class="intro">
    <div class="eyebrow"><span class="dot"></span> The quiet wild <span style="opacity:.45">/</span> 01</div>
    <h1>A little light<br>in the wild.</h1>
    <p class="description">A quiet moment beneath the pines.</p>
  </div>
  <div class="top-right"><span>✦</span> An evening outdoors</div>
  <div class="bottom-left">
    <div class="icon">
      <svg width="19" height="19" viewBox="0 0 24 24" fill="none" aria-hidden="true">
        <path d="M12.2 3.2c.5 3.5-3.5 4.4-3.1 7.2.2 1.1.9 1.8 1.6 2.1-.2-2 1.2-3.4 2.5-4.4.3 2.5 3.6 3.8 3.6 7a4.8 4.8 0 0 1-9.6 0c0-2.1 1-3.8 2-5.1" stroke="currentColor" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round"/>
        <path d="M5 20.5h14" stroke="currentColor" stroke-width="1.2" stroke-linecap="round"/>
      </svg>
    </div>
    <div><div class="place-label">The clearing</div><div class="place-name">Night in the pines</div></div>
  </div>
  <div class="instructions">
    <svg width="20" height="20" viewBox="0 0 24 24" fill="none" aria-hidden="true">
      <rect x="7.5" y="3" width="9" height="15" rx="4.5" stroke="currentColor" stroke-width="1.1"/>
      <path d="M12 6.5v3.3M3.5 20.5h17M3.5 20.5l2-2m-2 2 2 2m15-2-2-2m2 2-2 2" stroke="currentColor" stroke-width="1.1" stroke-linecap="round" stroke-linejoin="round"/>
    </svg>
    <span>Drag to explore<span class="extra"> &nbsp;·&nbsp; Scroll to zoom</span></span>
  </div>
</div>

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

const mount = document.getElementById('scene');
const scene = new THREE.Scene();
scene.background = new THREE.Color(0x0b1b22);
scene.fog = new THREE.Fog(0x172d30, 25, 65);

const camera = new THREE.PerspectiveCamera(43, window.innerWidth / window.innerHeight, 0.1, 250);
camera.position.set(0, 7.5, 20.5);

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

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

let seed = 481516;
function random() {
  seed = (seed * 1664525 + 1013904223) >>> 0;
  return seed / 4294967296;
}
function between(a, b) { return a + (b - a) * random(); }
function groundHeight(x, z) {
  const d = Math.sqrt(x * x + z * z);
  const fade = THREE.MathUtils.clamp((d - 5) / 7, 0, 1);
  return fade * (0.12 * Math.sin(x * 0.38) * Math.cos(z * 0.43) + 0.07 * Math.sin(x * 0.72 + z * 0.35));
}

// A softly graded night sky, independent of the fog.
const skyGeometry = new THREE.SphereGeometry(145, 32, 20);
const skyPosition = skyGeometry.attributes.position;
const skyColors = [];
const horizon = new THREE.Color(0x1b3538);
const zenith = new THREE.Color(0x07121f);
for (let i = 0; i < skyPosition.count; i++) {
  const t = THREE.MathUtils.clamp((skyPosition.getY(i) + 7) / 58, 0, 1);
  const c = horizon.clone().lerp(zenith, t);
  skyColors.push(c.r, c.g, c.b);
}
skyGeometry.setAttribute('color', new THREE.Float32BufferAttribute(skyColors, 3));
const sky = new THREE.Mesh(skyGeometry, new THREE.MeshBasicMaterial({
  vertexColors: true, side: THREE.BackSide, fog: false, depthWrite: false, toneMapped: false
}));
sky.renderOrder = -1000;
scene.add(sky);

// Stars are spread all around the horizon, so they remain visible while orbiting.
function makeStars(count, size, color) {
  const positions = [];
  for (let i = 0; i < count; i++) {
    const a = random() * Math.PI * 2;
    const elevation = between(0.012, 0.57);
    const r = between(113, 125);
    positions.push(Math.cos(a) * Math.cos(elevation) * r, Math.sin(elevation) * r, Math.sin(a) * Math.cos(elevation) * r);
  }
  const geometry = new THREE.BufferGeometry();
  geometry.setAttribute('position', new THREE.Float32BufferAttribute(positions, 3));
  const points = new THREE.Points(geometry, new THREE.PointsMaterial({
    color, size, sizeAttenuation: false, transparent: true, opacity: 0.78,
    fog: false, depthWrite: false, toneMapped: false
  }));
  scene.add(points);
}
makeStars(700, 1.4, 0xc9dfe1);
makeStars(65, 2.2, 0xf4e8cb);

function radialTexture() {
  const canvas = document.createElement('canvas');
  canvas.width = 128;
  canvas.height = 128;
  const context = canvas.getContext('2d');
  const gradient = context.createRadialGradient(64, 64, 0, 64, 64, 64);
  gradient.addColorStop(0, 'rgba(255,255,255,1)');
  gradient.addColorStop(0.12, 'rgba(255,255,255,0.78)');
  gradient.addColorStop(0.42, 'rgba(255,255,255,0.17)');
  gradient.addColorStop(1, 'rgba(255,255,255,0)');
  context.fillStyle = gradient;
  context.fillRect(0, 0, 128, 128);
  return new THREE.CanvasTexture(canvas);
}
const glowTexture = radialTexture();

// Moon, with a few subtle flat crater marks.
const moon = new THREE.Group();
moon.position.set(24, 13, -70);
const moonGlow = new THREE.Sprite(new THREE.SpriteMaterial({
  map: glowTexture, color: 0xf8e8b9, transparent: true, opacity: 0.30,
  blending: THREE.AdditiveBlending, depthWrite: false, fog: false, toneMapped: false
}));
moonGlow.scale.set(13, 13, 1);
moon.add(moonGlow);
const moonDisc = new THREE.Mesh(
  new THREE.SphereGeometry(2.45, 24, 16),
  new THREE.MeshBasicMaterial({ color: 0xf6e7c4, fog: false, toneMapped: false })
);
moon.add(moonDisc);
const craterMaterial = new THREE.MeshBasicMaterial({
  color: 0xb4a88f, transparent: true, opacity: 0.18,
  side: THREE.DoubleSide, fog: false, toneMapped: false
});
[[-0.78, 0.7, 0.38], [0.52, 0.2, 0.29], [-0.1, -0.9, 0.46], [1.0, -0.65, 0.18], [-1.25, -0.28, 0.2]].forEach(([x, y, r]) => {
  const mark = new THREE.Mesh(new THREE.CircleGeometry(r, 9), craterMaterial);
  mark.position.set(x, y, Math.sqrt(2.45 * 2.45 - x * x - y * y) + 0.012);
  moon.add(mark);
});
scene.add(moon);

// Moonlight and the firelight play across the clearing.
scene.add(new THREE.HemisphereLight(0x9bb9c4, 0x27342a, 0.65));
const moonlight = new THREE.DirectionalLight(0x9ebac6, 0.8);
moonlight.position.set(-12, 24, 10);
scene.add(moonlight);
const fireLight = new THREE.PointLight(0xff8138, 58, 23, 2);
fireLight.position.set(0, 2.15, 0);
fireLight.castShadow = true;
fireLight.shadow.mapSize.set(1024, 1024);
fireLight.shadow.camera.near = 0.25;
fireLight.shadow.camera.far = 23;
fireLight.shadow.bias = -0.001;
fireLight.shadow.normalBias = 0.035;
scene.add(fireLight);
const fireFill = new THREE.PointLight(0xff4f18, 8, 9, 2);
fireFill.position.set(0, 0.8, 0);
scene.add(fireFill);

// Faceted terrain, with a warmer patch where the trees give way to the clearing.
const groundGeometry = new THREE.PlaneGeometry(110, 110, 76, 76);
groundGeometry.rotateX(-Math.PI / 2);
const groundFlat = groundGeometry.toNonIndexed();
groundGeometry.dispose();
const gp = groundFlat.attributes.position;
const groundColors = new Float32Array(gp.count * 3);
const clearingColor = new THREE.Color(0x405044);
const forestColor = new THREE.Color(0x1c3935);
for (let i = 0; i < gp.count; i += 3) {
  let cx = 0, cz = 0;
  for (let j = 0; j < 3; j++) {
    const x = gp.getX(i + j), z = gp.getZ(i + j);
    gp.setY(i + j, groundHeight(x, z));
    cx += x / 3;
    cz += z / 3;
  }
  const d = Math.sqrt(cx * cx + cz * cz);
  const mix = THREE.MathUtils.smoothstep(d, 6.3, 13.5);
  const c = clearingColor.clone().lerp(forestColor, mix).multiplyScalar(between(0.86, 1.13));
  for (let j = 0; j < 3; j++) {
    groundColors[(i + j) * 3] = c.r;
    groundColors[(i + j) * 3 + 1] = c.g;
    groundColors[(i + j) * 3 + 2] = c.b;
  }
}
groundFlat.setAttribute('color', new THREE.BufferAttribute(groundColors, 3));
groundFlat.computeVertexNormals();
const ground = new THREE.Mesh(groundFlat, new THREE.MeshStandardMaterial({
  vertexColors: true, roughness: 1, flatShading: true
}));
ground.receiveShadow = true;
scene.add(ground);

// One shared, faceted four-tier pine shape.
function makePineGeometry() {
  const vertices = [], colors = [];
  const tiers = [
    [0.15, 0.57, 0.235],
    [0.30, 0.72, 0.195],
    [0.46, 0.86, 0.155],
    [0.61, 1.02, 0.115]
  ];
  const sides = 7;
  function addVertex(x, y, z, shade) {
    vertices.push(x, y, z);
    colors.push(shade, shade, shade);
  }
  tiers.forEach(([bottom, top, radius], layer) => {
    for (let i = 0; i < sides; i++) {
      const a = (i / sides) * Math.PI * 2 + layer * 0.16;
      const b = ((i + 1) / sides) * Math.PI * 2 + layer * 0.16;
      const shade = 0.72 + ((i * 3 + layer * 2) % 7) * 0.045;
      addVertex(Math.cos(a) * radius, bottom, Math.sin(a) * radius, shade);
      addVertex(Math.cos(b) * radius, bottom, Math.sin(b) * radius, shade);
      addVertex(0, top, 0, shade);
      addVertex(0, bottom, 0, 0.56);
      addVertex(Math.cos(b) * radius, bottom, Math.sin(b) * radius, 0.56);
      addVertex(Math.cos(a) * radius, bottom, Math.sin(a) * radius, 0.56);
    }
  });
  const geometry = new THREE.BufferGeometry();
  geometry.setAttribute('position', new THREE.Float32BufferAttribute(vertices, 3));
  geometry.setAttribute('color', new THREE.Float32BufferAttribute(colors, 3));
  geometry.computeVertexNormals();
  return geometry;
}
const pineGeometry = makePineGeometry();
const trunkGeometry = new THREE.CylinderGeometry(0.025, 0.042, 0.36, 7);
trunkGeometry.translate(0, 0.18, 0);
const trunkMaterial = new THREE.MeshStandardMaterial({ color: 0x554738, roughness: 1, flatShading: true });
const pineMaterials = [0x315c4f, 0x285247, 0x244a41, 0x355c4d, 0x21463e].map(color =>
  new THREE.MeshStandardMaterial({ color, vertexColors: true, roughness: 1, flatShading: true, side: THREE.DoubleSide })
);
const treePositions = [];
function addTree(x, z, height) {
  const tree = new THREE.Group();
  const trunk = new THREE.Mesh(trunkGeometry, trunkMaterial);
  const foliage = new THREE.Mesh(pineGeometry, pineMaterials[Math.floor(random() * pineMaterials.length)]);
  foliage.rotation.y = random() * Math.PI * 2;
  trunk.castShadow = Math.hypot(x, z) < 15;
  foliage.castShadow = Math.hypot(x, z) < 15;
  foliage.receiveShadow = true;
  tree.add(trunk, foliage);
  tree.position.set(x, groundHeight(x, z), z);
  tree.scale.setScalar(height);
  scene.add(tree);
  treePositions.push([x, z]);
}
[
  [-10.5, 2.0, 10.2], [11.2, 1.0, 10.7],
  [-8.6, -8.7, 8.7], [-4.6, -11.5, 9.2],
  [0, -12.7, 10.0], [4.3, -12.0, 8.1],
  [15.2, -10.3, 10.8], [-14.5, -10.8, 10.5]
].forEach(t => addTree(...t));

let attempts = 0;
while (treePositions.length < 53 && attempts++ < 2500) {
  const a = random() * Math.PI * 2;
  const r = between(10.2, 31);
  const x = Math.cos(a) * r;
  const z = Math.sin(a) * r;
  if (z > 5.5 && Math.abs(x) < 10) continue;
  // Leave a small window through the canopy for the moon.
  if (z < 0 && Math.abs(x - (20.5 - z) * 0.265) < 2.7) continue;
  if (treePositions.some(([tx, tz]) => Math.hypot(tx - x, tz - z) < 3.0)) continue;
  addTree(x, z, between(6.8, 11.8));
}

// Scattered blades of grass, kept out of the fire ring.
const grassVertices = new Float32Array([
  0,0,0, -0.075,0,0, -0.11,0.42,0,
  0,0,0, 0.075,0,0, 0.13,0.32,0,
  0,0,-0.05, 0,0,0.05, 0.015,0.36,0.10
]);
const grassGeometry = new THREE.BufferGeometry();
grassGeometry.setAttribute('position', new THREE.BufferAttribute(grassVertices, 3));
grassGeometry.computeVertexNormals();
const grass = new THREE.InstancedMesh(grassGeometry, new THREE.MeshStandardMaterial({
  color: 0x56745b, roughness: 1, side: THREE.DoubleSide, flatShading: true
}), 170);
const dummy = new THREE.Object3D();
for (let i = 0; i < 170; i++) {
  const a = random() * Math.PI * 2;
  const r = between(4.8, 14.5);
  const x = Math.cos(a) * r, z = Math.sin(a) * r;
  dummy.position.set(x, groundHeight(x, z) + 0.015, z);
  dummy.rotation.set(0, random() * Math.PI, 0);
  dummy.scale.setScalar(between(0.45, 1.2));
  dummy.updateMatrix();
  grass.setMatrixAt(i, dummy.matrix);
}
grass.instanceMatrix.needsUpdate = true;
scene.add(grass);

// Rocks in the clearing and a close ring around the hearth.
const rockGeometry = new THREE.DodecahedronGeometry(1, 0);
const rockMaterials = [0x69746c, 0x777c6e, 0x626e69, 0x858273].map(color =>
  new THREE.MeshStandardMaterial({ color, roughness: 1, flatShading: true })
);
function rock(x, z, sx, sy, sz, rotation = 0) {
  const mesh = new THREE.Mesh(rockGeometry, rockMaterials[Math.floor(random() * rockMaterials.length)]);
  mesh.position.set(x, groundHeight(x, z) + sy * 0.57, z);
  mesh.scale.set(sx, sy, sz);
  mesh.rotation.set(between(-0.15, 0.15), rotation, between(-0.12, 0.12));
  mesh.castShadow = true;
  mesh.receiveShadow = true;
  scene.add(mesh);
  return mesh;
}
[
  [-5.4, -1.5, 0.8, 0.46, 0.65], [-5.7, 3.6, 0.55, 0.32, 0.52],
  [5.5, 2.6, 0.85, 0.5, 0.65], [4.9, -4.4, 0.6, 0.35, 0.55],
  [-2.5, -5.5, 0.55, 0.33, 0.46], [7.2, -1.2, 0.44, 0.28, 0.36],
  [-7.0, -5.5, 0.68, 0.38, 0.58]
].forEach(v => rock(...v, random() * 3));

const ash = new THREE.Mesh(
  new THREE.CylinderGeometry(1.48, 1.48, 0.06, 12),
  new THREE.MeshStandardMaterial({ color: 0x282722, roughness: 1, flatShading: true })
);
ash.position.y = 0.045;
ash.receiveShadow = true;
scene.add(ash);
for (let i = 0; i < 13; i++) {
  const a = i / 13 * Math.PI * 2 + between(-0.07, 0.07);
  const r = between(1.36, 1.46);
  rock(Math.cos(a) * r, Math.sin(a) * r, between(0.34, 0.45), between(0.26, 0.35), between(0.32, 0.43), a);
}

// Cut logs, with visible end grain and a few simple bark ridges.
const barkMaterial = new THREE.MeshStandardMaterial({ color: 0x5c3929, roughness: 1, flatShading: true });
const barkRidgeMaterial = new THREE.MeshStandardMaterial({ color: 0x3a281f, roughness: 1, flatShading: true });
const cutMaterial = new THREE.MeshStandardMaterial({ color: 0xb08255, roughness: 1, flatShading: true });
const ringMaterial = new THREE.MeshBasicMaterial({ color: 0x785438, side: THREE.DoubleSide });
function addLog(x, z, length, radius, angle, y, details = true) {
  const group = new THREE.Group();
  const cylinder = new THREE.Mesh(new THREE.CylinderGeometry(radius, radius * 1.05, length, 8), [barkMaterial, cutMaterial, cutMaterial]);
  cylinder.castShadow = true;
  cylinder.receiveShadow = true;
  group.add(cylinder);
  if (details) {
    for (let i = 0; i < 5; i++) {
      const a = i * Math.PI * 2 / 5 + 0.3;
      const ridge = new THREE.Mesh(new THREE.CylinderGeometry(radius * 0.035, radius * 0.035, length * 0.94, 4), barkRidgeMaterial);
      ridge.position.set(Math.cos(a) * radius * 0.98, 0, Math.sin(a) * radius * 0.98);
      group.add(ridge);
    }
    for (const side of [-1, 1]) {
      for (const rr of [0.42, 0.72]) {
        const ring = new THREE.Mesh(new THREE.RingGeometry(radius * rr, radius * rr + 0.012, 8), ringMaterial);
        ring.rotation.x = Math.PI / 2;
        ring.position.y = side * (length / 2 + 0.008);
        group.add(ring);
      }
    }
  }
  const direction = new THREE.Vector3(Math.cos(angle), 0, Math.sin(angle));
  group.quaternion.setFromUnitVectors(new THREE.Vector3(0, 1, 0), direction);
  group.position.set(x, y, z);
  scene.add(group);
}
addLog(-3.7, 2.7, 3.0, 0.36, -0.28, 0.36);
addLog(3.8, -0.6, 2.7, 0.33, 1.15, 0.34);
addLog(-0.6, -4.5, 2.2, 0.25, 0.15, 0.26);
addLog(0, 0, 2.15, 0.18, 0.28, 0.22, false);
addLog(0.04, 0.02, 2.1, 0.17, -0.85, 0.26, false);
addLog(-0.04, -0.03, 1.9, 0.17, 1.8, 0.3, false);

// Little glowing coals beneath the flames.
const coalGeometry = new THREE.IcosahedronGeometry(1, 0);
const coalMaterials = [0xb83113, 0xe75118, 0xff8522].map(color =>
  new THREE.MeshBasicMaterial({ color, toneMapped: false })
);
for (let i = 0; i < 19; i++) {
  const a = random() * Math.PI * 2, r = between(0.2, 1.0);
  const coal = new THREE.Mesh(coalGeometry, coalMaterials[Math.floor(random() * coalMaterials.length)]);
  coal.position.set(Math.cos(a) * r, between(0.12, 0.27), Math.sin(a) * r);
  coal.scale.set(between(0.06, 0.16), between(0.035, 0.09), between(0.06, 0.13));
  scene.add(coal);
}

// Low-poly, vertex-colored flame tongues.
function flameGeometry(radius, height, palette) {
  const positions = [], colors = [];
  const levels = [
    [0, 0.40, 0],
    [0.13, 1.0, 0],
    [0.39, 0.72, 0.04],
    [0.70, 0.34, -0.05],
    [1.0, 0.005, 0.16]
  ];
  const cols = palette.map(c => new THREE.Color(c));
  const sides = 7;
  function point(level, angle, faceShade) {
    const [y, r, offset] = levels[level];
    positions.push(Math.cos(angle) * r * radius + offset * radius, y * height, Math.sin(angle) * r * radius);
    const c = cols[level].clone().multiplyScalar(faceShade);
    colors.push(c.r, c.g, c.b);
  }
  for (let l = 0; l < levels.length - 1; l++) {
    for (let i = 0; i < sides; i++) {
      const a = i * Math.PI * 2 / sides;
      const b = (i + 1) * Math.PI * 2 / sides;
      const shade = 0.91 + (i % 3) * 0.045;
      point(l, a, shade); point(l, b, shade); point(l + 1, b, shade);
      point(l, a, shade); point(l + 1, b, shade); point(l + 1, a, shade);
    }
  }
  const g = new THREE.BufferGeometry();
  g.setAttribute('position', new THREE.Float32BufferAttribute(positions, 3));
  g.setAttribute('color', new THREE.Float32BufferAttribute(colors, 3));
  return g;
}
const flameMaterial = new THREE.MeshBasicMaterial({ vertexColors: true, side: THREE.DoubleSide, toneMapped: false });
const outerPalette = [0xffc44d, 0xff9b29, 0xf66b1c, 0xe64514, 0xb52912];
const innerPalette = [0xfff4ab, 0xffe268, 0xffbe32, 0xff8d1d, 0xf45d15];
const flames = [];
function addFlame(x, z, radius, height, palette, phase) {
  const mesh = new THREE.Mesh(flameGeometry(radius, height, palette), flameMaterial);
  mesh.position.set(x, 0.24, z);
  scene.add(mesh);
  flames.push({ mesh, phase });
}
addFlame(0, -0.05, 0.67, 2.55, outerPalette, 0);
addFlame(-0.48, 0.02, 0.40, 1.65, outerPalette, 1.7);
addFlame(0.47, -0.08, 0.38, 1.75, outerPalette, 3.1);
addFlame(-0.08, 0.37, 0.40, 1.55, innerPalette, 0.8);
addFlame(0.35, 0.30, 0.24, 1.08, innerPalette, 2.2);

const fireGlow = new THREE.Sprite(new THREE.SpriteMaterial({
  map: glowTexture, color: 0xff7029, transparent: true, opacity: 0.28,
  blending: THREE.AdditiveBlending, depthWrite: false, toneMapped: false
}));
fireGlow.position.set(0, 1.35, -0.48);
fireGlow.scale.set(5.5, 5.5, 1);
scene.add(fireGlow);

// A tiny rising particle system, already distributed through the air at first paint.
const sparkCount = 65;
const sparkPositions = new Float32Array(sparkCount * 3);
const sparkColors = new Float32Array(sparkCount * 3);
const sparkData = [];
for (let i = 0; i < sparkCount; i++) {
  sparkData.push({
    phase: random(), speed: between(0.12, 0.25),
    x: between(-0.34, 0.34), z: between(-0.3, 0.3),
    drift: between(-0.4, 0.5), wobble: between(0, 6.28)
  });
  const c = new THREE.Color(random() > 0.5 ? 0xffa53c : 0xffd573);
  sparkColors[i * 3] = c.r; sparkColors[i * 3 + 1] = c.g; sparkColors[i * 3 + 2] = c.b;
}
const sparkGeometry = new THREE.BufferGeometry();
sparkGeometry.setAttribute('position', new THREE.BufferAttribute(sparkPositions, 3));
sparkGeometry.setAttribute('color', new THREE.BufferAttribute(sparkColors, 3));
const sparks = new THREE.Points(sparkGeometry, new THREE.PointsMaterial({
  size: 0.105, map: glowTexture, vertexColors: true, transparent: true, opacity: 0.95,
  blending: THREE.AdditiveBlending, depthWrite: false, toneMapped: false
}));
sparks.frustumCulled = false;
scene.add(sparks);

// Wisps of smoke, softened so the low-poly flames remain the focus.
const smoke = [];
for (let i = 0; i < 5; i++) {
  const puff = new THREE.Sprite(new THREE.SpriteMaterial({
    map: glowTexture, color: 0x899a94, transparent: true, opacity: 0.085,
    depthWrite: false
  }));
  scene.add(puff);
  smoke.push(puff);
}

function resize() {
  const width = window.innerWidth, height = window.innerHeight;
  camera.aspect = width / height;
  camera.fov = width < 600 ? 64 : 43;
  camera.updateProjectionMatrix();
  renderer.setPixelRatio(Math.min(window.devicePixelRatio, 1.75));
  renderer.setSize(width, height);
}
window.addEventListener('resize', resize);
resize();

const clock = new THREE.Clock();
function animate() {
  requestAnimationFrame(animate);
  const t = clock.getElapsedTime();
  controls.update();
  moon.lookAt(camera.position);

  flames.forEach(({ mesh, phase }) => {
    mesh.scale.y = 0.94 + 0.09 * Math.sin(t * 6.4 + phase) + 0.035 * Math.sin(t * 11.2 + phase);
    mesh.scale.x = 0.98 + 0.06 * Math.sin(t * 5.1 + phase);
    mesh.rotation.z = 0.045 * Math.sin(t * 4.0 + phase);
    mesh.rotation.x = 0.025 * Math.cos(t * 3.7 + phase);
  });
  fireLight.intensity = 55 + 7 * Math.sin(t * 8.3) + 4 * Math.sin(t * 13.7 + 1);
  fireFill.intensity = 8 + 1.5 * Math.sin(t * 7.2);
  fireGlow.material.opacity = 0.25 + 0.035 * Math.sin(t * 6.5);

  for (let i = 0; i < sparkCount; i++) {
    const s = sparkData[i];
    const p = (s.phase + t * s.speed) % 1;
    sparkPositions[i * 3] = s.x + s.drift * p + Math.sin(t * 2 + s.wobble) * 0.11 * p;
    sparkPositions[i * 3 + 1] = 0.45 + p * 4.7;
    sparkPositions[i * 3 + 2] = s.z + Math.cos(t * 1.6 + s.wobble) * 0.14 * p;
  }
  sparkGeometry.attributes.position.needsUpdate = true;

  smoke.forEach((puff, i) => {
    const p = ((t * 0.035 + i / smoke.length) % 1);
    puff.position.set(0.1 + p * 1.0 + Math.sin(t * 0.7 + i) * 0.12, 2.9 + p * 3.3, -0.3);
    const scale = 1.0 + p * 1.8;
    puff.scale.set(scale, scale, 1);
    puff.material.opacity = 0.075 * Math.sin(p * Math.PI);
  });
  renderer.render(scene, camera);
}
animate();
</script>
</body>
</html>
Reasoning trace (11,094 tokens)
**Configuring lighting parameters**

I'm considering PointLight shadows and the importance of intensity values for physically correct lighting. I want to add ambient and hemispheric light to illuminate a tree, aiming for a warm light radius around 22 with an intensity of 80 and a decay of 2, making the effective intensity around 5. For tone mapping, I'm looking at three color tones with ACES and an exposure of 1.2. The main point light has an intensity between 45-70, creating a night scene with a visible blue under moonlight with specific intensities.**Designing a tree layout**

I'm thinking about reducing the background trees to around 7 or 9 to create a clear star patch at the center or top of the scene. It's important that the trees are visually attractive, with distinctive variations in size and a dark emerald blue color. The lighting should balance between cool moonlight and warm fire. I want to ensure the arrangement spreads 38 trees within a radius of 10-25, while considering proximity and placement to avoid blocking key views.**Arranging the tree layout**

I'm planning to create about 48 trees in a loop with a radius of random values between 10.5 and 29, incorporating variable heights. In the background, I might have around a dozen trees, while the rest will be positioned far enough to be invisible but still counted. I’ll manually frame the hero with trees at coordinates like x ±12 and z4, ensuring they're in the camera view. The main visual focus of the scene will be the fire highlighting the hero.**Creating visual effects**

I'm thinking about how to create visual layering with flame cone animations featuring those jagged tongues, which sounds really dynamic! I want to use a ring lathe to generate geometries and arrange fire object meshes in groups at different x and z positions. Also, I'm considering using ConeGeometry with specific parameters, like radius and height, and translating it up to create the effect of a simple triangle. This could look pretty cool!**Evaluating particle system settings**

I’m looking at a sparks particle system that animates 80 points within a fire effect, focusing on warm color gradients and random positions. The point sizes will range from 3 to 5 pixels. I’m considering enabling size attenuation for the PointsMaterial, with a size setting of around 0.065 to ensure they appear about 3 pixels from a distance of 20. I'll also make sure the colors vary to enhance the effect.**Designing the moon scene**

I'm working on creating a moon scene, using a MeshBasic material that is double-sided and has no shading. The moon will be circular with a radius of 2.8, and I want it positioned to look at the camera. I’m planning to add small light gold craters with some opacity. I’m thinking of a large glowing sprite with a radial gradient in the sky, placing the moon behind a tree and adjusting its position near the top right corner of the screen.**Calculating tree positions and visibility**

I need to look at a 27:90 ratio to see if trees might obscure the moon's visibility, targeting a position at x=27. I could check the trees near the moon and keep a gap for visibility. If I set the moon at x=27 and adjust z and x ratios properly, I can create a system to reserve space for it. I'll avoid placing trees where they might obstruct the moon’s view and ensure there's enough clearance overall.**Setting the Background Color**

I'm thinking about implementing the background in my scene. I want to use sky, and I’ve chosen the color `THREE.Color` 0x081722. This deep hue could set a nice mood, possibly resembling a twilight or deep ocean effect. It’ll be interesting to see how this color complements the other elements in the scene. I just need to make sure it fits well visually! I'll keep exploring how this background enhances the overall aesthetic.**Organizing tree distribution**

I'm planning to manually create three clusters of trees. The first cluster will be a back line positioned between z -8.8 to -14, with an x range spanning -22 to 22, while maintaining a spacing of 3.2 units. I need to skip a tree at x9 to preserve the moon gap. The second cluster will have 38 trees placed randomly within a ring of radius 10-28, excluding areas for camera visibility where z > 5 and abs(x) < 8.5.**Refining visual effects**

I'm working on a scene with a light source connected to white stone, trying to manage the tones and brightness. It seems the flames’ basic vertex colors could use some adjustment under tone mapping, while keeping colors bright in MeshBasicMaterial without tone mapping. I’m thinking of adding ember fills and sparks above the flames, and maybe some smoke particles to enhance the atmosphere—low-poly gray puffs moving above the fire, though I’m aware they could obscure the stars. This will help create a more immersive camping fire experience!**Designing visual elements**

I'm setting up six blue-grey transparent sprites with a gradient canvas positioned between 0 and 5.5 units. I'll keep uniform opacity, but I'm contemplating whether to use individual materials for animation or stick to a single one. There will be transparent depth sorting to keep things clean. I’ll also add smoke glows, ensuring they don't obscure the fire too much. I'll overlay a gradient vignette through CSS for a softer touch, keeping everything neat within the specified HTML and CSS without external fonts. Got to make sure the layout is visually engaging!**Creating UI elements**

I need to avoid taking a screenshot at the center, focusing on the bottom right for the "DRAG TO ORBIT" text along with a tiny mouse SVG to enhance the user experience. Since the user wants OrbitControls, I’ll make sure the UI enables scroll zoom and touch gestures. At the top, I’ll add the title “AN INTERACTIVE LANDSCAPE” in Georgia serif font, white at size 39 to ensure it stands out. This should help create a visually appealing interface!**Adjusting mobile camera settings**

I'm considering how the top of the mobile title obscures the sky, but it’s fine. I might set the camera distance to be adaptive while keeping the field of view (FOV) at 55 and width at 10.3. The moon's position needs adjustments, and using a FOV of 65 could help place it better. I want to determine if full code is needed and could add detailed ember geometry with color and logs under the fire. Time's still ample for this!**Adding details to logs**

I’m thinking about adding narrow bark seams along the length of the logs. To do this, I need to position cylinder lines around using local coordinates. This should enhance the texture and overall look of the logs, making them appear more realistic. I’ll want to ensure that the seams are set correctly so they align well with the log’s surface. It feels like a small detail, but it should add a lot to the final appearance!**Considering camera controls**

I'm thinking about the camera orbiting the moon and how it can let the user view the backside of the moon craters. I could update the rotation settings if needed, but the spherical moon is looking good. It's important that as the crater group rotates toward the camera every frame, the whole sphere still maintains its orientation. Setting the entire group's position to look at the camera might be the way to go for consistent results.