← Canyon Run results

Canyon Run

GPT 5.6 Sol · full

Initial view of Canyon Run

Reviews & generation details

Reviews

Human review · Jul 17, 2026 · rubric 1

Historical path-based review. Association with these exact bytes is unverified.

Visual design
4 / 5
UX / feel
3 / 5
Works
4 / 5
Prompt spirit
5 / 5
Delight
4 / 5
Gorgeous design elements for everything from HUD to game objects/terrain; frustrating controls and weird speed bug for restarted runs

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 21,140 bytes · SHA-256 12d407bf0bbe
<!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>Helios Rift — Procedural Canyon Racer</title>
<style>
*{box-sizing:border-box}html,body{margin:0;width:100%;height:100%;overflow:hidden;background:#100c1f;font-family:Rajdhani,system-ui,sans-serif;color:#fff;user-select:none}
canvas{display:block;width:100%;height:100%;cursor:crosshair}
#ui{position:fixed;inset:0;pointer-events:none;z-index:3}
.vignette{position:absolute;inset:0;background:radial-gradient(ellipse at center,transparent 48%,rgba(17,7,27,.23) 75%,rgba(7,3,18,.7) 115%);mix-blend-mode:multiply}
.grain{position:absolute;inset:0;opacity:.08;background-image:url("data:image/svg+xml,%3Csvg viewBox='0 0 180 180' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.9' numOctaves='2' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)' opacity='.55'/%3E%3C/svg%3E")}
#top{position:absolute;left:5vw;right:5vw;top:4vh;display:flex;justify-content:space-between;align-items:flex-start;text-transform:uppercase;letter-spacing:.18em;text-shadow:0 1px 12px #160e31}
.brand{font-size:12px;color:#ffd7a8}.brand b{font-size:18px;display:block;letter-spacing:.35em;color:#fff;font-weight:600}.score{text-align:right;font-size:11px;color:#d8c8df}.score strong{display:block;font-size:31px;line-height:1;color:#fff;font-variant-numeric:tabular-nums;letter-spacing:.08em;font-weight:500}
#mult{position:absolute;right:5vw;top:20vh;text-align:right;font-size:11px;letter-spacing:.25em;color:#ffc77d;text-transform:uppercase;transition:transform .12s,filter .12s}#mult b{display:block;font-size:60px;line-height:.85;letter-spacing:-.05em;font-weight:500;color:#ffdfaa}#mult.hot{transform:scale(1.22);filter:drop-shadow(0 0 18px #ff7955)}
#near{position:absolute;top:30%;width:100%;text-align:center;opacity:0;transform:scale(.8);font-weight:600;font-size:16px;letter-spacing:.7em;color:#ffe6b7;text-transform:uppercase;text-shadow:0 0 20px #ff5c32;transition:.15s}#near.show{opacity:1;transform:scale(1)}
#bottom{position:absolute;left:6vw;right:6vw;bottom:5vh;display:flex;gap:5vw;align-items:flex-end}.meter{flex:1;max-width:420px}.meter:last-child{margin-left:auto;text-align:right}.label{font-size:10px;letter-spacing:.28em;text-transform:uppercase;color:#dacbdb;margin-bottom:7px;display:flex;justify-content:space-between}.track{height:3px;background:rgba(255,255,255,.16);position:relative;overflow:visible}.fill{height:100%;width:70%;background:#ffbd71;box-shadow:0 0 11px #ff6b48;transition:width .15s}.fill:after{content:"";position:absolute;right:0;top:-3px;width:2px;height:9px;background:white;box-shadow:0 0 8px white}#turboFill{background:#b4a8ff;box-shadow:0 0 12px #6c5cff}
#velocity{position:absolute;left:50%;bottom:3.2vh;transform:translateX(-50%);text-align:center;font-size:10px;letter-spacing:.3em;color:#d7c7d9}#velocity b{display:block;color:#fff;font-size:24px;letter-spacing:.05em;font-weight:500}
#boostHint{position:absolute;left:50%;bottom:13vh;transform:translateX(-50%);font-size:11px;letter-spacing:.25em;text-transform:uppercase;color:#d5c9ee;opacity:0;transition:.3s}#boostHint.ready{opacity:1;animation:pulse 1.3s infinite}@keyframes pulse{50%{filter:drop-shadow(0 0 8px #aaa1ff);opacity:.55}}
.screen{position:fixed;z-index:10;inset:0;display:flex;align-items:center;justify-content:center;background:linear-gradient(125deg,rgba(10,6,22,.88),rgba(30,12,39,.56));backdrop-filter:blur(6px);transition:.5s;pointer-events:auto}.screen.hidden{opacity:0;visibility:hidden;pointer-events:none}.card{text-align:center;width:min(620px,90vw)}.eyebrow{font-size:11px;letter-spacing:.65em;color:#ffad70;text-transform:uppercase}.title{font-size:clamp(52px,9vw,108px);line-height:.75;letter-spacing:-.04em;font-weight:600;margin:28px 0 18px;text-shadow:0 0 45px rgba(255,92,48,.28)}.title em{display:block;font-style:normal;color:#ffad70;font-weight:400}.sub{font-size:14px;letter-spacing:.15em;color:#d2c6d7;line-height:1.7;max-width:480px;margin:25px auto}.controls{display:flex;justify-content:center;gap:32px;margin:34px 0;color:#bfb1ca;font-size:11px;letter-spacing:.12em;text-transform:uppercase}.key{display:inline-flex;align-items:center;justify-content:center;min-width:30px;height:25px;border:1px solid rgba(255,255,255,.38);margin-right:8px;color:white;background:rgba(255,255,255,.05)}button{pointer-events:auto;border:1px solid #ffb476;background:transparent;color:#fff;font:600 13px Rajdhani;letter-spacing:.42em;text-transform:uppercase;padding:16px 31px 16px 36px;cursor:pointer;clip-path:polygon(8px 0,100% 0,calc(100% - 8px) 100%,0 100%);transition:.2s}button:hover{background:#ffad70;color:#211127;box-shadow:0 0 35px rgba(255,120,70,.45)}
#gameover .title{font-size:66px}.stats{display:flex;justify-content:center;gap:55px;margin:32px}.stat span{display:block;font-size:10px;letter-spacing:.25em;color:#bfaebf;text-transform:uppercase}.stat b{font-size:30px;font-weight:500;color:#ffd4a0}
#pause{position:absolute;inset:0;display:none;align-items:center;justify-content:center;font-size:20px;letter-spacing:.6em;background:rgba(10,5,22,.45);backdrop-filter:blur(4px);text-transform:uppercase;z-index:8}#pause.show{display:flex}
@media(max-width:650px){#mult b{font-size:42px}.controls{gap:12px;flex-wrap:wrap}.brand b{font-size:14px}.meter{max-width:none}.title{font-size:60px}.stats{gap:25px}.score strong{font-size:24px}}
</style>
</head><body>
<canvas id="game"></canvas>
<div id="ui">
 <div class="vignette"></div><div class="grain"></div>
 <div id="top"><div class="brand">Canyon sector <b>HELIOS / 07</b></div><div class="score">Distance score<strong id="score">000000</strong></div></div>
 <div id="mult">Proximity chain<b id="multVal">×1.0</b></div><div id="near">Near miss +</div>
 <div id="boostHint">Turbo ready · hold space</div>
 <div id="bottom"><div class="meter"><div class="label"><span>Core energy</span><span id="energyText">100%</span></div><div class="track"><div class="fill" id="energyFill"></div></div></div><div class="meter"><div class="label"><span>Turbo reserve</span><span id="turboText">0%</span></div><div class="track"><div class="fill" id="turboFill"></div></div></div></div>
 <div id="velocity">VELOCITY<b id="speed">000</b></div><div id="pause">Suspended</div>
</div>
<div class="screen" id="intro"><div class="card"><div class="eyebrow">An endless velocity ritual</div><div class="title">HELIOS<em>RIFT</em></div><div class="sub">Skim the canyon. Thread the monoliths. Harvest light before your core fades.</div><div class="controls"><span><i class="key">WASD</i> Fly</span><span><i class="key">Space</i> Turbo</span><span><i class="key">P</i> Pause</span></div><button id="start">Enter the rift</button></div></div>
<div class="screen hidden" id="gameover"><div class="card"><div class="eyebrow">Signal terminated</div><div class="title">FLIGHT<em>ENDED</em></div><div class="stats"><div class="stat"><span>Final score</span><b id="finalScore">0</b></div><div class="stat"><span>Max velocity</span><b id="maxSpeed">0</b></div><div class="stat"><span>Near misses</span><b id="misses">0</b></div></div><button id="restart">Fly again</button></div></div>
<script>
(()=>{'use strict';
const canvas=document.getElementById('game'),ctx=canvas.getContext('2d',{alpha:false});
let W,H,DPR=1, CX,CY, horizon;
function resize(){DPR=Math.min(2,devicePixelRatio||1);W=innerWidth;H=innerHeight;canvas.width=W*DPR;canvas.height=H*DPR;canvas.style.width=W+'px';canvas.style.height=H+'px';ctx.setTransform(DPR,0,0,DPR,0,0);CX=W/2;CY=H/2;horizon=H*.38} addEventListener('resize',resize);resize();
const $=id=>document.getElementById(id), ui={score:$('score'),mult:$('mult'),multVal:$('multVal'),near:$('near'),energy:$('energyFill'),energyText:$('energyText'),turbo:$('turboFill'),turboText:$('turboText'),speed:$('speed'),hint:$('boostHint'),intro:$('intro'),over:$('gameover'),pause:$('pause')};
const keys={};addEventListener('keydown',e=>{keys[e.code]=true;if(['Space','ArrowUp','ArrowDown','ArrowLeft','ArrowRight'].includes(e.code))e.preventDefault();if(e.code==='KeyP'&&state==='play'){paused=!paused;ui.pause.classList.toggle('show',paused);if(!paused)last=performance.now()}});addEventListener('keyup',e=>keys[e.code]=false);
let audio=null,hum=null,humGain=null;
function initAudio(){if(audio)return;audio=new (window.AudioContext||window.webkitAudioContext)();hum=audio.createOscillator();humGain=audio.createGain();const filter=audio.createBiquadFilter();hum.type='sawtooth';hum.frequency.value=54;filter.type='lowpass';filter.frequency.value=210;humGain.gain.value=.035;hum.connect(filter).connect(humGain).connect(audio.destination);hum.start()}
function tone(freq,dur,type='sine',vol=.12,slide=0){if(!audio)return;const o=audio.createOscillator(),g=audio.createGain();o.type=type;o.frequency.setValueAtTime(freq,audio.currentTime);o.frequency.exponentialRampToValueAtTime(Math.max(30,freq+slide),audio.currentTime+dur);g.gain.setValueAtTime(vol,audio.currentTime);g.gain.exponentialRampToValueAtTime(.001,audio.currentTime+dur);o.connect(g).connect(audio.destination);o.start();o.stop(audio.currentTime+dur)}
let state='intro',paused=false,last=0,time=0,worldZ=0,score=0,maxSpeed=0,nearCount=0,shake=0,flash=0;
let player,segments=[],particles=[],stars=[];
const PAL={sky1:'#211338',sky2:'#7b3154',sun:'#ffc47b',wallL:'#38223f',wallM:'#6b3546',wallHi:'#ad574f',ground:'#25182e'};
function rng(n){return Math.sin(n*91.773+13.1)*43758.5453%1}
function makeSegment(i){const z=i*160, difficulty=Math.min(1,score/180000);let center=Math.sin(i*.42)*42+Math.sin(i*.11)*55;let width=145-(difficulty*32)-Math.abs(Math.sin(i*.29))*25;const type=(i>4&&Math.abs(rng(i))>.62)?(Math.abs(rng(i+2))>.54?'mono':'squeeze'):'canyon';let obs=[];
 if(type==='mono'){const count=1+(Math.abs(rng(i+5))>.62?1:0);for(let k=0;k<count;k++){const side=k?1:-1;obs.push({x:center+side*(22+Math.abs(rng(i+k))*38),y:-4+Math.abs(rng(i+8+k))*25,r:13+difficulty*4,h:90,type:'mono',passed:false,near:false})}}
 if(type==='squeeze'){const gap=45-difficulty*12, gy=4+Math.abs(rng(i+4))*22;obs.push({x:center-width*.38,y:gy,r:width*.34-gap*.15,h:100,type:'blade',passed:false,near:false});obs.push({x:center+width*.38,y:gy,r:width*.34-gap*.15,h:100,type:'blade',passed:false,near:false})}
 let orb=null;if(i>2&&(i%4===0||type==='squeeze')){let ox=center+(rng(i+12))*width*.52, oy=4+Math.abs(rng(i+17))*35;if(type==='squeeze'){ox=center;oy=18}orb={x:ox,y:oy,r:4,taken:false}}
 return {i,z,center,width,type,obs,orb};}
function reset(){time=0;worldZ=0;score=0;maxSpeed=0;nearCount=0;shake=0;flash=0;segments=[];particles=[];stars=[];player={x:0,y:14,vx:0,vy:0,speed:126,energy:100,turbo:0,mult:1,roll:0,pitch:0,boost:false,dead:false};for(let i=0;i<40;i++)segments.push(makeSegment(i));for(let i=0;i<95;i++)stars.push({x:Math.random(),y:Math.random()*.39,s:Math.random()*1.5+.3,a:Math.random()*.55+.15});updateHUD()}
function start(){initAudio();audio.resume();reset();state='play';paused=false;ui.intro.classList.add('hidden');ui.over.classList.add('hidden');last=performance.now();requestAnimationFrame(loop)}
$('start').onclick=start;$('restart').onclick=start;
function project(x,y,z){const zz=Math.max(8,z-worldZ), f=Math.min(H*.95,W*.85);return{x:CX+(x-player.x*.42)*f/zz,y:horizon-(y-player.y*.14)*f/zz+f*20/zz,s:f/zz,z:zz}}
function poly(points,fill){ctx.beginPath();ctx.moveTo(points[0].x,points[0].y);for(let i=1;i<points.length;i++)ctx.lineTo(points[i].x,points[i].y);ctx.closePath();ctx.fillStyle=fill;ctx.fill()}
function update(dt){time+=dt;const steer=((keys.KeyD||keys.ArrowRight)?1:0)-((keys.KeyA||keys.ArrowLeft)?1:0), pitch=((keys.KeyW||keys.ArrowUp)?1:0)-((keys.KeyS||keys.ArrowDown)?1:0);
 player.vx+=(steer*92-player.vx*3.2)*dt;player.vy+=(pitch*76-player.vy*3.5)*dt;player.x+=player.vx*dt;player.y+=player.vy*dt;player.y=Math.max(-4,Math.min(60,player.y));player.roll+=(steer*.72-player.roll)*dt*6;player.pitch+=(pitch*.24-player.pitch)*dt*5;
 const difficulty=Math.min(1.2,score/190000);let target=132+difficulty*60+pitch*8;player.boost=!!keys.Space&&player.turbo>1;if(player.boost){target+=105;player.turbo-=28*dt;shake=Math.max(shake,1.5)}else{if(Math.abs(steer)<.1&&Math.abs(pitch)<.1&&player.speed>125)player.turbo=Math.min(100,player.turbo+4.2*dt)}player.speed+=(target-player.speed)*dt*(player.boost?2.7:1.15);maxSpeed=Math.max(maxSpeed,player.speed);worldZ+=player.speed*dt;score+=player.speed*dt*player.mult*.12;player.energy-=dt*(2.25+difficulty*.65+(player.boost?.8:0));
 if(hum){hum.frequency.setTargetAtTime(42+player.speed*.16,audio.currentTime,.06);humGain.gain.setTargetAtTime(player.boost?.065:.035,audio.currentTime,.05)}
 while(segments.length&&segments[0].z<worldZ-180)segments.shift();while(segments.length<40)segments.push(makeSegment(segments[segments.length-1].i+1));
 let nearest=999;for(const seg of segments){const dz=seg.z-worldZ;if(dz<-18||dz>35)continue;const wallDist=seg.width*.5-Math.abs(player.x-seg.center);nearest=Math.min(nearest,wallDist);if(wallDist<4){die()}for(const o of seg.obs){const d=Math.hypot(player.x-o.x,(player.y-o.y)*1.25)-o.r;nearest=Math.min(nearest,d);if(Math.abs(dz)<10&&d<4)die();if(dz<0&&!o.passed){o.passed=true;if(d<17&&d>4){nearMiss(2.5-d/12)}}}if(seg.orb&&!seg.orb.taken&&Math.abs(dz)<10&&Math.hypot(player.x-seg.orb.x,(player.y-seg.orb.y)*1.25)<10){seg.orb.taken=true;player.energy=Math.min(100,player.energy+28);player.turbo=Math.min(100,player.turbo+22);score+=500*player.mult;tone(480,.32,'sine',.12,520);burst(seg.orb.x,seg.orb.y,24,'#ffd790')}}
 if(nearest<24&&nearest>4){player.mult=Math.min(8,player.mult+dt*(24-nearest)*.045);shake=Math.max(shake,(24-nearest)*.05)}else player.mult=Math.max(1,player.mult-dt*.32);if(player.energy<=0)die();
 if(Math.random()<dt*(8+player.speed*.05))particles.push({x:Math.random()*W,y:horizon+Math.random()*(H-horizon),vx:(Math.random()-.5)*20,vy:35+Math.random()*120,life:1,a:.15+Math.random()*.3});particles.forEach(p=>{p.x+=p.vx*dt;p.y+=p.vy*dt*(player.speed/130);p.life-=dt});particles=particles.filter(p=>p.life>0);shake*=Math.pow(.07,dt);flash*=Math.pow(.01,dt);updateHUD()}
function nearMiss(bonus){player.mult=Math.min(8,player.mult+bonus);player.turbo=Math.min(100,player.turbo+12);score+=300*player.mult;nearCount++;shake=5;ui.near.classList.add('show');ui.mult.classList.add('hot');setTimeout(()=>{ui.near.classList.remove('show');ui.mult.classList.remove('hot')},300);tone(150,.42,'sawtooth',.08,650)}
function burst(x,y,n,c){const p=project(x,y,worldZ+15);for(let i=0;i<n;i++)particles.push({x:p.x,y:p.y,vx:(Math.random()-.5)*190,vy:(Math.random()-.5)*190,life:.7,a:.9,c})}
function die(){if(player.dead)return;player.dead=true;state='over';tone(95,1.2,'sawtooth',.16,-60);setTimeout(()=>{ui.over.classList.remove('hidden');$('finalScore').textContent=Math.floor(score).toLocaleString();$('maxSpeed').textContent=Math.floor(maxSpeed);$('misses').textContent=nearCount},500)}
function updateHUD(){ui.score.textContent=Math.floor(score).toString().padStart(6,'0');ui.multVal.textContent='×'+player.mult.toFixed(1);ui.energy.style.width=player.energy+'%';ui.energyText.textContent=Math.max(0,Math.ceil(player.energy))+'%';ui.turbo.style.width=player.turbo+'%';ui.turboText.textContent=Math.ceil(player.turbo)+'%';ui.speed.textContent=Math.floor(player.speed).toString().padStart(3,'0');ui.hint.classList.toggle('ready',player.turbo>25)}
function drawSky(){const g=ctx.createLinearGradient(0,0,0,H);g.addColorStop(0,PAL.sky1);g.addColorStop(.48,PAL.sky2);g.addColorStop(.8,'#d86d59');g.addColorStop(1,PAL.ground);ctx.fillStyle=g;ctx.fillRect(0,0,W,H);stars.forEach(s=>{ctx.globalAlpha=s.a*(.7+.3*Math.sin(time+s.x*15));ctx.fillStyle='#ffe3c8';ctx.fillRect(s.x*W,s.y*H,s.s,s.s)});ctx.globalAlpha=1;const sunX=W*.68,sunY=horizon*.76,r=Math.min(W,H)*.105;const sg=ctx.createRadialGradient(sunX,sunY,0,sunX,sunY,r*2);sg.addColorStop(0,'rgba(255,238,180,.85)');sg.addColorStop(.3,'rgba(255,174,104,.2)');sg.addColorStop(1,'rgba(255,130,80,0)');ctx.fillStyle=sg;ctx.fillRect(sunX-r*2,sunY-r*2,r*4,r*4);ctx.fillStyle='#ffd599';ctx.beginPath();ctx.arc(sunX,sunY,r,0,Math.PI*2);ctx.fill();ctx.fillStyle='rgba(103,47,76,.55)';for(let i=0;i<5;i++)ctx.fillRect(sunX-r,sunY-r*.35+i*r*.22,r*2,2+i*2)}
function drawWorld(){// ground speed ribbons
 const gg=ctx.createLinearGradient(0,horizon,0,H);gg.addColorStop(0,'#523047');gg.addColorStop(1,'#171222');ctx.fillStyle=gg;ctx.fillRect(0,horizon,W,H-horizon);
 for(let i=0;i<16;i++){let z=((i*95-worldZ)%1520+1520)%1520+30;let a=project(-220,-8,worldZ+z),b=project(220,-8,worldZ+z);ctx.strokeStyle=`rgba(255,165,110,${Math.max(0,.2-z/900)})`;ctx.lineWidth=1;ctx.beginPath();ctx.moveTo(a.x,a.y);ctx.lineTo(b.x,b.y);ctx.stroke()}
 const visible=segments.filter(s=>s.z>worldZ+5&&s.z<worldZ+1800).sort((a,b)=>b.z-a.z);for(const s of visible){const idx=segments.indexOf(s),next=segments[idx+1]||s;drawWalls(s,next);drawObjects(s)} }
function drawWalls(s,n){const z1=s.z,z2=n.z;for(const side of [-1,1]){const x1=s.center+side*s.width*.5,x2=n.center+side*n.width*.5;const p1=project(x1,-8,z1),p2=project(x2,-8,z2),t1=project(x1+side*(45+Math.abs(rng(s.i))*40),110,z1),t2=project(x2+side*(45+Math.abs(rng(n.i))*40),110,z2);let shade=side<0?PAL.wallL:PAL.wallM;poly([p1,p2,t2,t1],shade);const ridge1=project(x1+side*18,34,z1),ridge2=project(x2+side*18,40,z2);poly([p1,p2,ridge2,ridge1],side<0?'#4c2941':'#8c474d');ctx.strokeStyle='rgba(255,179,120,.18)';ctx.lineWidth=1;ctx.beginPath();ctx.moveTo(t1.x,t1.y);ctx.lineTo(t2.x,t2.y);ctx.stroke()}}
function drawObjects(s){const z=s.z;if(s.orb&&!s.orb.taken){const p=project(s.orb.x,s.orb.y,z),r=Math.max(1,p.s*s.orb.r);ctx.save();ctx.globalCompositeOperation='lighter';const g=ctx.createRadialGradient(p.x,p.y,0,p.x,p.y,r*3);g.addColorStop(0,'white');g.addColorStop(.2,'#fff0a7');g.addColorStop(.5,'rgba(255,129,68,.45)');g.addColorStop(1,'rgba(255,89,50,0)');ctx.fillStyle=g;ctx.beginPath();ctx.arc(p.x,p.y,r*3,0,7);ctx.fill();ctx.restore();ctx.save();ctx.translate(p.x,p.y);ctx.rotate(time*1.8);ctx.fillStyle='#fff5bd';polyLocal(r);ctx.restore()}
 for(const o of s.obs){const p=project(o.x,-8,z),top=project(o.x,o.h,z),r=Math.max(2,p.s*o.r);const left={x:p.x-r,y:p.y},right={x:p.x+r,y:p.y};const tl={x:top.x-r*.58,y:top.y},tr={x:top.x+r*.58,y:top.y};poly([left,right,tr,tl],o.type==='blade'?'#6b3851':'#4e2d49');poly([right,{x:right.x+r*.38,y:right.y-r*.12}, {x:tr.x+r*.25,y:tr.y},tr],'#ad594f');poly([tl,tr,{x:tr.x+r*.25,y:tr.y},{x:tl.x+r*.25,y:tl.y-r*.08}],'#d47861')}}
function polyLocal(r){ctx.beginPath();for(let i=0;i<6;i++){const a=i*Math.PI/3,x=Math.cos(a)*r,y=Math.sin(a)*r;(i?ctx.lineTo(x,y):ctx.moveTo(x,y))}ctx.closePath();ctx.fill()}
function drawCraft(){const x=CX+player.x*1.1,y=H*.72-player.y*2.0;ctx.save();ctx.translate(x,y);ctx.rotate(-player.roll);const sc=Math.min(W,H)/650;ctx.scale(sc,sc);if(player.boost){ctx.globalCompositeOperation='lighter';const eg=ctx.createLinearGradient(0,10,0,115);eg.addColorStop(0,'rgba(210,210,255,.9)');eg.addColorStop(1,'rgba(102,66,255,0)');ctx.fillStyle=eg;polyLocalTrail(0,22,14,105)}ctx.globalCompositeOperation='source-over';// shadow
ctx.fillStyle='rgba(8,5,20,.35)';ctx.beginPath();ctx.ellipse(0,52,68,13,0,0,7);ctx.fill();
poly([{x:-76,y:18},{x:-12,y:-4},{x:0,y:-30},{x:12,y:-4},{x:76,y:18},{x:17,y:24},{x:0,y:12},{x:-17,y:24}],'#c5bcc8');poly([{x:-76,y:18},{x:-12,y:-4},{x:0,y:12},{x:-17,y:24}],'#6f6378');poly([{x:76,y:18},{x:12,y:-4},{x:0,y:12},{x:17,y:24}],'#e4d9d5');poly([{x:-12,y:-4},{x:0,y:-30},{x:12,y:-4},{x:0,y:12}],'#36283f');ctx.fillStyle=player.boost?'#d9d6ff':'#ff9a66';ctx.shadowBlur=18;ctx.shadowColor=player.boost?'#8378ff':'#ff5f40';ctx.fillRect(-10,22,20,5);ctx.restore()}
function polyLocalTrail(x,y,w,h){ctx.beginPath();ctx.moveTo(x-w,y);ctx.lineTo(x+w,y);ctx.lineTo(x+3,y+h);ctx.lineTo(x-3,y+h);ctx.closePath();ctx.fill()}
function render(){ctx.save();let sx=(Math.random()-.5)*shake,sy=(Math.random()-.5)*shake;ctx.translate(sx,sy);drawSky();drawWorld();ctx.globalCompositeOperation='lighter';particles.forEach(p=>{ctx.globalAlpha=Math.max(0,p.life)*p.a;ctx.fillStyle=p.c||'#ffbc84';ctx.fillRect(p.x,p.y,1.5,p.vy>40?8:3)});ctx.globalAlpha=1;ctx.globalCompositeOperation='source-over';drawCraft();if(player.boost){ctx.fillStyle='rgba(154,128,255,.055)';ctx.fillRect(0,0,W,H);for(let i=0;i<18;i++){ctx.strokeStyle=`rgba(210,195,255,${Math.random()*.18})`;ctx.beginPath();let x=Math.random()*W,y=Math.random()*H;ctx.moveTo(x,y);ctx.lineTo(x+(x-CX)*.12,y+(y-CY)*.12);ctx.stroke()}}ctx.restore()}
function loop(now){if(state==='intro')return;let dt=Math.min(.035,(now-last)/1000||.016);last=now;if(!paused&&state==='play')update(dt);render();if(state==='play'||state==='over')requestAnimationFrame(loop)}
reset();render();
})();
</script></body></html>
<!-- agent-meta {"model":"openai/gpt-5.6-sol","provider":"openrouter","persona":"full","sessionId":"22ff97b8-03d2-4751-b8d9-4b4628d81af6","tokensIn":152009,"tokensOut":8551,"tokensTotal":160560,"turns":12,"toolCalls":11,"failedToolCalls":0,"timestamp":"2026-07-13T15:49:42.569Z"} -->