Canyon Run
GPT 6 Luna · full
◈Preview unavailable — try playing the result
Browser check: Preview unavailable or timed out. This is a technical check, not a quality review.
Reviews & generation details
Reviews
No human review yet. Unreviewed does not mean unsuccessful.
Generation context
Imported historical artifact. Its exact original instructions and lineage are not known.
Generation prompt · exact text unavailable
See the current prompt for reference. It may differ from the instructions used to generate this artifact.
Inspect original source 23,439 bytes · SHA-256 e9da3e417d3c
<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no"><title>DUST RUNNER — Velocity</title><script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script>
<style>
@import url('https://fonts.googleapis.com/css2?family=Orbitron:wght@400;500;700;900&family=Rajdhani:wght@400;500;600;700&display=swap');
:root{--ice:#d8fbff;--cyan:#67eaff;--amber:#ffc18d}*{box-sizing:border-box}html,body{margin:0;width:100%;height:100%;overflow:hidden;background:#100d20;color:#e9f8ff;font-family:'Rajdhani',sans-serif}canvas#view{position:absolute;inset:0;width:100%;height:100%;display:block}.shade{position:absolute;inset:0;pointer-events:none;background:linear-gradient(180deg,rgba(10,9,25,.12),transparent 39%,rgba(11,9,23,.42));z-index:1}.hud{position:absolute;inset:0;z-index:2;pointer-events:none}.topline{position:absolute;left:5.2%;right:5.2%;top:5%;display:flex;justify-content:space-between;align-items:flex-start}.brand{font:700 13px Orbitron,sans-serif;letter-spacing:.36em;color:#d5faff;text-shadow:0 0 18px #59dafa}.brand span{display:block;font:500 9px Rajdhani,sans-serif;letter-spacing:.48em;color:#8c9bad;margin-top:7px}.stat,.label{font:500 10px Orbitron,sans-serif;letter-spacing:.2em;color:#9aacbf}.stat b{font:600 21px Rajdhani,sans-serif;letter-spacing:.12em;color:#e5faff;display:block;margin-top:5px}.scorebox{text-align:right}.leftstats{position:absolute;left:5.2%;top:30%;display:flex;flex-direction:column;gap:27px}.label{font-size:9px;letter-spacing:.22em;color:#9bacbf}.energyWrap{width:135px;height:3px;margin-top:9px;background:rgba(186,220,255,.16);overflow:hidden}.energy{height:100%;width:100%;background:linear-gradient(90deg,#59ecff,#d6ffff);box-shadow:0 0 12px #58eaff;transition:width .15s}.turboWrap{width:135px;height:2px;background:rgba(186,220,255,.13);margin-top:9px}.turbo{height:100%;width:0;background:#ffb86f;box-shadow:0 0 12px #ff985b}.combo{position:absolute;top:29%;right:5.2%;text-align:right;transition:transform .15s}.combo b{display:block;font:500 36px Orbitron,sans-serif;color:#dcfaff;text-shadow:0 0 25px #5feaff;line-height:1.15}.combo.hot b{color:#ffce97;text-shadow:0 0 24px #ff8e59}.speedbar{position:absolute;bottom:8%;left:50%;transform:translateX(-50%);width:min(280px,42vw);text-align:center}.speedline{height:2px;background:rgba(200,235,255,.19);position:relative;margin:0 auto 10px}.speedfill{height:100%;width:0;background:linear-gradient(90deg,#75dcff,#fff4d2);box-shadow:0 0 12px #7cecff}.speedtext{font:500 9px Orbitron,sans-serif;letter-spacing:.28em;color:#a1b5c6}.speedtext strong{font:600 14px Rajdhani,sans-serif;color:#eaffff;margin-right:5px}.hint{position:absolute;bottom:4%;left:50%;transform:translateX(-50%);font:500 9px Orbitron,sans-serif;letter-spacing:.2em;color:rgba(202,224,238,.55);white-space:nowrap}.crosshair{position:absolute;left:50%;top:50%;transform:translate(-50%,-50%);width:18px;height:18px;opacity:.28}.crosshair:before,.crosshair:after{content:'';position:absolute;background:#c6faff}.crosshair:before{height:1px;width:18px;top:9px}.crosshair:after{width:1px;height:18px;left:9px}.overlay{position:absolute;inset:0;z-index:5;display:flex;align-items:center;justify-content:center;background:radial-gradient(ellipse at 50% 51%,rgba(22,17,43,.22),rgba(9,8,22,.67));transition:opacity .45s,visibility .45s}.overlay.hidden{opacity:0;visibility:hidden;pointer-events:none}.panel{text-align:center;width:min(560px,90vw);padding:40px 24px;position:relative}.eyebrow{font:500 10px Orbitron,sans-serif;letter-spacing:.42em;color:#85eaff;margin-bottom:20px}.title{font:900 clamp(42px,8vw,78px)/.9 Orbitron,sans-serif;letter-spacing:.09em;margin:0;color:#f0fbff;text-shadow:0 0 45px rgba(100,210,255,.32)}.title em{font-style:normal;color:#ffbd84}.subtitle{font:500 13px Rajdhani,sans-serif;letter-spacing:.3em;color:#c1c4d0;margin:20px 0 34px}.rule{width:45px;height:1px;background:#7de8ff;margin:0 auto 25px;box-shadow:0 0 12px #7de8ff}.copy{max-width:375px;margin:0 auto 28px;font-size:16px;line-height:1.5;color:#cad3df}.start{pointer-events:auto;border:1px solid rgba(144,232,255,.7);background:rgba(77,199,232,.1);color:#e6fcff;padding:15px 34px;font:500 11px Orbitron,sans-serif;letter-spacing:.28em;cursor:pointer;transition:.2s;box-shadow:0 0 24px rgba(71,213,255,.08)}.start:hover{background:rgba(90,220,255,.22);box-shadow:0 0 35px rgba(71,213,255,.25);transform:translateY(-2px)}.small{font:500 9px Orbitron,sans-serif;color:#9aabc0;letter-spacing:.16em;margin-top:20px}.summary{display:flex;justify-content:center;gap:40px;margin:25px 0}.summary div{font:500 9px Orbitron,sans-serif;letter-spacing:.2em;color:#a8b5c5}.summary b{display:block;font:600 23px Rajdhani,sans-serif;color:#e8fbff;margin-top:8px}.touch{display:none}@media(max-width:650px){.topline{top:3.5%;left:5%;right:5%}.leftstats{top:22%;left:5%}.energyWrap,.turboWrap{width:98px}.combo{top:22%;right:5%}.combo b{font-size:30px}.brand{font-size:11px}.hint{bottom:3%;font-size:8px}.speedbar{bottom:7%}.touch{display:block;position:absolute;bottom:14%;z-index:4;pointer-events:auto;color:rgba(210,244,255,.3);font:10px Orbitron;letter-spacing:.2em}.touch.left{left:8%}.touch.right{right:8%}}
</style></head><body>
<canvas id="view"></canvas><div class="shade"></div><div class="hud"><div class="topline"><div class="brand">V E L O C I T Y<span>THE SUNLESS RUN</span></div><div class="stat scorebox">DISTANCE<b id="score">000000</b></div></div><div class="leftstats"><div><div class="label">CORE ENERGY</div><div class="energyWrap"><div class="energy" id="energy"></div></div></div><div><div class="label">AFTERBURN</div><div class="turboWrap"><div class="turbo" id="turbo"></div></div></div></div><div class="combo" id="combo"><div class="label">PROXIMITY</div><b id="mult">×1</b></div><div class="crosshair"></div><div class="speedbar"><div class="speedline"><div class="speedfill" id="speedfill"></div></div><div class="speedtext"><strong id="speed">0</strong> KM / H</div></div><div class="hint">A / D OR ← → · W / S PITCH · SPACE BOOST</div><div class="touch left">◁ BANK</div><div class="touch right">BANK ▷</div></div>
<div class="overlay" id="overlay"><div class="panel" id="panel"><div class="eyebrow">// FLIGHT SYSTEM ONLINE</div><h1 class="title">DUST<br><em>RUNNER</em></h1><div class="subtitle">A CANYON WITHOUT AN END</div><div class="rule"></div><div class="copy">Ride the slipstream. Thread the needle.<br>Stay close to the stone. Stay alive.</div><button class="start" id="start">INITIATE FLIGHT</button><div class="small">WASD / ARROWS TO STEER · SPACE TO BURN</div></div></div>
<script>
(()=>{
const $=s=>document.querySelector(s),canvas=document.querySelector('#view');
const renderer=new THREE.WebGLRenderer({canvas,antialias:true,alpha:false,powerPreference:'high-performance'});renderer.setPixelRatio(Math.min(devicePixelRatio||1,1.7));renderer.setSize(innerWidth,innerHeight);renderer.outputEncoding=THREE.sRGBEncoding;renderer.toneMapping=THREE.ACESFilmicToneMapping;renderer.toneMappingExposure=.82;
const scene=new THREE.Scene();scene.background=new THREE.Color('#17152b');scene.fog=new THREE.FogExp2('#493449',.00135);const camera=new THREE.PerspectiveCamera(62,innerWidth/innerHeight,.1,1800);camera.position.set(0,5.5,-13);camera.lookAt(0,2.4,78);
// Smooth sunset dome gives the canyon a luminous horizon without textures or external assets.
const skyGeo=new THREE.SphereGeometry(900,32,20);const skyMat=new THREE.ShaderMaterial({side:THREE.BackSide,depthWrite:false,uniforms:{},vertexShader:'varying vec3 vPos; void main(){vPos=position; gl_Position=projectionMatrix*modelViewMatrix*vec4(position,1.0);}',fragmentShader:'varying vec3 vPos; void main(){float h=normalize(vPos).y; vec3 zen=vec3(.035,.035,.105); vec3 dusk=vec3(.17,.095,.20); vec3 glow=vec3(.56,.25,.26); vec3 c=mix(glow,dusk,smoothstep(-.08,.36,h)); c=mix(c,zen,smoothstep(.22,.82,h)); gl_FragColor=vec4(c,1.0);}'});const sky=new THREE.Mesh(skyGeo,skyMat);sky.frustumCulled=false;scene.add(sky);
scene.add(new THREE.HemisphereLight(0xb9d9ff,0x39283a,.62));const sunLight=new THREE.DirectionalLight(0xffc48d,2.1);sunLight.position.set(-32,65,80);scene.add(sunLight);const fillLight=new THREE.DirectionalLight(0x7c91d0,.75);fillLight.position.set(32,20,-50);scene.add(fillLight);
const sun=new THREE.Mesh(new THREE.SphereGeometry(13,24,16),new THREE.MeshBasicMaterial({color:0xffc98d}));sun.position.set(0,29,390);scene.add(sun);const sunHalo=new THREE.Mesh(new THREE.SphereGeometry(19,20,12),new THREE.MeshBasicMaterial({color:0xffa889,transparent:true,opacity:.13,depthWrite:false}));sunHalo.position.copy(sun.position);scene.add(sunHalo);
let W=innerWidth,H=innerHeight;addEventListener('resize',()=>{W=innerWidth;H=innerHeight;camera.aspect=W/H;camera.updateProjectionMatrix();renderer.setPixelRatio(Math.min(devicePixelRatio||1,1.7));renderer.setSize(W,H)});
let state='ready',world=0,t=0,last=performance.now(),score=0,energy=100,turbo=0,speed=48,maxSpeed=0,mult=1,shake=0,seed=9013;const player={x:0,y:0,vx:0,vy:0,roll:0};let chunks=[],items=[],stars=[],audio=null,engineOsc=null,boosting=false;const keys={};
function rand(){seed=(seed*1664525+1013904223)>>>0;return seed/4294967296}function clamp(x,a,b){return Math.max(a,Math.min(b,x))}function lerp(a,b,p){return a+(b-a)*p}function widthAt(d){return 11.8-Math.min(2,(score-1800)/8000)+Math.sin(d*.0012)*.8+Math.sin(d*.0032)*.4}function centerAt(d){return Math.sin(d*.00078)*1.4+Math.sin(d*.0021)*.38}
function mat(color,rough=.92,extra={}){return new THREE.MeshStandardMaterial({color,roughness:rough,flatShading:true,...extra})}
const floorMats=['#29273d','#30283c','#292b40','#34283b'].map(c=>mat(c));const wallMats=['#654450','#754b50','#5e4554','#84534d','#6b4b5b','#795251'].map(c=>mat(c));const darkMat=mat('#28243a'),orbMat=new THREE.MeshStandardMaterial({color:0x83f5ff,emissive:0x37deff,emissiveIntensity:2.4,roughness:.25,metalness:.3,flatShading:true});
function makeChunk(start){let group=new THREE.Group();group.position.z=start;scene.add(group);let abs=world+start;const n=20,L=240;
// Faceted canyon floor strip
let positions=[],indices=[],colors=[];for(let iz=0;iz<=n;iz++){let z=L*iz/n,d=abs+z,c=centerAt(d),w=widthAt(d);for(let ix=0;ix<=8;ix++){let f=ix/8*2-1;let x=c+f*w*1.4;let y=-2.7+Math.sin(d*.035+ix*1.8)*.14;positions.push(x,y,z);if(iz<n&&ix<8){let a=iz*9+ix,b=a+1,c1=a+9,d1=c1+1;indices.push(a,c1,b,b,c1,d1)}}}let fg=new THREE.BufferGeometry();fg.setAttribute('position',new THREE.Float32BufferAttribute(positions,3));fg.setIndex(indices);fg.computeVertexNormals();let floor=new THREE.Mesh(fg,floorMats[Math.floor(rand()*floorMats.length)]);group.add(floor);
// Irregular low-poly wall surfaces, tiled as triangles, with individual sunset stone tones
for(const side of [-1,1]){let verts=[],idx=[],col=[];const rows=10;for(let iz=0;iz<=n;iz++){let z=L*iz/n,d=abs+z,c=centerAt(d),w=widthAt(d);for(let j=0;j<=rows;j++){let h=j/rows,rough=Math.sin(d*.021+j*5.7+side)*.55+Math.sin(d*.067+j*2.4)*.3;let base=side*(w+Math.max(0,h-.18)*(10+rough));let x=c+base;let y=-2.8+h*(10+rough)+Math.sin(d*.018+j*2+side)*.18;verts.push(x,y,z);let shade=.76+rand()*.35;col.push(shade,shade*.79,shade*.78);if(iz<n&&j<rows){let a=iz*(rows+1)+j,b=a+rows+1;idx.push(a,a+1,b,b,a+1,b+1)}}}let g=new THREE.BufferGeometry();g.setAttribute('position',new THREE.Float32BufferAttribute(verts,3));g.setAttribute('color',new THREE.Float32BufferAttribute(col,3));g.setIndex(idx);g.computeVertexNormals();let m=new THREE.MeshStandardMaterial({color:side<0?0x76545c:0x79545c,vertexColors:true,roughness:1,flatShading:true,side:THREE.DoubleSide});group.add(new THREE.Mesh(g,m));
// lit seam ribbons
let seam=new THREE.Mesh(new THREE.BoxGeometry(.075,.055,L),new THREE.MeshBasicMaterial({color:0xffbd91,transparent:true,opacity:.19}));seam.position.set(centerAt(abs+L/2)+side*(widthAt(abs+L/2)*.97),1.1,L/2);group.add(seam)}
// stone teeth at the skyline create a broken silhouette
for(let i=0;i<9;i++){let z=12+rand()*220,d=abs+z,side=rand()<.5?-1:1;let h=3+rand()*11,w=2+rand()*5;let m=new THREE.Mesh(new THREE.ConeGeometry(w,h,5,1),wallMats[Math.floor(rand()*wallMats.length)]);m.position.set(centerAt(d)+side*(widthAt(d)+w*.65),4+h*.35,z);m.rotation.z=(rand()-.5)*.15;group.add(m)}
let chunk={group,start,length:L,items:[]};chunks.push(chunk);
// Procedural obstacle clusters + fuel shards in each streamed segment
for(let j=0;j<3;j++){if(rand()<(score>2500?.84:.68)){let z=22+rand()*205,d=abs+z,c=centerAt(d),w=widthAt(d),kind=rand();let item;if(kind<.48){let side=rand()<.5?-1:1,x=c+side*w*(.6+rand()*.18),r=1.1+rand()*1.05,h=3+rand()*3.5;let mesh=new THREE.Mesh(new THREE.DodecahedronGeometry(r,0),wallMats[Math.floor(rand()*wallMats.length)]);mesh.scale.y=h/(r*2);mesh.position.set(x,0,z);mesh.rotation.set(rand(),rand(),rand());group.add(mesh);item={type:'rock',mesh,x,z,r:r*.8,hy:h*.34}}else if(kind<.78){let x=c+(rand()-.5)*w*1.3,r=.8+rand()*.35,h=4+rand()*3;let mesh=new THREE.Mesh(new THREE.BoxGeometry(r*1.5,h,r*1.4),wallMats[Math.floor(rand()*wallMats.length)]);mesh.position.set(x,h*.5-1,z);mesh.rotation.y=(rand()-.5)*.35;group.add(mesh);let cap=new THREE.Mesh(new THREE.ConeGeometry(r*1.2,.65,4),wallMats[3]);cap.position.set(x,h-.65,z);group.add(cap);item={type:'monolith',mesh,x,z,r:r*.9,hy:h*.35}}else{let gap=w*(.28+rand()*.12),mid=c+(rand()-.5)*1.5,outer=w*1.3;let leftW=Math.max(.5,outer*.5-gap*.5),rightW=leftW;for(let s of [-1,1]){let xx=mid+s*(gap/2+leftW/2);let pillar=new THREE.Mesh(new THREE.BoxGeometry(leftW,7,2.4),wallMats[2+Math.floor(rand()*3)]);pillar.position.set(xx,1.4,z);group.add(pillar);let cap=new THREE.Mesh(new THREE.BoxGeometry(leftW*1.1,.45,2.8),wallMats[1]);cap.position.set(xx,5,z);group.add(cap)}let lintel=new THREE.Mesh(new THREE.BoxGeometry(gap+leftW,.7,2.2),wallMats[3]);lintel.position.set(mid,5,z);group.add(lintel);item={type:'gate',mesh:null,x:mid,z,gap,hy:2.3}}chunk.items.push(item);items.push(item)}
if(rand()<.92){let z=45+rand()*195,d=abs+z,x=centerAt(d)+(rand()-.5)*widthAt(d)*1.35;let groupOrb=new THREE.Group();groupOrb.position.set(x,(rand()-.5)*2,z);let gem=new THREE.Mesh(new THREE.OctahedronGeometry(.68,0),orbMat);groupOrb.add(gem);let ring=new THREE.Mesh(new THREE.TorusGeometry(.88,.035,5,12),new THREE.MeshBasicMaterial({color:0x80f5ff,transparent:true,opacity:.72}));ring.rotation.x=.6;groupOrb.add(ring);const glow=new THREE.PointLight(0x43dcff,1.7,13);groupOrb.add(glow);group.add(groupOrb);chunk.items.push({type:'orb',mesh:groupOrb,x,z,r:1.25,baseY:groupOrb.position.y,phase:rand()*6.28});items.push(chunk.items[chunk.items.length-1])}}
return chunk}
function initWorld(){for(let i=0;i<7;i++)makeChunk(30+i*240)}initWorld();
// Craft: single low-poly swept-wing glider, emissive twin engine cores
const ship=new THREE.Group();const hull=new THREE.Mesh(new THREE.ConeGeometry(.78,3.4,5,1),mat('#e3f2ed',.38,{metalness:.35}));hull.rotation.x=-Math.PI/2;hull.position.y=0;ship.add(hull);const wing=new THREE.Mesh(new THREE.BufferGeometry(),mat('#d2e8e3',.4,{metalness:.25,side:THREE.DoubleSide}));let wingGeo=new THREE.BufferGeometry();wingGeo.setAttribute('position',new THREE.Float32BufferAttribute([-0.3,0,.45,-3.1,-.1,.8,-1.1,0,-.4, .3,0,.45,1.1,0,-.4,3.1,-.1,.8],3));wingGeo.setIndex([0,1,2,3,4,5]);wingGeo.computeVertexNormals();wing.geometry.dispose();ship.add(new THREE.Mesh(wingGeo,mat('#c8e4e3',.42,{side:THREE.DoubleSide,metalness:.2})));const canopy=new THREE.Mesh(new THREE.OctahedronGeometry(.38,0),new THREE.MeshStandardMaterial({color:0x82dce8,emissive:0x1b7289,metalness:.65,roughness:.2}));canopy.scale.set(.65,.65,1.6);canopy.position.set(0,.2,-.35);ship.add(canopy);for(let s of [-1,1]){let eng=new THREE.Mesh(new THREE.CylinderGeometry(.12,.18,.55,6),new THREE.MeshBasicMaterial({color:0x8af6ff}));eng.rotation.x=Math.PI/2;eng.position.set(s*.72,-.04,.9);ship.add(eng)}const engineGlow=new THREE.PointLight(0x43dfff,3,17);engineGlow.position.set(0,0,2);ship.add(engineGlow);scene.add(ship);
// Tiny procedural dust streak field (one dynamic buffer; no per-frame allocations)
let trailPos=new Float32Array(240*3);for(let i=0;i<240;i++){trailPos[i*3]=(rand()-.5)*45;trailPos[i*3+1]=(rand()-.2)*20;trailPos[i*3+2]=rand()*520+20}let trailGeo=new THREE.BufferGeometry();trailGeo.setAttribute('position',new THREE.BufferAttribute(trailPos,3));let trailPts=new THREE.Points(trailGeo,new THREE.PointsMaterial({color:0xffc19a,size:.55,transparent:true,opacity:.62,sizeAttenuation:true}));scene.add(trailPts);
function sound(){try{audio=new(window.AudioContext||window.webkitAudioContext)();engineOsc=audio.createOscillator();let g=audio.createGain();engineOsc.type='sawtooth';engineOsc.frequency.value=56;g.gain.value=.018;let filter=audio.createBiquadFilter();filter.type='lowpass';filter.frequency.value=250;engineOsc.connect(filter);filter.connect(g);g.connect(audio.destination);engineOsc.start()}catch(e){}}
function tone(f,d,type='sine',v=.08){if(!audio)return;let o=audio.createOscillator(),g=audio.createGain();o.type=type;o.frequency.setValueAtTime(f,audio.currentTime);g.gain.setValueAtTime(v,audio.currentTime);g.gain.exponentialRampToValueAtTime(.001,audio.currentTime+d);o.connect(g);g.connect(audio.destination);o.start();o.stop(audio.currentTime+d)}
function start(){if(state==='playing')return;if(!audio)sound();if(audio.state==='suspended')audio.resume();state='playing';$('#overlay').classList.add('hidden');last=performance.now()}
function endRun(){if(state!=='playing')return;state='over';tone(110,.65,'triangle',.13);$('#panel').innerHTML=`<div class="eyebrow">// FLIGHT TERMINATED</div><h1 class="title">RUN<br><em>ENDED</em></h1><div class="subtitle">THE CANYON CLAIMS ANOTHER</div><div class="summary"><div>DISTANCE<b>${Math.floor(score).toLocaleString()}</b></div><div>TOP SPEED<b>${Math.floor(maxSpeed*3.2)} KM/H</b></div></div><button class="start" id="start">FLY AGAIN</button><div class="small">THE HORIZON IS STILL OUT THERE</div>`;$('#overlay').classList.remove('hidden');$('#start').onclick=restart}
function restart(){for(const c of chunks)scene.remove(c.group);chunks=[];items=[];world=score=0;energy=100;turbo=0;speed=48;maxSpeed=0;mult=1;player.x=player.y=player.vx=player.vy=player.roll=0;seed=9013;initWorld();state='playing';$('#overlay').classList.add('hidden');last=performance.now();if(audio?.state==='suspended')audio.resume()}
$('#start').onclick=start;addEventListener('keydown',e=>{keys[e.code]=true;if(['ArrowLeft','ArrowRight','ArrowUp','ArrowDown','Space'].includes(e.code))e.preventDefault();if((e.code==='Enter'||e.code==='Space')&&state!=='playing')start()});addEventListener('keyup',e=>keys[e.code]=false);
let pointer=false,px=0;canvas.addEventListener('pointerdown',e=>{pointer=true;px=e.clientX;canvas.setPointerCapture(e.pointerId)});canvas.addEventListener('pointermove',e=>{if(pointer){player.vx+= (e.clientX-px)*.018;px=e.clientX}});canvas.addEventListener('pointerup',()=>pointer=false);
function advance(dt){world+=speed*dt;for(const c of chunks)c.group.position.z-=speed*dt;for(let i=chunks.length-1;i>=0;i--){if(chunks[i].group.position.z < -240){scene.remove(chunks[i].group);chunks.splice(i,1)}}let tail=chunks[chunks.length-1];while(chunks.length<7||tail.group.position.z<1200){tail=chunks[chunks.length-1];makeChunk(tail.group.position.z+240)} }
function update(dt){if(state!=='playing')return;t+=dt;const ix=(keys.ArrowRight||keys.KeyD?1:0)-(keys.ArrowLeft||keys.KeyA?1:0),iy=(keys.ArrowUp||keys.KeyW?1:0)-(keys.ArrowDown||keys.KeyS?1:0);player.vx+=ix*17*dt;player.vy+=iy*9*dt;player.vx*=Math.exp(-2.45*dt);player.vy*=Math.exp(-2.6*dt);player.x=clamp(player.x+player.vx*dt,-9,9);player.y=clamp(player.y+player.vy*dt,-3,3.4);player.roll=lerp(player.roll,clamp(-player.vx*.12,-.62,.62),Math.min(1,dt*5));let difficulty=Math.min(1,score/14000);boosting=!!keys.Space&&turbo>2;if(boosting)turbo=Math.max(0,turbo-27*dt);else turbo=Math.min(100,turbo+(Math.abs(player.vx)<1.05?2.2:.3)*dt);speed=lerp(speed,49+difficulty*27+(boosting?38:0),Math.min(1,dt*(boosting?1.4:.62)));maxSpeed=Math.max(maxSpeed,speed);score+=speed*dt*(1+(mult-1)*.22);energy-=(2.3+difficulty*1.15+(boosting?1.4:0))*dt;advance(dt);
let shipX=centerAt(world)+player.x;ship.position.set(shipX,player.y,7);ship.rotation.z=-player.roll;ship.rotation.x=player.vy*.035;camera.position.x=lerp(camera.position.x,shipX*.52,dt*2.8);camera.position.y=lerp(camera.position.y,5.5+player.y*.12,dt*1.7);camera.fov=lerp(camera.fov,boosting?84:70,dt*2.4);camera.updateProjectionMatrix();camera.lookAt(shipX*.3,0,72);engineGlow.intensity=boosting?6:3;
let wallGap=widthAt(world+7)-Math.abs(player.x);if(wallGap<.42){shake=8;endRun()}let proximity=wallGap<3.25?1-(wallGap-.42)/2.83:0;for(const c of chunks){for(const o of c.items){if(o.type==='orb'&&o.mesh){o.mesh.rotation.y+=dt*1.5;o.mesh.position.y=o.baseY+Math.sin(t*2.5+o.phase)*.3}let z=c.group.position.z+o.z;if(z<0||z>24)continue;let dx=Math.abs(shipX-o.x),dy=Math.abs(player.y-(o.type==='orb'?o.mesh.position.y:0));if(o.type==='orb'){if(dx<1.55&&dy<1.8){o.mesh.visible=false;o.type='collected';energy=Math.min(100,energy+27);turbo=Math.min(100,turbo+20);score+=145;tone(770,.22,'sine',.08);tone(1120,.18,'sine',.045)}}else{let dist=Math.hypot(dx,dy*.8),rad=o.type==='gate'?o.gap*.5-1.1:o.r+.45;if(o.type==='gate'){if(dx>o.gap*.5-1&&dy<o.hy){endRun();break}let edge=Math.abs(dx-o.gap*.5);if(edge<3.5&&dy<2)proximity=Math.max(proximity,1-edge/3.5)}else if(dist<rad){shake=9;endRun();break}else if(dist<rad+3){proximity=Math.max(proximity,1-(dist-rad)/3)}}}}
if(proximity>0){mult=1+Math.min(9,Math.floor(proximity*9));shake=Math.max(shake,proximity*2.2);if(Math.random()<dt*2)tone(230+Math.random()*180,.1,'triangle',.022)}else mult=Math.max(1,mult-dt*2);shake*=Math.exp(-3.1*dt);if(energy<=0)endRun();
// Recycle dust streak positions ahead of the camera.
let arr=trailGeo.attributes.position.array;for(let i=0;i<240;i++){let k=i*3;arr[k+2]-=speed*dt*1.18;if(arr[k+2]<-18){arr[k]=(rand()-.5)*45;arr[k+1]=(rand()-.2)*20;arr[k+2]=520+rand()*260}}trailGeo.attributes.position.needsUpdate=true;
if(engineOsc&&audio)engineOsc.frequency.setTargetAtTime(48+speed*.66+(boosting?30:0),audio.currentTime,.13);
$('#score').textContent=String(Math.floor(score)).padStart(6,'0');$('#energy').style.width=clamp(energy,0,100)+'%';$('#energy').style.background=energy<25?'linear-gradient(90deg,#ff6e87,#ffd08e)':'linear-gradient(90deg,#59ecff,#d6ffff)';$('#turbo').style.width=turbo+'%';$('#speed').textContent=Math.floor(speed*3.2);$('#speedfill').style.width=clamp((speed-35)/105*100,0,100)+'%';$('#mult').textContent='×'+Math.floor(mult);$('#combo').classList.toggle('hot',mult>1);$('#combo').style.transform=`scale(${mult>1?1.06:1})`}
function render(){if(shake>.1&&state==='playing'){camera.position.x+=(Math.random()-.5)*shake*.025;camera.position.y+=(Math.random()-.5)*shake*.018}renderer.render(scene,camera)}function frame(now){let dt=Math.min(.045,(now-last)/1000||.016);last=now;update(dt);render();requestAnimationFrame(frame)}requestAnimationFrame(frame);
})();
</script></body></html>
<!-- agent-meta {"model":"openai/gpt-6-luna","provider":"openrouter","persona":"full","sessionId":"8f6206c8-22e7-4867-945f-ca52d64d33d3","tokensIn":755517,"tokensOut":29248,"tokensTotal":784765,"cost":0.02651184,"turns":27,"toolCalls":26,"failedToolCalls":2,"timestamp":"2026-09-23T00:11:43.706Z"} -->