Models 44

GPT-6 Luna

by OpenAIReasoningClean
Open in new window

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

How it went

Total time
30.9 s
Cost
$0.0021
Output tokens
4,135
Spent thinking
0 tokens
Speed
140.3 tok/s
Console errors
0
First token after
1.4 s
First visible text after
1.4 s
Prompt tokens
555
Code size
13.3 KB
Finish reason
stop
Served by
OpenAI
Model id
openai/gpt-6-luna
Reasoning sent
{"effort":"none"}
Max output
64,000 tokens
Generated
Nov 10, 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 · 328 lines

<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Moonlit Campfire</title>
<style>
  * { box-sizing: border-box; }
  html, body { width:100%; height:100%; margin:0; overflow:hidden; background:#07101c; }
  body { font-family: Georgia, "Times New Roman", serif; color:#f2e5cf; }
  canvas { display:block; width:100%; height:100%; }
  .title {
    position:fixed; top:25px; left:30px; z-index:2; pointer-events:none;
    text-shadow:0 2px 14px #000;
  }
  .title .eyebrow {
    font:600 10px/1.2 system-ui, sans-serif; letter-spacing:.28em;
    color:#d5a866; text-transform:uppercase; margin-bottom:7px;
  }
  .title h1 { font-size:27px; font-weight:400; letter-spacing:.025em; margin:0; }
  .hint {
    position:fixed; right:28px; bottom:24px; z-index:2;
    font:11px/1.5 system-ui,sans-serif; letter-spacing:.08em;
    color:rgba(235,222,201,.65); text-align:right; pointer-events:none;
  }
  .hint span { color:#e3b66f; }
  @media(max-width:600px) {
    .title { top:17px; left:18px; }
    .title h1 { font-size:21px; }
    .hint { right:16px; bottom:15px; font-size:10px; }
  }
</style>
</head>
<body>
<div class="title"><div class="eyebrow">Nocturne · 07</div><h1>The Quiet Clearing</h1></div>
<div class="hint"><span>DRAG</span> look around &nbsp;·&nbsp; <span>SCROLL</span> zoom</div>
<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>
<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(0x08111f);
scene.fog = new THREE.FogExp2(0x101b29, 0.027);

const camera = new THREE.PerspectiveCamera(48, innerWidth / innerHeight, 0.1, 180);
camera.position.set(0, 7.5, 17);

const renderer = new THREE.WebGLRenderer({ antialias:true, powerPreference:'high-performance' });
renderer.setPixelRatio(Math.min(devicePixelRatio, 1.7));
renderer.setSize(innerWidth, innerHeight);
renderer.shadowMap.enabled = true;
renderer.shadowMap.type = THREE.PCFSoftShadowMap;
renderer.outputColorSpace = THREE.SRGBColorSpace;
renderer.toneMapping = THREE.ACESFilmicToneMapping;
renderer.toneMappingExposure = 1.15;
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.045;
controls.minDistance = 8;
controls.maxDistance = 30;
controls.minPolarAngle = 0.2;
controls.maxPolarAngle = Math.PI * 0.47;
controls.update();

scene.add(new THREE.HemisphereLight(0x8494bd, 0x171a1b, 0.62));
const moonLight = new THREE.DirectionalLight(0x94add6, 1.35);
moonLight.position.set(-9, 16, -7);
moonLight.castShadow = true;
moonLight.shadow.mapSize.set(2048, 2048);
moonLight.shadow.camera.left = -23;
moonLight.shadow.camera.right = 23;
moonLight.shadow.camera.top = 23;
moonLight.shadow.camera.bottom = -23;
moonLight.shadow.bias = -0.0005;
scene.add(moonLight);

const groundMat = new THREE.MeshStandardMaterial({ color:0x28332e, roughness:1, flatShading:true });
const ground = new THREE.Mesh(new THREE.PlaneGeometry(100,100,36,36), groundMat);
ground.rotation.x = -Math.PI/2;
ground.position.y = -0.04;
ground.receiveShadow = true;
scene.add(ground);

// Subtle uneven forest floor, with broad, low-poly patches.
const patchMat = [
  new THREE.MeshStandardMaterial({color:0x354137, roughness:1, flatShading:true}),
  new THREE.MeshStandardMaterial({color:0x202c2a, roughness:1, flatShading:true}),
  new THREE.MeshStandardMaterial({color:0x394033, roughness:1, flatShading:true})
];
for(let i=0;i<54;i++){
  const r=1.5+Math.random()*4.2, a=Math.random()*Math.PI*2;
  const g=new THREE.CircleGeometry(r,7);
  const m=new THREE.Mesh(g,patchMat[i%patchMat.length]);
  m.rotation.x=-Math.PI/2;
  m.rotation.z=Math.random()*Math.PI;
  m.position.set(Math.cos(a)*(4+Math.random()*28),0.006+Math.random()*0.004,Math.sin(a)*(4+Math.random()*28));
  m.scale.set(1+Math.random(),.7+Math.random()*.8,1);
  m.receiveShadow=true;
  scene.add(m);
}

const barkMat = [
  new THREE.MeshStandardMaterial({color:0x40342d,roughness:1,flatShading:true}),
  new THREE.MeshStandardMaterial({color:0x584334,roughness:1,flatShading:true}),
  new THREE.MeshStandardMaterial({color:0x302d2b,roughness:1,flatShading:true})
];
const leafMats = [
  new THREE.MeshStandardMaterial({color:0x152b29,roughness:1,flatShading:true}),
  new THREE.MeshStandardMaterial({color:0x1b3831,roughness:1,flatShading:true}),
  new THREE.MeshStandardMaterial({color:0x243c35,roughness:1,flatShading:true}),
  new THREE.MeshStandardMaterial({color:0x18272c,roughness:1,flatShading:true})
];
const trunkGeo=new THREE.CylinderGeometry(.25,.42,1,6,1);
const crownGeos=[
  new THREE.ConeGeometry(1,1,7,1),
  new THREE.IcosahedronGeometry(1,0)
];

function createTree(x,z,scale){
  const group=new THREE.Group();
  group.position.set(x,0,z);
  group.rotation.y=Math.random()*Math.PI;
  const h=(3.0+Math.random()*3.8)*scale;
  const trunk=new THREE.Mesh(trunkGeo,new THREE.MeshStandardMaterial({color:barkMat[Math.floor(Math.random()*barkMat.length)].color,roughness:1,flatShading:true}));
  trunk.position.y=h*.30; trunk.scale.set(scale,h*.68,scale); trunk.castShadow=true; trunk.receiveShadow=true;
  group.add(trunk);
  const variant=Math.random();
  if(variant<.75){
    for(let tier=0;tier<3;tier++){
      const size=(1.6-tier*.27)*scale*(.82+Math.random()*.3);
      const crown=new THREE.Mesh(crownGeos[0],leafMats[Math.floor(Math.random()*leafMats.length)]);
      crown.position.set((Math.random()-.5)*.28*scale,h*(.48+tier*.20),0);
      crown.scale.set(size,h*(.34+Math.random()*.07),size);
      crown.rotation.y=Math.random()*Math.PI;
      crown.castShadow=true; crown.receiveShadow=true;
      group.add(crown);
    }
  }else{
    for(let j=0;j<3;j++){
      const size=(1.05+Math.random()*.48)*scale;
      const crown=new THREE.Mesh(crownGeos[1],leafMats[Math.floor(Math.random()*leafMats.length)]);
      crown.position.set((Math.random()-.5)*.65*scale,h*(.67+j*.11), (Math.random()-.5)*.45*scale);
      crown.scale.set(size,size*1.15,size);
      crown.castShadow=true; crown.receiveShadow=true;
      group.add(crown);
    }
  }
  scene.add(group);
}
let planted=0, tries=0;
while(planted<74 && tries<1000){
  tries++;
  const a=Math.random()*Math.PI*2;
  const r=9+Math.random()*29;
  const x=Math.cos(a)*r, z=Math.sin(a)*r;
  // Keep a clearly open ring around the fire, with denser trees at the perimeter.
  if(Math.hypot(x,z)<9.5) continue;
  createTree(x,z,.78+Math.random()*.52);
  planted++;
}

// A few fallen branches and stones dress the clearing.
function makeLog(x,z,length,angle){
  const wood=new THREE.Mesh(new THREE.CylinderGeometry(.19,.23,length,7,1),barkMat[1]);
  wood.position.set(x,.21,z);
  wood.rotation.z=Math.PI/2;
  wood.rotation.y=angle;
  wood.castShadow=true; wood.receiveShadow=true;
  scene.add(wood);
  const endMat=new THREE.MeshStandardMaterial({color:0x927152,roughness:1,flatShading:true});
  for(const s of [-1,1]){
    const cap=new THREE.Mesh(new THREE.CylinderGeometry(.17,.17,.025,7),endMat);
    cap.position.set(x+Math.cos(angle)*length*.5*s,.21,z-Math.sin(angle)*length*.5*s);
    cap.rotation.z=Math.PI/2; cap.rotation.y=angle;
    scene.add(cap);
  }
}
makeLog(-4.8,2.1,2.4,-.42);
makeLog(4.8,2.7,2.2,.38);
makeLog(5.6,-2.2,1.6,-.55);

const rockMats=[
  new THREE.MeshStandardMaterial({color:0x555b58,roughness:1,flatShading:true}),
  new THREE.MeshStandardMaterial({color:0x69685f,roughness:1,flatShading:true}),
  new THREE.MeshStandardMaterial({color:0x414a4a,roughness:1,flatShading:true})
];
for(let i=0;i<13;i++){
  const a=i/13*Math.PI*2+(Math.random()-.5)*.22;
  const r=2.05+Math.random()*.38;
  const geo=new THREE.DodecahedronGeometry(.52+Math.random()*.25,0);
  const rock=new THREE.Mesh(geo,rockMats[Math.floor(Math.random()*rockMats.length)]);
  rock.position.set(Math.cos(a)*r,.28,Math.sin(a)*r);
  rock.scale.set(1.1,.72,.9);
  rock.rotation.set(Math.random()*.5,Math.random()*Math.PI,Math.random()*.4);
  rock.castShadow=true; rock.receiveShadow=true;
  scene.add(rock);
}

// Charred kindling beneath the flame.
const charMat=new THREE.MeshStandardMaterial({color:0x211b19,roughness:1,flatShading:true});
for(let i=0;i<5;i++){
  const log=new THREE.Mesh(new THREE.CylinderGeometry(.12,.15,2.4,6),charMat);
  const a=i*Math.PI/5;
  log.position.set(0,.3,0);
  log.rotation.set(.12,0,Math.PI/2);
  log.rotation.y=a;
  log.castShadow=true;
  scene.add(log);
}

// Stylized layered flame meshes, animated in place.
const flameMats=[
  new THREE.MeshBasicMaterial({color:0xff5a1b,transparent:true,opacity:.9,side:THREE.DoubleSide,depthWrite:false}),
  new THREE.MeshBasicMaterial({color:0xffa326,transparent:true,opacity:.92,side:THREE.DoubleSide,depthWrite:false}),
  new THREE.MeshBasicMaterial({color:0xffe081,transparent:true,opacity:.94,side:THREE.DoubleSide,depthWrite:false})
];
const flameGeo=new THREE.ConeGeometry(1,1,6,1);
const flames=[];
for(let i=0;i<7;i++){
  const mat=flameMats[i%3];
  const mesh=new THREE.Mesh(flameGeo,mat);
  const a=i/7*Math.PI*2;
  mesh.userData={a,phase:Math.random()*6.28,base:.72+Math.random()*.48,layer:i%3};
  mesh.position.set(Math.cos(a)*.28,.85,Math.sin(a)*.28);
  mesh.rotation.z=(Math.random()-.5)*.2;
  scene.add(mesh); flames.push(mesh);
}
const heart=new THREE.Mesh(new THREE.IcosahedronGeometry(.36,1),new THREE.MeshBasicMaterial({color:0xffc24e}));
heart.position.y=.63; scene.add(heart);

const fireLight=new THREE.PointLight(0xff7b2c,5.2,18,1.45);
fireLight.position.set(0,1.35,0);
fireLight.castShadow=true;
fireLight.shadow.mapSize.set(1024,1024);
fireLight.shadow.bias=-.003;
scene.add(fireLight);

// Sparks: small glowing points that rise, drift, and respawn.
const sparkCount=110;
const sparkPositions=new Float32Array(sparkCount*3);
const sparkColors=new Float32Array(sparkCount*3);
const sparkData=[];
for(let i=0;i<sparkCount;i++){
  sparkData.push({y:Math.random()*3.8,angle:Math.random()*Math.PI*2,r:Math.random()*.55,life:Math.random()});
}
const sparkGeom=new THREE.BufferGeometry();
sparkGeom.setAttribute('position',new THREE.BufferAttribute(sparkPositions,3));
sparkGeom.setAttribute('color',new THREE.BufferAttribute(sparkColors,3));
const sparkMat=new THREE.PointsMaterial({size:.075,vertexColors:true,transparent:true,opacity:.95,depthWrite:false,blending:THREE.AdditiveBlending,sizeAttenuation:true});
const sparks=new THREE.Points(sparkGeom,sparkMat);
scene.add(sparks);

// Moon and star field.
const moon=new THREE.Mesh(new THREE.SphereGeometry(1.55,16,12),new THREE.MeshBasicMaterial({color:0xe4e6d8}));
moon.position.set(-15,19,-38); scene.add(moon);
const halo=new THREE.Mesh(new THREE.SphereGeometry(2.25,16,12),new THREE.MeshBasicMaterial({color:0x8195ba,transparent:true,opacity:.09,side:THREE.BackSide,depthWrite:false}));
halo.position.copy(moon.position); scene.add(halo);

const starGeo=new THREE.BufferGeometry();
const starPos=[];
for(let i=0;i<400;i++){
  const x=(Math.random()-.5)*120, y=8+Math.random()*45, z=-28-Math.random()*72;
  starPos.push(x,y,z);
}
starGeo.setAttribute('position',new THREE.Float32BufferAttribute(starPos,3));
const stars=new THREE.Points(starGeo,new THREE.PointsMaterial({color:0xcbd4e7,size:.12,transparent:true,opacity:.85,sizeAttenuation:true}));
scene.add(stars);

// Small distant fir silhouettes softly dissolve into the night.
const distantMat=new THREE.MeshStandardMaterial({color:0x17232b,roughness:1,flatShading:true});
for(let i=0;i<24;i++){
  const a=Math.PI*2*i/24;
  const r=35+Math.random()*9;
  const tree=new THREE.Mesh(new THREE.ConeGeometry(1.8+Math.random(),6+Math.random()*4,6),distantMat);
  tree.position.set(Math.cos(a)*r,3,Math.sin(a)*r);
  tree.castShadow=false;
  scene.add(tree);
}

let time=0;
function animate(){
  requestAnimationFrame(animate);
  time+=0.016;
  for(let i=0;i<flames.length;i++){
    const f=flames[i], d=f.userData;
    const flicker=.85+Math.sin(time*11+d.phase)*.16+Math.sin(time*19+d.phase*1.7)*.1;
    f.scale.set((.34+d.layer*.07)*flicker,d.base*flicker*(.88+.12*Math.sin(time*8+d.phase)),(.34+d.layer*.07)*flicker);
    f.position.x=Math.cos(d.a+time*.35)*(.22+.06*Math.sin(time*7+d.phase));
    f.position.z=Math.sin(d.a+time*.35)*(.22+.06*Math.cos(time*9+d.phase));
    f.position.y=.66+d.layer*.14+.07*Math.sin(time*12+d.phase);
    f.rotation.y=time*.7+d.a;
  }
  heart.scale.setScalar(.9+.12*Math.sin(time*13));
  fireLight.intensity=4.8+Math.sin(time*12)*.8+Math.sin(time*21+1.5)*.45;
  fireLight.position.x=Math.sin(time*3)*.12;
  for(let i=0;i<sparkCount;i++){
    const s=sparkData[i];
    s.y+=.025+Math.random()*.012;
    s.angle+=.012;
    s.r+=.003;
    if(s.y>4.8){s.y=.65;s.r=Math.random()*.2;s.angle=Math.random()*Math.PI*2;}
    const k=i*3;
    sparkPositions[k]=Math.cos(s.angle)*s.r;
    sparkPositions[k+1]=s.y;
    sparkPositions[k+2]=Math.sin(s.angle)*s.r;
    const bright=Math.max(.12,1-s.y/5);
    sparkColors[k]=1; sparkColors[k+1]=.42+bright*.35; sparkColors[k+2]=.08+bright*.08;
  }
  sparkGeom.attributes.position.needsUpdate=true;
  sparkGeom.attributes.color.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,1.7));
});
</script>
</body>
</html>