Models 44

Muse Ember

Open in new window

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

How it went

Total time
7.8 s
Cost
$0.0022
Output tokens
4,383
Spent thinking
157 tokens
Speed
710 tok/s
Console errors
0
First token after
1.6 s
First visible text after
1.6 s
Prompt tokens
574
Code size
12.5 KB
Finish reason
stop
Served by
Meta
Model id
meta/muse-ember
Reasoning sent
{"effort":"minimal"}
Max output
943,718 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 · 272 lines

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Campfire in the Forest — Low-Poly Night</title>
<style>
  *{margin:0;padding:0;box-sizing:border-box}
  html,body{width:100%;height:100%;overflow:hidden;background:#070b1a;font-family:system-ui,-apple-system,Segoe UI,Roboto,Helvetica,Arial,sans-serif}
  #app{position:fixed;inset:0}
  canvas{display:block}
  .hud{position:fixed;top:18px;left:18px;z-index:10;color:#fff;pointer-events:none;max-width:340px}
  .hud h1{font-size:26px;letter-spacing:.02em;line-height:1.05;text-shadow:0 2px 18px rgba(0,0,0,.8)}
  .hud h1 span{color:#ffb347}
  .hud p{margin-top:8px;font-size:13px;line-height:1.5;color:rgba(255,255,255,.82);text-shadow:0 1px 10px rgba(0,0,0,.8)}
  .badge{display:inline-flex;gap:6px;align-items:center;margin-top:12px;background:rgba(10,14,30,.55);backdrop-filter:blur(8px);border:1px solid rgba(255,255,255,.14);border-radius:999px;padding:7px 12px;font-size:12px;color:#dbe7ff}
  .dot{width:8px;height:8px;border-radius:50%;background:#ffb347;box-shadow:0 0 10px #ff8c1a;animation:pulse 1.6s infinite}
  @keyframes pulse{0%,100%{transform:scale(1);opacity:1}50%{transform:scale(1.4);opacity:.6}}
  .controls{position:fixed;left:50%;bottom:18px;transform:translateX(-50%);z-index:10;pointer-events:none;background:rgba(8,11,24,.6);backdrop-filter:blur(10px);border:1px solid rgba(255,255,255,.13);border-radius:999px;padding:9px 16px;color:#e8efff;font-size:13px;white-space:nowrap;box-shadow:0 8px 30px rgba(0,0,0,.5)}
  .controls b{color:#ffb347}
  .stats{position:fixed;top:18px;right:18px;z-index:10;display:flex;gap:8px;pointer-events:none}
  .stat{background:rgba(8,11,24,.55);backdrop-filter:blur(8px);border:1px solid rgba(255,255,255,.12);border-radius:14px;padding:10px 14px;color:#fff;text-align:center;min-width:78px}
  .stat strong{font-size:20px;display:block;color:#ffb347}
  .stat small{font-size:11px;letter-spacing:.08em;text-transform:uppercase;color:rgba(255,255,255,.65)}
  .vignette{position:fixed;inset:0;pointer-events:none;z-index:5;background:radial-gradient(ellipse at center,transparent 52%,rgba(2,4,14,.55) 100%)}
  @media(max-width:640px){
    .hud h1{font-size:21px}.hud p{display:none}.stats{display:none}.controls{font-size:12px;padding:8px 12px;max-width:92vw;white-space:normal;text-align:center}
  }
</style>
<script type="importmap">{"imports":{"three":"https://cdn.jsdelivr.net/npm/three@0.170.0/build/three.module.js","three/addons/":"https://cdn.jsdelivr.net/npm/three@0.170.0/examples/jsm/"}}</script>
</head>
<body>
<div id="app"></div>
<div class="vignette"></div>
<div class="hud">
  <h1>🏕️ Campfire<br>in the <span>Forest</span></h1>
  <p>A cozy low-poly clearing at night — flickering flames, rising sparks, and a ring of pine trees under the moon.</p>
  <div class="badge"><span class="dot"></span> Live • 38 trees • Sparks &amp; Shadows</div>
</div>
<div class="stats">
  <div class="stat"><strong id="fps">60</strong><small>FPS</small></div>
  <div class="stat"><strong>38</strong><small>Trees</small></div>
  <div class="stat"><strong id="temp">24°</strong><small>Fire °C</small></div>
</div>
<div class="controls">🖱️ <b>Drag</b> to orbit &nbsp;•&nbsp; <b>Scroll</b> to zoom &nbsp;•&nbsp; <b>Right-drag</b> to pan</div>

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

const container = document.getElementById('app');
const scene = new THREE.Scene();
scene.background = new THREE.Color(0x070b1a);
scene.fog = new THREE.Fog(0x0a1024, 18, 58);

const camera = new THREE.PerspectiveCamera(55, innerWidth/innerHeight, 0.1, 300);
camera.position.set(9, 6, 11);

const renderer = new THREE.WebGLRenderer({antialias:true});
renderer.setSize(innerWidth, innerHeight);
renderer.setPixelRatio(Math.min(devicePixelRatio, 2));
renderer.shadowMap.enabled = true;
renderer.shadowMap.type = THREE.PCFSoftShadowMap;
renderer.toneMapping = THREE.ACESFilmicToneMapping;
renderer.toneMappingExposure = 1.15;
container.appendChild(renderer.domElement);

const controls = new OrbitControls(camera, renderer.domElement);
controls.target.set(0, 1.2, 0);
controls.enableDamping = true;
controls.dampingFactor = 0.06;
controls.maxPolarAngle = Math.PI * 0.49;
controls.minPolarAngle = Math.PI * 0.15;
controls.minDistance = 4;
controls.maxDistance = 28;
controls.maxTargetRadius = 6;
controls.autoRotate = true;
controls.autoRotateSpeed = 0.6;
controls.addEventListener('start', ()=> controls.autoRotate = false);

// Lights
scene.add(new THREE.AmbientLight(0x334466, 0.7));
const moonLight = new THREE.DirectionalLight(0x8899cc, 0.5);
moonLight.position.set(-18, 24, -10);
moonLight.castShadow = true;
moonLight.shadow.mapSize.set(1024,1024);
scene.add(moonLight);

const fireLight = new THREE.PointLight(0xff7722, 28, 22, 1.6);
fireLight.position.set(0, 1.6, 0);
fireLight.castShadow = true;
fireLight.shadow.mapSize.set(1024,1024);
fireLight.shadow.bias = -0.004;
scene.add(fireLight);
const fireGlow = new THREE.PointLight(0xffaa33, 8, 10, 2);
fireGlow.position.set(0,0.8,0); scene.add(fireGlow);

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

// subtle clearing patch
const patch = new THREE.Mesh(new THREE.CircleGeometry(5.2, 24), new THREE.MeshStandardMaterial({color:0x3a2a18, roughness:1, flatShading:true}));
patch.rotation.x = -Math.PI/2; patch.position.y = 0.02; patch.receiveShadow = true; scene.add(patch);

// Rocks & logs around fire
const rockMat = new THREE.MeshStandardMaterial({color:0x7a7f8a, roughness:1, flatShading:true});
const logMat = new THREE.MeshStandardMaterial({color:0x5a3a1e, roughness:1, flatShading:true});
const logMat2 = new THREE.MeshStandardMaterial({color:0x6b4423, roughness:1, flatShading:true});

for(let i=0;i<10;i++){
  const a = (i/10)*Math.PI*2 + Math.random()*0.3;
  const r = 1.55 + Math.random()*0.15;
  const rock = new THREE.Mesh(new THREE.DodecahedronGeometry(0.32+Math.random()*0.18,0), rockMat);
  rock.position.set(Math.cos(a)*r, 0.18, Math.sin(a)*r);
  rock.rotation.set(Math.random()*3,Math.random()*3,Math.random()*3);
  rock.castShadow = rock.receiveShadow = true;
  scene.add(rock);
}
// scattered rocks
for(let i=0;i<14;i++){
  const a=Math.random()*Math.PI*2, r=3+Math.random()*16;
  const rock=new THREE.Mesh(new THREE.DodecahedronGeometry(0.25+Math.random()*0.55,0), rockMat);
  rock.position.set(Math.cos(a)*r,0.15,Math.sin(a)*r);
  rock.rotation.set(Math.random()*3,Math.random()*3,Math.random()*3);
  rock.castShadow=rock.receiveShadow=true;
  scene.add(rock);
}
// teepee logs + bench logs
for(let i=0;i<6;i++){
  const a=(i/6)*Math.PI*2;
  const log=new THREE.Mesh(new THREE.CylinderGeometry(0.09,0.11,1.5,7), i%2?logMat:logMat2);
  log.position.set(Math.cos(a)*0.35,0.65,Math.sin(a)*0.35);
  log.lookAt(0,1.6,0); log.rotateX(Math.PI/2);
  log.castShadow=true; scene.add(log);
}
[[-2.2,1.5,0.4],[2.3,-1.2,-0.3],[0.5,2.4,1.2]].forEach(([x,z,ry])=>{
  const bench=new THREE.Mesh(new THREE.CylinderGeometry(0.22,0.22,2.2,8), logMat);
  bench.rotation.z=Math.PI/2; bench.rotation.y=ry; bench.position.set(x,0.22,z);
  bench.castShadow=bench.receiveShadow=true; scene.add(bench);
  const log2=bench.clone(); log2.position.y=0.22; log2.position.x+=0.35; scene.add(log2);
});

// Trees (38)
const trunkMat=new THREE.MeshStandardMaterial({color:0x4a2f1a,roughness:1,flatShading:true});
const leafMats=[0x1a4a2e,0x1f5a35,0x245e30,0x2a6b3a].map(c=>new THREE.MeshStandardMaterial({color:c,roughness:1,flatShading:true}));
function makeTree(s){
  const g=new THREE.Group();
  const trunk=new THREE.Mesh(new THREE.CylinderGeometry(0.16*s,0.24*s,1.2*s,6),trunkMat);
  trunk.position.y=0.6*s; trunk.castShadow=true; g.add(trunk);
  const mat=leafMats[Math.floor(Math.random()*leafMats.length)];
  [[0,2.0,0,1.05,1.6],[0,3.0,0,0.78,1.4],[0,3.85,0,0.5,1.15]].forEach(([x,y,z,r,h])=>{
    const cone=new THREE.Mesh(new THREE.ConeGeometry(r*s,h*s,7),mat);
    cone.position.set(x,y*s,z); cone.castShadow=true; g.add(cone);
  });
  return g;
}
let treeCount=0;
for(let i=0;i<38;i++){
  const a=Math.random()*Math.PI*2;
  const r=7.5+Math.pow(Math.random(),0.8)*26;
  const s=0.9+Math.random()*1.4;
  const t=makeTree(s);
  t.position.set(Math.cos(a)*r,0,Math.sin(a)*r);
  t.rotation.y=Math.random()*Math.PI*2;
  scene.add(t); treeCount++;
}
// a few closer hero trees
[[ -6, -3,1.3],[6,-5,1.1],[-4,6,1.2],[7,4,0.95]].forEach(([x,z,s])=>{
  const t=makeTree(s); t.position.set(x,0,z); scene.add(t); treeCount++;
});

// Moon
const moon=new THREE.Mesh(new THREE.SphereGeometry(2.2,20,20), new THREE.MeshBasicMaterial({color:0xf5f0d0}));
moon.position.set(-22,20,-28); scene.add(moon);
const halo=new THREE.Mesh(new THREE.SphereGeometry(3.2,20,20), new THREE.MeshBasicMaterial({color:0xfff8cc,transparent:true,opacity:0.18}));
halo.position.copy(moon.position); scene.add(halo);

// Stars
const starGeo=new THREE.BufferGeometry();
const starPos=[];
for(let i=0;i<900;i++){
  const a=Math.random()*Math.PI*2, e=Math.random()*Math.PI*0.45+0.08, r=90;
  starPos.push(Math.cos(a)*Math.cos(e)*r, Math.sin(e)*r, Math.sin(a)*Math.cos(e)*r);
}
starGeo.setAttribute('position', new THREE.Float32BufferAttribute(starPos,3));
scene.add(new THREE.Points(starGeo, new THREE.PointsMaterial({color:0xffffff,size:0.55,sizeAttenuation:true,transparent:true,opacity:0.9})));

// Flames — layered cones
const flames=[];
const flameCols=[0xff5500,0xff8833,0xffcc33,0xfff2a0];
const flameMats=flameCols.map(c=>new THREE.MeshBasicMaterial({color:c,transparent:true,opacity:0.9,side:THREE.DoubleSide}));
for(let layer=0;layer<4;layer++){
  const h=1.7-layer*0.32, r=0.62-layer*0.13;
  const cone=new THREE.Mesh(new THREE.ConeGeometry(r,h,10,1,true), flameMats[layer]);
  cone.position.y=0.45+h/2;
  cone.castShadow=false;
  scene.add(cone);
  flames.push({mesh:cone, baseH:h, baseR:r, phase:Math.random()*10, speed:5+Math.random()*4});
}
// glowing coals
for(let i=0;i<12;i++){
  const c=new THREE.Mesh(new THREE.DodecahedronGeometry(0.09+Math.random()*0.08,0), new THREE.MeshStandardMaterial({color:0x331100, emissive:0xff4400, emissiveIntensity:1.2+Math.random(), roughness:1}));
  const a=Math.random()*Math.PI*2, r=Math.random()*0.55;
  c.position.set(Math.cos(a)*r,0.12,Math.sin(a)*r); scene.add(c);
}

// Sparks particle system
const SPARKS=220;
const sparkGeo=new THREE.BufferGeometry();
const sparkPos=new Float32Array(SPARKS*3);
const sparkData=[];
for(let i=0;i<SPARKS;i++){
  sparkData.push({x:(Math.random()-0.5)*0.7, y:Math.random()*3.5, z:(Math.random()-0.5)*0.7, vy:0.6+Math.random()*1.4, vx:(Math.random()-0.5)*0.35, vz:(Math.random()-0.5)*0.35, life:Math.random()});
}
sparkGeo.setAttribute('position', new THREE.BufferAttribute(sparkPos,3));
const sparks=new THREE.Points(sparkGeo, new THREE.PointsMaterial({color:0xffbb44,size:0.09,transparent:true,opacity:0.95,blending:THREE.AdditiveBlending,depthWrite:false}));
scene.add(sparks);

const clock=new THREE.Clock();
let frames=0, lastFps=performance.now();
function animate(){
  requestAnimationFrame(animate);
  const t=clock.getElapsedTime();
  // flicker
  const flick = 0.88 + Math.sin(t*11)*0.07 + Math.sin(t*23+1)*0.05 + Math.random()*0.06;
  fireLight.intensity = 28 * flick;
  fireGlow.intensity = 8 * flick;
  flames.forEach(f=>{
    const w = 1 + Math.sin(t*f.speed + f.phase)*0.14 + Math.sin(t*17+f.phase)*0.06;
    f.mesh.scale.set(1/Math.sqrt(w), w, 1/Math.sqrt(w));
    f.mesh.rotation.y = t*0.4 + f.phase;
    f.mesh.position.x = Math.sin(t*3+f.phase)*0.05;
    f.mesh.position.z = Math.cos(t*2.6+f.phase)*0.05;
  });
  // sparks
  for(let i=0;i<SPARKS;i++){
    const s=sparkData[i];
    s.y+=s.vy*0.016; s.x+=s.vx*0.016+Math.sin(t*3+i)*0.002; s.z+=s.vz*0.016;
    s.life-=0.0035;
    if(s.y>3.8||s.life<=0){ s.y=0.5+Math.random()*0.3; s.x=(Math.random()-0.5)*0.7; s.z=(Math.random()-0.5)*0.7; s.life=1; }
    sparkPos[i*3]=s.x; sparkPos[i*3+1]=s.y; sparkPos[i*3+2]=s.z;
  }
  sparkGeo.attributes.position.needsUpdate=true;
  sparks.material.opacity = 0.75 + flick*0.25;

  controls.update();
  renderer.render(scene,camera);

  frames++;
  const now=performance.now();
  if(now-lastFps>500){
    const fps=Math.round(frames*1000/(now-lastFps));
    document.getElementById('fps').textContent=fps;
    document.getElementById('temp').textContent=Math.round(18+flick*10)+'°';
    frames=0; lastFps=now;
  }
}
animate();

addEventListener('resize',()=>{
  camera.aspect=innerWidth/innerHeight;
  camera.updateProjectionMatrix();
  renderer.setSize(innerWidth,innerHeight);
});
</script>
</body>
</html>