Rally
GPT 5.6 Luna Pro · composer

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 14,593 bytes · SHA-256 955f37012e53
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>RALLY//DUST — Alpine Sprint</title>
<script src="https://cdn.jsdelivr.net/npm/three@0.160.0/build/three.min.js"></script>
<style>
/* ── css: base ── */
*{box-sizing:border-box}html,body,#app,#game{margin:0;width:100%;height:100%;overflow:hidden;background:#0c1820;font-family:Arial,Helvetica,sans-serif;color:#fff}#viewport{position:absolute;inset:0}canvas{display:block}#hud{position:absolute;inset:0;pointer-events:none}.brand{position:absolute;top:22px;left:28px;font-weight:900;font-style:italic;font-size:25px;letter-spacing:2px;text-shadow:3px 3px 0 #0a1720}.brand span{color:#e85d36}.brand small{display:block;font-size:9px;letter-spacing:5px;color:#9eb2b5;font-style:normal;margin-top:3px}.stats{position:absolute;right:25px;top:20px;display:flex;gap:18px;text-align:right;background:rgba(8,20,26,.64);padding:12px 15px;border-left:3px solid #e85d36;backdrop-filter:blur(5px)}.stats div{min-width:54px}.stats b{display:block;font-size:19px;letter-spacing:1px}.stats div:first-child b{font-size:31px;color:#ffd36a}.stats em{font-size:8px;color:#9fb1b5;letter-spacing:1px;font-style:normal}.stats div:nth-child(4) b,.stats div:nth-child(5) b{font-size:14px;margin-top:8px}.stats div:nth-child(5) b{color:#b9e4d0}.brand+ .stats{}#minimap{position:absolute;right:25px;bottom:25px;width:180px;height:130px;background:rgba(8,19,24,.68);border:1px solid rgba(255,255,255,.35);border-radius:3px}.#tip{position:absolute;bottom:18px;left:28px;font-size:10px;letter-spacing:1px;color:rgba(255,255,255,.7)}#countdown{position:absolute;inset:0;display:grid;place-content:center;text-align:center;text-shadow:0 5px 0 rgba(0,0,0,.3)}#countdown strong{font-size:110px;color:#ffd36a;font-style:italic}#countdown span{font-size:12px;letter-spacing:6px}.modal{position:absolute;inset:0;display:none;place-content:center;text-align:center;background:rgba(6,15,20,.74);backdrop-filter:blur(8px)}.modal.show{display:grid}.modal h1{font-size:46px;font-style:italic;letter-spacing:5px;margin:0 0 5px;color:#ffd36a}.modal p{font-size:30px;margin:14px 0 0}.modal small{letter-spacing:3px;color:#9fb1b5}.modal button,button{border:0;background:#e85d36;color:#fff;font-weight:900;letter-spacing:2px;padding:14px 32px;margin:22px 7px 0;cursor:pointer}.modal button:hover{background:#ff7950}.modal p:nth-of-type(2){font-size:14px;color:#b9e4d0;margin-top:12px}.modal button+button{background:#294953}#touch{display:none;position:absolute;bottom:18px;left:15px;right:15px;justify-content:space-between;pointer-events:auto}#touch button{margin:0;padding:16px 17px;border-radius:50%;background:rgba(20,39,47,.8);border:1px solid #789096;font-size:17px}#touch button[data-key=space]{border-radius:8px;font-size:10px;padding:14px 12px}@media(max-width:700px){.stats{top:12px;right:10px;gap:8px;padding:8px}.brand{left:12px;top:12px;font-size:18px}.brand small{font-size:7px}.stats div:nth-child(4),.stats div:nth-child(5){display:none}#tip{display:none}#minimap{right:10px;bottom:100px;width:130px;height:95px}#touch{display:flex}.modal h1{font-size:32px}}
</style>
</head>
<body>
<main id="game"><div id="viewport"></div><div id="hud"><div class="brand">RALLY<span>//DUST</span><small>ALPINE SPRINT</small></div><div class="stats"><div><b id="speed">000</b><em>KM/H</em></div><div><b id="gear">N</b><em>GEAR</em></div><div><b id="lap">1 / 3</b><em>LAP</em></div><div><b id="timer">00:00.000</b><em>TIME</em></div><div><b id="best">--:--.---</b><em>BEST LAP</em></div></div><canvas id="minimap" width="180" height="130"></canvas><div id="tip">WASD / ARROWS DRIVE • SPACE DRIFT • C CAMERA • P PAUSE</div></div><div id="countdown"><strong>3</strong><span>GET READY</span></div><div id="pause" class="modal"><h1>PAUSED</h1><button id="resume">RESUME</button><button id="restart">RESTART</button></div><div id="finish" class="modal"><h1>STAGE CLEAR</h1><p id="final">00:00.000</p><small>FINAL TIME</small><p id="finalbest">BEST LAP —</p><button id="finishRestart">RACE AGAIN</button></div><div id="touch"><button data-key="left">◀</button><button data-key="up">▲</button><button data-key="down">▼</button><button data-key="right">▶</button><button data-key="space">DRIFT</button></div></main>
<script>
'use strict';
// ── const: Rally ──
const Rally = (() => {
const S={scene:null,camera:null,renderer:null,car:null,track:null,curve:null,t:0,offset:0,speed:0,lap:1,started:false,paused:false,finished:false,startTime:0,lapStart:0,best:null,last:0,camMode:0,keys:{},objects:[],dust:[],skids:[],audio:null};
const $=id=>document.getElementById(id);
function mat(c,rough=1){return new THREE.MeshStandardMaterial({color:c,roughness:rough})}
function mesh(g,m){let x=new THREE.Mesh(g,m);x.castShadow=true;x.receiveShadow=true;return x}
function makeCar(){let g=new THREE.Group();let red=mat(0xd84d32),dark=mat(0x17252b),glass=mat(0x84a9ae),yellow=mat(0xffd15c);
let body=mesh(new THREE.BoxGeometry(1.65,.48,3.15),red);body.position.y=.62;g.add(body);let hood=mesh(new THREE.BoxGeometry(1.45,.25,1.05),red);hood.position.set(0,.88,-.72);g.add(hood);
let cabin=mesh(new THREE.BoxGeometry(1.25,.52,1.3),glass);cabin.position.set(0,1.02,.38);g.add(cabin);let roof=mesh(new THREE.BoxGeometry(1.35,.12,1.45),dark);roof.position.set(0,1.31,.35);g.add(roof);
let spoiler=mesh(new THREE.BoxGeometry(1.8,.1,.16),dark);spoiler.position.set(0,1.25,1.55);g.add(spoiler);for(let x of [-.78,.78]){let w=mesh(new THREE.CylinderGeometry(.32,.32,.22,10),dark);w.rotation.z=Math.PI/2;w.position.set(x,.48,-.95);g.add(w);let w2=w.clone();w2.position.z=1.05;g.add(w2)}
for(let x of [-.58,.58]){let l=mesh(new THREE.BoxGeometry(.25,.16,.08),yellow);l.position.set(x,.78,-1.59);g.add(l);let r=mesh(new THREE.BoxGeometry(.28,.14,.08),mat(0xff3327));r.position.set(x,.73,1.59);g.add(r)}return g}
function makeTree(x,y,z,scale){let g=new THREE.Group(), trunk=mesh(new THREE.CylinderGeometry(.14,.2,1.5,6),mat(0x594335));trunk.position.y=.75;g.add(trunk);for(let i=0;i<3;i++){let c=mesh(new THREE.ConeGeometry(.9-i*.16,1.25,7),mat(i===0?0x214d3b:0x2d6947));c.position.y=1.45+i*.52;g.add(c)}g.position.set(x,y,z);g.scale.setScalar(scale);return g}
function makeRock(x,y,z){let r=mesh(new THREE.DodecahedronGeometry(.4+Math.random()*.4,0),mat(0x778087));r.position.set(x,y+.25,z);r.scale.y=.65;return r}
function setup(){S.scene=new THREE.Scene();S.scene.background=new THREE.Color(0x8db4b1);S.scene.fog=new THREE.Fog(0x8db4b1,55,240);S.camera=new THREE.PerspectiveCamera(62,innerWidth/innerHeight,.1,400);S.renderer=new THREE.WebGLRenderer({antialias:true});S.renderer.setSize(innerWidth,innerHeight);S.renderer.setPixelRatio(Math.min(devicePixelRatio,1.7));S.renderer.shadowMap.enabled=true;$('viewport').appendChild(S.renderer.domElement);let amb=new THREE.HemisphereLight(0xc9e9e5,0x30443c,1.8);S.scene.add(amb);let sun=new THREE.DirectionalLight(0xffefd0,3);sun.position.set(-40,80,25);sun.castShadow=true;sun.shadow.mapSize.set(1024,1024);S.scene.add(sun);
let ground=mesh(new THREE.PlaneGeometry(500,500),mat(0x52715c));ground.rotation.x=-Math.PI/2;ground.receiveShadow=true;S.scene.add(ground);
let pts=[];for(let i=0;i<12;i++){let a=i/12*Math.PI*2;let rad=34+Math.sin(a*3)*5+Math.cos(a*2)*3;pts.push(new THREE.Vector3(Math.cos(a)*rad,3+Math.sin(a*2.2)*2,Math.sin(a)*rad));}S.curve=new THREE.CatmullRomCurve3(pts,true,'catmullrom',.45);S.track=new THREE.Group();S.scene.add(S.track);
let roadMat=mat(0x343b3b), edgeMat=mat(0xc39b69);for(let i=0;i<150;i++){let t=i/150,p=S.curve.getPointAt(t),q=S.curve.getPointAt((t+.004)%1),ang=Math.atan2(q.z-p.z,q.x-p.x);let slab=mesh(new THREE.BoxGeometry(7,.12,2.6),roadMat);slab.position.copy(p);slab.position.y-=.08;slab.rotation.y=-ang+Math.PI/2;S.track.add(slab);for(let side of [-1,1]){let e=mesh(new THREE.BoxGeometry(.65,.14,2.55),edgeMat);e.position.copy(p);e.position.x+=Math.cos(ang+Math.PI/2)*side*3.55;e.position.z+=Math.sin(ang+Math.PI/2)*side*3.55;e.rotation.y=-ang+Math.PI/2;S.track.add(e)}}
for(let i=0;i<90;i++){let t=(i*.173)%1,p=S.curve.getPointAt(t),q=S.curve.getPointAt((t+.002)%1),a=Math.atan2(q.z-p.z,q.x-p.x),side=i%2?1:-1,d=9+Math.random()*15,x=p.x+Math.cos(a+Math.PI/2)*side*d,z=p.z+Math.sin(a+Math.PI/2)*side*d;S.scene.add(makeTree(x,p.y-2,z,.7+Math.random()*.7));if(i%7===0)S.scene.add(makeRock(x+side*2,p.y-2,z+2))}
let start=S.curve.getPointAt(0),next=S.curve.getPointAt(.01);let gate=new THREE.Group();for(let side of [-1,1]){let post=mesh(new THREE.BoxGeometry(.18,3,.18),mat(0xe85d36));post.position.set(start.x+side*3.5,start.y+1,start.z);gate.add(post)}let banner=mesh(new THREE.BoxGeometry(7,.65,.12),mat(0xe85d36));banner.position.set(start.x,start.y+2.3,start.z);gate.add(banner);gate.rotation.y=-Math.atan2(next.z-start.z,next.x-start.x)+Math.PI/2;S.scene.add(gate);
S.car=makeCar();S.scene.add(S.car);resize();}
function resize(){if(!S.renderer)return;S.camera.aspect=innerWidth/innerHeight;S.camera.updateProjectionMatrix();S.renderer.setSize(innerWidth,innerHeight)}
return {S,$,setup,resize,mat};
})();
// ── function: formatTime ──
function formatTime(ms){let m=Math.floor(ms/60000),s=Math.floor(ms/1000)%60,mm=Math.floor(ms%1000);return String(m).padStart(2,'0')+':'+String(s).padStart(2,'0')+'.'+String(mm).padStart(3,'0')}
// ── function: beep ──
function beep(freq,dur=.1){let S=Rally.S;if(!S.audio)return;let o=S.audio.createOscillator(),g=S.audio.createGain();o.frequency.value=freq;o.type='square';g.gain.setValueAtTime(.045,S.audio.currentTime);g.gain.exponentialRampToValueAtTime(.001,S.audio.currentTime+dur);o.connect(g).connect(S.audio.destination);o.start();o.stop(S.audio.currentTime+dur)}
// ── function: setCountdown ──
function setCountdown(){let el=Rally.$('countdown'),n=3;el.style.display='grid';el.querySelector('strong').textContent=n;beep(440);let iv=setInterval(()=>{n--;if(n>0){el.querySelector('strong').textContent=n;beep(440)}else{el.querySelector('strong').textContent='GO!';el.querySelector('strong').style.color='#8ee0a8';beep(880);Rally.S.started=true;Rally.S.startTime=performance.now();Rally.S.lapStart=Rally.S.startTime;setTimeout(()=>el.style.display='none',650);clearInterval(iv)}},900)}
// ── function: updateHUD ──
function updateHUD(now){let s=Rally.S;Rally.$('speed').textContent=String(Math.round(Math.abs(s.speed)*5.4)).padStart(3,'0');Rally.$('gear').textContent=s.speed<.2?'N':s.speed>7?'4':s.speed>4?'3':s.speed>2?'2':'1';Rally.$('lap').textContent=s.lap+' / 3';Rally.$('timer').textContent=formatTime(s.started?(now-s.startTime):0);Rally.$('best').textContent=s.best?formatTime(s.best):'--:--.---'}
// ── function: drawMap ──
function drawMap(){let s=Rally.S,c=document.getElementById('minimap'),x=c.getContext('2d');x.clearRect(0,0,180,130);x.strokeStyle='#9eb8a8';x.lineWidth=5;x.beginPath();for(let i=0;i<=80;i++){let p=s.curve.getPointAt(i/80),xx=90+p.x*1.45,yy=65+p.z*1.45;i?x.lineTo(xx,yy):x.moveTo(xx,yy)}x.stroke();let p=s.curve.getPointAt(s.t);x.fillStyle='#ffd36a';x.beginPath();x.arc(90+p.x*1.45,65+p.z*1.45,4,0,7);x.fill()}
// ── function: tick ──
function tick(now){let s=Rally.S,dt=Math.min((now-s.last)/1000,.04);s.last=now;if(s.started&&!s.paused&&!s.finished){let k=s.keys,gas=k.up||k.arrowup||k.w,brake=k.down||k.arrowdown||k.s,turn=(k.left||k.arrowleft||k.a?-1:0)+(k.right||k.arrowright||k.d?1:0),drift=k.space;let grip=Math.abs(s.offset)>3.2?.52:drift?.72:1;if(gas)s.speed+=dt*(10*grip);else s.speed-=dt*2.3;if(brake)s.speed-=dt*12;s.speed=Math.max(-2,Math.min(11,s.speed));s.offset+=turn*dt*(s.speed*.28+1.2)*(drift?1.3:1);s.offset*=1-dt*(drift?.35:1.9);if(Math.abs(s.offset)>3.7){s.speed-=dt*4;s.offset=Math.max(-4.5,Math.min(4.5,s.offset))}s.t=(s.t+s.speed*dt/125+1)%1;if(s.t<.015&&s.speed>2){let lapTime=now-s.lapStart;s.best=s.best?Math.min(s.best,lapTime):lapTime;s.lapStart=now;s.lap++;beep(700);if(s.lap>3){s.finished=true;Rally.$('final').textContent=formatTime(now-s.startTime);Rally.$('finalbest').textContent='BEST LAP '+formatTime(s.best);Rally.$('finish').classList.add('show');beep(1000,.3)}}let p=s.curve.getPointAt(s.t),q=s.curve.getPointAt((s.t+.002)%1),ang=Math.atan2(q.z-p.z,q.x-p.x),side=new THREE.Vector3(Math.cos(ang+Math.PI/2),0,Math.sin(ang+Math.PI/2));s.car.position.copy(p).addScaledVector(side,s.offset);s.car.position.y+=.18;s.car.rotation.y=-ang+Math.PI/2;s.car.rotation.z=-turn*.08*(s.speed/11);let target=new THREE.Vector3(Math.cos(ang),0,Math.sin(ang));target.multiplyScalar(-9).add(s.car.position);target.y+=4.2;let camTarget=s.camMode?s.car.position.clone().add(new THREE.Vector3(0,1,0)):s.car.position;s.camera.position.lerp(target,.075);s.camera.lookAt(camTarget)}updateHUD(now);drawMap();s.renderer.render(s.scene,s.camera);requestAnimationFrame(tick)}
// ── main ──
Rally.setup();
const s=Rally.S;s.last=performance.now();
function resetRace(){s.t=0;s.offset=0;s.speed=0;s.lap=1;s.started=false;s.paused=false;s.finished=false;s.best=null;s.car.position.set(0,0,0);Rally.$('pause').classList.remove('show');Rally.$('finish').classList.remove('show');setCountdown()}
function key(e,on){let k=e.key.toLowerCase();if(['arrowup','arrowdown','arrowleft','arrowright',' ','w','a','s','d'].includes(k))e.preventDefault();if(k==='p'&&on&&s.started&&!s.finished){s.paused=!s.paused;Rally.$('pause').classList.toggle('show',s.paused)}if(k==='r'&&on)resetRace();if(k==='c'&&on)s.camMode=1-s.camMode;s.keys[k===' ' ? 'space':k]=on;if(on&&!s.audio){s.audio=new AudioContext()}}
addEventListener('keydown',e=>key(e,true));addEventListener('keyup',e=>key(e,false));addEventListener('resize',Rally.resize);
Rally.$('resume').onclick=()=>{s.paused=false;Rally.$('pause').classList.remove('show')};Rally.$('restart').onclick=resetRace;Rally.$('finishRestart').onclick=resetRace;
document.querySelectorAll('#touch button').forEach(b=>{let k=b.dataset.key;b.addEventListener('pointerdown',e=>{e.preventDefault();s.keys[k]=true;if(!s.audio)s.audio=new AudioContext()});b.addEventListener('pointerup',()=>s.keys[k]=false);b.addEventListener('pointerleave',()=>s.keys[k]=false)});
setCountdown();requestAnimationFrame(tick);
</script>
</body>
</html>
<!-- agent-meta {"model":"openai/gpt-5.6-luna-pro","provider":"openrouter","persona":"composer","sessionId":"8d1a0094-b05b-41e3-a596-77f3d8b1fd49","tokensIn":370288,"tokensOut":20663,"tokensTotal":390951,"turns":12,"toolCalls":14,"failedToolCalls":1,"timestamp":"2026-07-14T03:49:07.229Z"} -->