groove-dev 0.27.110 → 0.27.112

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. package/EMBEDDING_SERVICE_BUILD_PLAN.md +200 -0
  2. package/TRAINING_DATA_v2.md +9 -0
  3. package/moe-training/client/consent.js +47 -55
  4. package/moe-training/client/domain-tagger.js +3 -1
  5. package/moe-training/client/trajectory-capture.js +3 -2
  6. package/moe-training/shared/constants.js +1 -0
  7. package/moe-training/test/client/consent.test.js +23 -20
  8. package/moe-training/test/client/domain-tagger.test.js +6 -4
  9. package/node_modules/@groove-dev/cli/package.json +1 -1
  10. package/node_modules/@groove-dev/daemon/package.json +1 -1
  11. package/node_modules/@groove-dev/daemon/src/api.js +24 -42
  12. package/node_modules/@groove-dev/daemon/src/index.js +8 -10
  13. package/node_modules/@groove-dev/gui/dist/assets/{index-B8JomvGM.js → index-CHu5w3i3.js} +1 -1
  14. package/node_modules/@groove-dev/gui/dist/index.html +1 -1
  15. package/node_modules/@groove-dev/gui/package.json +1 -1
  16. package/node_modules/@groove-dev/gui/src/stores/groove.js +1 -1
  17. package/node_modules/moe-training/client/consent.js +47 -55
  18. package/node_modules/moe-training/client/domain-tagger.js +3 -1
  19. package/node_modules/moe-training/client/trajectory-capture.js +3 -2
  20. package/node_modules/moe-training/shared/constants.js +1 -0
  21. package/node_modules/moe-training/test/client/consent.test.js +23 -20
  22. package/node_modules/moe-training/test/client/domain-tagger.test.js +6 -4
  23. package/package.json +1 -1
  24. package/packages/cli/package.json +1 -1
  25. package/packages/daemon/package.json +1 -1
  26. package/packages/daemon/src/api.js +24 -42
  27. package/packages/daemon/src/index.js +8 -10
  28. package/packages/gui/dist/assets/{index-B8JomvGM.js → index-CHu5w3i3.js} +1 -1
  29. package/packages/gui/dist/index.html +1 -1
  30. package/packages/gui/package.json +1 -1
  31. package/packages/gui/src/stores/groove.js +1 -1
  32. package/TRAINING_DATA.md +0 -12
  33. package/codex/browser-racing-game/README.md +0 -45
  34. package/codex/browser-racing-game/dist/assets/index-D-sGTraQ.js +0 -47
  35. package/codex/browser-racing-game/dist/assets/index-S75nJv69.css +0 -1
  36. package/codex/browser-racing-game/dist/index.html +0 -14
  37. package/codex/browser-racing-game/index.html +0 -13
  38. package/codex/browser-racing-game/package-lock.json +0 -841
  39. package/codex/browser-racing-game/package.json +0 -15
  40. package/codex/browser-racing-game/src/app.css +0 -359
  41. package/codex/browser-racing-game/src/main.ts +0 -913
  42. package/codex/browser-racing-game/tsconfig.json +0 -20
  43. package/codex/browser-racing-game/vite.config.ts +0 -12
@@ -1,45 +0,0 @@
1
- # Apex Rush GP
2
-
3
- A polished, self-contained browser racing game built with Vite, TypeScript, CSS, Canvas, and browser-safe Web Audio APIs. It is inspired by fast F1/NASCAR-style racing with a top-down arcade feel.
4
-
5
- ## Features
6
-
7
- - Playable canvas racing with keyboard controls
8
- - 7 AI opponents with racing-line behavior
9
- - 3-lap race flow with countdown, lap tracking, positions, finish screen, and restart
10
- - Speed, handling, boost, off-track slowdown, car collisions, sparks, exhaust, camera shake, and engine tones
11
- - Responsive layout, HUD, boost meter, and minimap
12
- - No paid or external game assets; visuals are drawn with CSS and Canvas
13
-
14
- ## Controls
15
-
16
- | Key | Action |
17
- | --- | --- |
18
- | `W` / `↑` | Throttle |
19
- | `S` / `↓` | Brake / reverse |
20
- | `A` / `←` | Steer left |
21
- | `D` / `→` | Steer right |
22
- | `Space` | Boost |
23
-
24
- ## Run Locally
25
-
26
- ```bash
27
- npm install
28
- npm run dev
29
- ```
30
-
31
- Open the local Vite URL shown in your terminal.
32
-
33
- ## Build
34
-
35
- ```bash
36
- npm run build
37
- npm run preview
38
- ```
39
-
40
- ## Gameplay Tips
41
-
42
- - Stay on the asphalt; grass slows you down hard.
43
- - Use boost on exits and straights instead of mid-corner.
44
- - Light taps steer better than holding a direction at high speed.
45
- - AI cars can be bumped, but big impacts cost speed.
@@ -1,47 +0,0 @@
1
- (function(){let e=document.createElement(`link`).relList;if(e&&e.supports&&e.supports(`modulepreload`))return;for(let e of document.querySelectorAll(`link[rel="modulepreload"]`))n(e);new MutationObserver(e=>{for(let t of e)if(t.type===`childList`)for(let e of t.addedNodes)e.tagName===`LINK`&&e.rel===`modulepreload`&&n(e)}).observe(document,{childList:!0,subtree:!0});function t(e){let t={};return e.integrity&&(t.integrity=e.integrity),e.referrerPolicy&&(t.referrerPolicy=e.referrerPolicy),e.crossOrigin===`use-credentials`?t.credentials=`include`:e.crossOrigin===`anonymous`?t.credentials=`omit`:t.credentials=`same-origin`,t}function n(e){if(e.ep)return;e.ep=!0;let n=t(e);fetch(e.href,n)}})();var e={width:2400,height:1500},t=145,n=22,r=3,i=760,a=1040,o=7,s=[{x:520,y:1070},{x:350,y:760},{x:470,y:360},{x:880,y:230},{x:1320,y:335},{x:1585,y:245},{x:2040,y:390},{x:2180,y:740},{x:2020,y:1075},{x:1600,y:1235},{x:1260,y:1045},{x:940,y:1250}],c=[`Vega`,`Blitz`,`Nova`,`Apex`,`Turbo`,`Rook`,`Echo`],l=[`#ff4d6d`,`#f7b731`,`#45aaf2`,`#a55eea`,`#26de81`,`#fd9644`,`#d1d8e0`],u=Ee(),d=document.querySelector(`#app`);if(!d)throw Error(`Missing #app root`);d.innerHTML=`
2
- <main class="shell">
3
- <section class="hero-panel" aria-label="Game introduction">
4
- <div>
5
- <p class="eyebrow">Apex Rush GP</p>
6
- <h1>Canvas racing with boost, bruises, and bot rivals.</h1>
7
- <p class="lede">Thread the racing line, manage turbo, and out-drag seven AI competitors across ${r} laps.</p>
8
- </div>
9
- <div class="controls-card">
10
- <div><kbd>W</kbd><kbd>↑</kbd><span>Throttle</span></div>
11
- <div><kbd>S</kbd><kbd>↓</kbd><span>Brake / reverse</span></div>
12
- <div><kbd>A</kbd><kbd>D</kbd><kbd>←</kbd><kbd>→</kbd><span>Steer</span></div>
13
- <div><kbd>Space</kbd><span>Boost</span></div>
14
- </div>
15
- </section>
16
-
17
- <section class="game-card" aria-label="Apex Rush GP racing game">
18
- <canvas id="raceCanvas" aria-label="Top-down racing canvas"></canvas>
19
- <div class="hud top-left">
20
- <span class="label">Speed</span>
21
- <strong id="speedText">0</strong>
22
- <span class="unit">km/h</span>
23
- </div>
24
- <div class="hud top-center">
25
- <span class="label">Lap</span>
26
- <strong id="lapText">1/${r}</strong>
27
- </div>
28
- <div class="hud top-right">
29
- <span class="label">Place</span>
30
- <strong id="placeText">P1</strong>
31
- </div>
32
- <div class="boost-meter" aria-label="Boost meter"><span id="boostFill"></span></div>
33
- <canvas id="miniMap" class="mini-map" aria-label="Track minimap"></canvas>
34
- <div id="banner" class="banner">
35
- <p class="eyebrow">Ready?</p>
36
- <h2>Apex Rush GP</h2>
37
- <button id="startButton" class="primary-button">Start Race</button>
38
- </div>
39
- <div id="results" class="results hidden" aria-live="polite"></div>
40
- </section>
41
- </main>
42
- `;var f=Q(`#raceCanvas`),p=Q(`#miniMap`),ee=Q(`#speedText`),te=Q(`#lapText`),ne=Q(`#placeText`),re=Q(`#boostFill`),m=Q(`#banner`),h=Q(`#results`),ie=Q(`#startButton`),g=$(f),_=$(p),v=ae(s),y=v.reduce((e,t)=>e+t.length,0),b=new Set,x=[],S=[],C=`menu`,w=0,T=0,E=performance.now(),D={x:e.width/2,y:e.height/2,shake:0},O=null,k=!1;function ae(e){let t=0;return e.map((n,r)=>{let i=e[(r+1)%e.length],a=Ce(n,i),o={a:n,b:i,length:a,start:t};return t+=a,o})}var oe=class{context;master;engineOscillator;engineGain;constructor(){this.context=new AudioContext,this.master=this.context.createGain(),this.master.gain.value=.16,this.master.connect(this.context.destination),this.engineOscillator=this.context.createOscillator(),this.engineGain=this.context.createGain(),this.engineOscillator.type=`sawtooth`,this.engineOscillator.frequency.value=70,this.engineGain.gain.value=0,this.engineOscillator.connect(this.engineGain),this.engineGain.connect(this.master),this.engineOscillator.start()}async resume(){this.context.state!==`running`&&await this.context.resume()}updateEngine(e,t){let n=this.context.currentTime;this.engineOscillator.frequency.setTargetAtTime(65+e*170+(t?75:0),n,.04),this.engineGain.gain.setTargetAtTime(.015+e*.07+(t?.035:0),n,.05)}tone(e,t=.12,n=`triangle`,r=.08){let i=this.context.createOscillator(),a=this.context.createGain();i.type=n,i.frequency.value=e,a.gain.value=0,i.connect(a),a.connect(this.master),i.start();let o=this.context.currentTime;a.gain.linearRampToValueAtTime(r,o+.01),a.gain.exponentialRampToValueAtTime(.001,o+t),i.stop(o+t+.02)}crash(){this.tone(72,.18,`square`,.1),window.setTimeout(()=>this.tone(48,.12,`sawtooth`,.05),35)}lap(){this.tone(540,.1,`triangle`,.08),window.setTimeout(()=>this.tone(760,.14,`triangle`,.08),85)}countdown(e){this.tone(e===0?880:420,e===0?.28:.12,`sine`,.1)}};function A(){let e=y-170,t=R(e,0),n=[{id:`player`,name:`You`,color:`#33afbc`,isPlayer:!0,position:t.position,velocity:{x:0,y:0},angle:t.angle,speed:0,boost:100,lap:1,progress:e,totalProgress:0,lastProgress:e,lane:0,targetSpeed:i,finished:!1,finishTime:null,bumpFlash:0,offTrack:!1}];for(let t=0;t<o;t+=1){let r=Math.floor((t+1)/2),i=(t%2==0?-1:1)*(42+r*7),a=R(e-72*(t+1),i);n.push({id:`ai-${t}`,name:c[t],color:l[t],isPlayer:!1,position:a.position,velocity:{x:0,y:0},angle:a.angle,speed:0,boost:100,lap:1,progress:J(e-72*(t+1)),totalProgress:-72*(t+1),lastProgress:J(e-72*(t+1)),lane:i,targetSpeed:650+t*12+Math.random()*52,finished:!1,finishTime:null,bumpFlash:0,offTrack:!1})}return n}function j(){O??=new oe,O.resume(),C=`countdown`,x=A(),S=[],w=performance.now(),T=0,k=!1,h.classList.add(`hidden`),m.classList.remove(`hidden`),m.innerHTML=`<p class="eyebrow">Engines hot</p><h2 id="countdownText">3</h2>`,O.countdown(3)}function se(){C=`racing`,T=performance.now(),m.classList.add(`hidden`)}function ce(){C=`finished`,m.classList.add(`hidden`);let e=L(),t=e.findIndex(e=>e.isPlayer)+1;h.classList.remove(`hidden`),h.innerHTML=`
43
- <p class="eyebrow">Race Complete</p>
44
- <h2>${we(t)} place!</h2>
45
- <ol>${e.map((e,t)=>`<li><span>${t+1}. ${e.name}</span><strong>${Te(e.finishTime??performance.now())}</strong></li>`).join(``)}</ol>
46
- <button id="restartButton" class="primary-button">Race Again</button>
47
- `,h.querySelector(`#restartButton`)?.addEventListener(`click`,j)}function le(e,t){if(C===`countdown`){let n=(t-w)/1e3,r=document.querySelector(`#countdownText`),i=Math.max(0,3-Math.floor(n));r&&(r.textContent=i===0?`GO!`:String(i)),Math.abs(n-1)<e&&O?.countdown(2),Math.abs(n-2)<e&&O?.countdown(1),Math.abs(n-3)<e&&O?.countdown(0),n>=3.65&&se()}if(C===`racing`||C===`finished`){for(let n of x)n.finished||(n.isPlayer?ue(n,e):de(n,e,t),fe(n,t),n.bumpFlash=Math.max(0,n.bumpFlash-e*4));pe(e),me(e),N(e),I();let n=x[0];O?.updateEngine(Math.min(1,Math.abs(n.speed)/i),b.has(` `)&&n.boost>0&&C===`racing`),C===`racing`&&n.finished&&!k&&(k=!0,O?.lap(),ce())}else N(e),I()}function ue(e,n){let r=U(`w`,`arrowup`),o=U(`s`,`arrowdown`),s=U(`a`,`arrowleft`),c=U(`d`,`arrowright`),l=b.has(` `)&&e.boost>0&&e.speed>120;r&&(e.speed+=620*n),o&&(e.speed-=e.speed>60?840*n:430*n),!r&&!o&&(e.speed*=1-Math.min(.045,n*1.7)),l?(e.speed+=930*n,e.boost=Math.max(0,e.boost-35*n),B(e,`#59f3ff`,2)):e.boost=Math.min(100,e.boost+10*n),e.offTrack=z(e.position).distance>t-8;let u=l?a:i,d=e.offTrack?.66:1;e.speed=Y(e.speed,-220,u*d),e.offTrack&&(e.speed*=1-Math.min(.04,n*1.8),Math.random()<.7&&B(e,`#b28758`,1));let f=Number(c)-Number(s),p=Y(Math.abs(e.speed)/i,0,1);e.angle+=f*n*(1.45+p*2.1)*Math.sign(e.speed||1),e.velocity.x=Math.cos(e.angle)*e.speed,e.velocity.y=Math.sin(e.angle)*e.speed,e.position.x+=e.velocity.x*n,e.position.y+=e.velocity.y*n,M(e),Math.abs(e.speed)>180&&Math.random()<.25&&B(e,e.offTrack?`#b28758`:`#c9d8e8`,1)}function de(e,n,r){let i=130+Math.abs(e.speed)*.34,a=Math.sin(r/820+Number(e.id.slice(-1))*1.7)*14,o=R(e.progress+i,e.lane+a),s=q(Math.atan2(o.position.y-e.position.y,o.position.x-e.position.x)-e.angle);e.angle+=Y(s,-2.45*n,2.45*n),e.offTrack=z(e.position).distance>t-18;let c=Math.abs(q(o.angle-R(e.progress+20).angle)),l=e.targetSpeed*(1-Y(c*.7,0,.34))*(e.offTrack?.72:1);e.speed+=Y(l-e.speed,-520*n,360*n),e.boost>18&&Math.abs(s)<.16&&e.speed>280&&Math.random()<.008?(e.speed+=160*n,e.boost-=16*n,B(e,`#8cf7ff`,1)):e.boost=Math.min(100,e.boost+5*n),e.speed=Y(e.speed,0,850),e.velocity.x=Math.cos(e.angle)*e.speed,e.velocity.y=Math.sin(e.angle)*e.speed,e.position.x+=e.velocity.x*n,e.position.y+=e.velocity.y*n,M(e)}function fe(e,t){let n=z(e.position),i=e.lap;e.lastProgress=e.progress,e.progress=n.along;let a=e.progress-e.lastProgress;a<-y*.5&&(a+=y),a>y*.5&&(a-=y),a>-90&&(e.totalProgress+=Math.max(0,a),e.lap=Y(Math.floor(e.totalProgress/y)+1,1,r),e.isPlayer&&e.lap>i&&e.lap<=r&&O?.lap()),!e.finished&&e.totalProgress>=y*r-u&&(e.finished=!0,e.finishTime=t,e.speed*=.72)}function M(e){let n=z(e.position);n.distance>t+92&&(e.position.x=n.position.x+n.normal.x*Math.sign(n.signedOffset)*(t+92),e.position.y=n.position.y+n.normal.y*Math.sign(n.signedOffset)*(t+92),e.speed*=.62)}function pe(e){for(let t=0;t<x.length;t+=1)for(let n=t+1;n<x.length;n+=1){let r=x[t],i=x[n];if(r.finished||i.finished)continue;let a=i.position.x-r.position.x,o=i.position.y-r.position.y,s=Math.hypot(a,o);if(s>0&&s<42){let t={x:a/s,y:o/s},n=(42-s)*.55;r.position.x-=t.x*n,r.position.y-=t.y*n,i.position.x+=t.x*n,i.position.y+=t.y*n;let c=Math.abs(r.speed-i.speed)*.18+80;r.speed=Math.max(-120,r.speed-c*e*5),i.speed=Math.max(-120,i.speed-c*e*5),r.bumpFlash=1,i.bumpFlash=1,D.shake=Math.max(D.shake,Math.min(18,c*.04)),(r.isPlayer||i.isPlayer)&&O?.crash();for(let e=0;e<9;e+=1)S.push({position:{x:(r.position.x+i.position.x)/2,y:(r.position.y+i.position.y)/2},velocity:K({x:70+Math.random()*260,y:0},Math.random()*Math.PI*2),color:Math.random()>.45?`#ffd166`:`#ffffff`,life:.32,maxLife:.32,size:2+Math.random()*3})}}}function me(e){S=S.filter(t=>(t.life-=e,t.position.x+=t.velocity.x*e,t.position.y+=t.velocity.y*e,t.velocity.x*=1-Math.min(.08,e*4),t.velocity.y*=1-Math.min(.08,e*4),t.life>0))}function N(t){let n=x[0],r=n?.position.x??e.width/2,i=n?.position.y??e.height/2;D.x+=(r-D.x)*Math.min(1,t*5.5),D.y+=(i-D.y)*Math.min(1,t*5.5),D.shake=Math.max(0,D.shake-t*28)}function he(){let e=f.width/devicePixelRatio,t=f.height/devicePixelRatio;g.save(),g.scale(devicePixelRatio,devicePixelRatio),g.clearRect(0,0,e,t);let n=(Math.random()-.5)*D.shake,r=(Math.random()-.5)*D.shake;g.translate(e/2-D.x+n,t/2-D.y+r),ge(g),ve(g);for(let e of S)be(g,e);for(let e of[...x].sort((e,t)=>e.position.y-t.position.y))ye(g,e);g.restore(),xe(g,e,t),Se()}function ge(t){let n=t.createLinearGradient(0,0,e.width,e.height);n.addColorStop(0,`#102315`),n.addColorStop(.5,`#18351f`),n.addColorStop(1,`#0b1c13`),t.fillStyle=n,t.fillRect(0,0,e.width,e.height),t.globalAlpha=.18,t.strokeStyle=`#d8f5a2`,t.lineWidth=2;for(let n=-100;n<e.width+100;n+=92)t.beginPath(),t.moveTo(n,0),t.lineTo(n+360,e.height),t.stroke();t.globalAlpha=1,P(t,1430,92,455,95,`#172336`),P(t,1670,1325,510,88,`#2a1731`),_e(t)}function P(e,t,n,r,i,a){e.fillStyle=`rgba(0,0,0,0.24)`,Z(e,t+10,n+12,r,i,16),e.fill(),e.fillStyle=a,Z(e,t,n,r,i,16),e.fill();for(let r=0;r<4;r+=1)for(let i=0;i<22;i+=1)e.fillStyle=[`#33afbc`,`#f7b731`,`#ff4d6d`,`#f8fbff`][i%4],e.globalAlpha=.72,e.fillRect(t+18+i*19,n+16+r*17,10,7);e.globalAlpha=1}function _e(e){e.fillStyle=`#202936`,Z(e,1040,620,430,245,24),e.fill(),e.fillStyle=`#101722`,Z(e,1080,655,350,52,12),e.fill(),e.fillStyle=`#33afbc`,e.font=`700 32px Inter, sans-serif`,e.fillText(`APEX RUSH`,1110,693)}function ve(e){F(e,t*2+n*2,`#f7f9fb`),F(e,t*2+n,`#d92238`,[36,32]),F(e,t*2,`#29313c`),F(e,7,`rgba(255,255,255,0.28)`,[30,26]),F(e,3,`rgba(255,255,255,0.55)`);let r=R(y-u);e.save(),e.translate(r.position.x,r.position.y),e.rotate(r.angle+Math.PI/2);for(let t=-4;t<4;t+=1)for(let n=-3;n<3;n+=1)e.fillStyle=(t+n)%2==0?`#ffffff`:`#111827`,e.fillRect(n*20,t*18,20,18);e.restore()}function F(e,t,n,r=[]){e.save(),e.lineJoin=`round`,e.lineCap=`round`,e.lineWidth=t,e.strokeStyle=n,e.setLineDash(r),e.beginPath(),s.forEach((t,n)=>{n===0?e.moveTo(t.x,t.y):e.lineTo(t.x,t.y)}),e.closePath(),e.stroke(),e.restore()}function ye(e,t){e.save(),e.translate(t.position.x,t.position.y),e.rotate(t.angle),e.fillStyle=`rgba(0,0,0,0.32)`,Z(e,-23,-8,46,30,8),e.fill(),e.fillStyle=t.bumpFlash>0?`#ffffff`:t.color,Z(e,-25,-14,50,28,8),e.fill(),e.fillStyle=`#07111e`,Z(e,-5,-10,18,20,5),e.fill(),e.fillStyle=`#f8fbff`,e.fillRect(11,-9,8,5),e.fillRect(11,4,8,5),e.fillStyle=`#111827`,e.fillRect(-18,-18,12,7),e.fillRect(-18,11,12,7),e.fillRect(9,-18,12,7),e.fillRect(9,11,12,7),t.isPlayer&&(e.strokeStyle=`#8df8ff`,e.lineWidth=3,e.globalAlpha=.75,Z(e,-31,-20,62,40,12),e.stroke()),e.restore(),e.fillStyle=`rgba(2,6,23,0.72)`,e.font=`700 20px Inter, sans-serif`,e.textAlign=`center`,e.fillText(t.name,t.position.x,t.position.y-32)}function be(e,t){e.save(),e.globalAlpha=Y(t.life/t.maxLife,0,1),e.fillStyle=t.color,e.beginPath(),e.arc(t.position.x,t.position.y,t.size,0,Math.PI*2),e.fill(),e.restore()}function xe(e,t,n){let r=e.createRadialGradient(t/2,n/2,n*.2,t/2,n/2,t*.72);r.addColorStop(0,`rgba(0,0,0,0)`),r.addColorStop(1,`rgba(0,0,0,0.45)`),e.fillStyle=r,e.fillRect(0,0,t,n)}function Se(){let t=p.width/devicePixelRatio,n=p.height/devicePixelRatio;_.save(),_.scale(devicePixelRatio,devicePixelRatio),_.clearRect(0,0,t,n),_.fillStyle=`rgba(7, 17, 30, 0.82)`,Z(_,0,0,t,n,18),_.fill(),_.translate(13,10);let r=Math.min((t-26)/e.width,(n-22)/e.height);_.scale(r,r),_.lineWidth=46,_.strokeStyle=`#344154`,_.lineCap=`round`,_.lineJoin=`round`,_.beginPath(),s.forEach((e,t)=>{t===0?_.moveTo(e.x,e.y):_.lineTo(e.x,e.y)}),_.closePath(),_.stroke();for(let e of x)_.fillStyle=e.isPlayer?`#8df8ff`:e.color,_.beginPath(),_.arc(e.position.x,e.position.y,e.isPlayer?34:24,0,Math.PI*2),_.fill();_.restore()}function I(){let e=x[0];if(!e)return;let t=L().findIndex(e=>e.isPlayer)+1;ee.textContent=String(Math.max(0,Math.round(Math.abs(e.speed)*.42))),te.textContent=`${Math.min(r,e.lap)}/${r}`,ne.textContent=`P${t}`,re.style.width=`${e.boost}%`}function L(){return[...x].sort((e,t)=>e.finished&&t.finished?(e.finishTime??0)-(t.finishTime??0):e.finished?-1:t.finished?1:t.totalProgress-e.totalProgress)}function R(e,t=0){let n=J(e),r=v.find(e=>n>=e.start&&n<=e.start+e.length)??v[v.length-1],i=Y((n-r.start)/r.length,0,1),a=X(r.a.x,r.b.x,i),o=X(r.a.y,r.b.y,i),s=G({x:r.b.x-r.a.x,y:r.b.y-r.a.y}),c={x:-s.y,y:s.x};return{position:{x:a+c.x*t,y:o+c.y*t},tangent:s,normal:c,angle:Math.atan2(s.y,s.x)}}function z(e){let t=null;for(let n of v){let r={x:n.b.x-n.a.x,y:n.b.y-n.a.y},i=Y(W({x:e.x-n.a.x,y:e.y-n.a.y},r)/W(r,r),0,1),a={x:n.a.x+r.x*i,y:n.a.y+r.y*i},o=G(r),s={x:-o.y,y:o.x},c={x:e.x-a.x,y:e.y-a.y},l=W(c,s),u={position:a,tangent:o,normal:s,angle:Math.atan2(o.y,o.x),distance:Math.hypot(c.x,c.y),along:n.start+n.length*i,signedOffset:l};(!t||u.distance<t.distance)&&(t=u)}if(!t)throw Error(`Track has no segments`);return t}function B(e,t,n){for(let r=0;r<n;r+=1){let n=K({x:-28,y:(Math.random()-.5)*17},e.angle);S.push({position:{x:e.position.x+n.x,y:e.position.y+n.y},velocity:K({x:-80-Math.random()*120,y:(Math.random()-.5)*90},e.angle),color:t,life:.28+Math.random()*.28,maxLife:.56,size:3+Math.random()*5})}}function V(){let e=f.getBoundingClientRect();f.width=Math.floor(e.width*devicePixelRatio),f.height=Math.floor(e.height*devicePixelRatio),p.width=Math.floor(p.clientWidth*devicePixelRatio),p.height=Math.floor(p.clientHeight*devicePixelRatio)}function H(e){let t=Math.min(.033,(e-E)/1e3);E=e,le(t,e),he(),requestAnimationFrame(H)}function U(...e){return e.some(e=>b.has(e))}function Ce(e,t){return Math.hypot(e.x-t.x,e.y-t.y)}function W(e,t){return e.x*t.x+e.y*t.y}function G(e){let t=Math.hypot(e.x,e.y)||1;return{x:e.x/t,y:e.y/t}}function K(e,t){let n=Math.cos(t),r=Math.sin(t);return{x:e.x*n-e.y*r,y:e.x*r+e.y*n}}function q(e){return Math.atan2(Math.sin(e),Math.cos(e))}function J(e){return(e%y+y)%y}function Y(e,t,n){return Math.min(n,Math.max(t,e))}function X(e,t,n){return e+(t-e)*n}function we(e){return`${e}${e===1?`st`:e===2?`nd`:e===3?`rd`:`th`}`}function Te(e){if(!T)return`--:--`;let t=Math.max(0,e-T),n=Math.floor(t/1e3),r=Math.floor(t%1e3/10).toString().padStart(2,`0`);return`${Math.floor(n/60)}:${String(n%60).padStart(2,`0`)}.${r}`}function Ee(){return 12}function Z(e,t,n,r,i,a){let o=Math.min(a,r/2,i/2);e.beginPath(),e.moveTo(t+o,n),e.arcTo(t+r,n,t+r,n+i,o),e.arcTo(t+r,n+i,t,n+i,o),e.arcTo(t,n+i,t,n,o),e.arcTo(t,n,t+r,n,o),e.closePath()}function Q(e){let t=document.querySelector(e);if(!t)throw Error(`Missing required element: ${e}`);return t}function $(e){let t=e.getContext(`2d`);if(!t)throw Error(`Canvas 2D context is unavailable`);return t}window.addEventListener(`keydown`,e=>{[`ArrowUp`,`ArrowDown`,`ArrowLeft`,`ArrowRight`,` `].includes(e.key)&&e.preventDefault(),b.add(e.key.toLowerCase())}),window.addEventListener(`keyup`,e=>{b.delete(e.key.toLowerCase())}),window.addEventListener(`resize`,V),ie.addEventListener(`click`,j),x=A(),V(),requestAnimationFrame(H);
@@ -1 +0,0 @@
1
- :root{--color-accent:#33afbc;--color-success:#31d07f;--color-warning:#f7b731;--color-danger:#ff4d6d;--color-info:#45aaf2;--color-purple:#a55eea;--color-orange:#fd9644;--color-surface-0:#050913;--color-surface-1:#08111c;--color-surface-2:#101a28;--color-surface-3:#162235;--color-surface-4:#233247;--color-surface-5:#304259;--color-surface-6:#40546e;--color-text-0:#f8fbff;--color-text-1:#d9e5f2;--color-text-2:#a9bbcf;--color-text-3:#73869b;--color-text-4:#536579;--color-border:#b4cde638;--color-border-subtle:#b4cde61f;--font-sans:Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;--font-mono:"JetBrains Mono", "SF Mono", ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;color:var(--color-text-0);background:var(--color-surface-0);font-family:var(--font-sans);font-synthesis:none;text-rendering:geometricprecision}*{box-sizing:border-box}body{background:radial-gradient(circle at 0 0,#33afbc3d,#0000 34rem),radial-gradient(circle at 82% 0,#ff4d6d2e,#0000 28rem),linear-gradient(135deg,#050913 0%,#07111e 52%,#0d1322 100%);min-width:320px;min-height:100vh;margin:0;overflow-x:hidden}button,kbd{font:inherit}.shell{grid-template-rows:auto minmax(560px,1fr);gap:18px;width:min(1480px,100%);min-height:100vh;margin:0 auto;padding:clamp(14px,2vw,28px);display:grid}.hero-panel{border:1px solid var(--color-border-subtle);background:linear-gradient(135deg,#101a28eb,#08111ca3);border-radius:28px;grid-template-columns:1fr auto;align-items:end;gap:18px;padding:clamp(18px,2vw,28px);display:grid;box-shadow:0 24px 80px #00000047,inset 0 1px #ffffff14}.eyebrow{color:var(--color-accent);letter-spacing:.18em;text-transform:uppercase;margin:0 0 8px;font-size:.72rem;font-weight:800}h1,h2,p{margin-top:0}h1{letter-spacing:-.07em;max-width:840px;margin-bottom:8px;font-size:clamp(2rem,5vw,4.9rem);line-height:.92}h2{letter-spacing:-.06em;margin-bottom:16px;font-size:clamp(3rem,9vw,7rem);line-height:.9}.lede{max-width:710px;color:var(--color-text-2);margin-bottom:0;font-size:clamp(.95rem,2vw,1.1rem)}.controls-card{border:1px solid var(--color-border-subtle);background:#05091373;border-radius:20px;gap:8px;min-width:min(360px,100%);padding:14px;display:grid}.controls-card div{color:var(--color-text-2);align-items:center;gap:8px;font-size:.82rem;font-weight:700;display:flex}kbd{border:1px solid var(--color-border);min-width:34px;color:var(--color-text-0);background:linear-gradient(180deg, var(--color-surface-4), var(--color-surface-2));font-family:var(--font-mono);text-align:center;border-bottom-color:#ffffff61;border-radius:9px;padding:6px 8px;font-size:.72rem;box-shadow:0 4px #00000047}.game-card{border:1px solid var(--color-border);isolation:isolate;background:#06101b;border-radius:30px;min-height:560px;position:relative;overflow:hidden;box-shadow:0 32px 120px #00000080,inset 0 1px #ffffff14}#raceCanvas{cursor:crosshair;width:100%;height:100%;min-height:560px;display:block}.hud,.boost-meter,.mini-map,.banner,.results{z-index:2;position:absolute}.hud{border:1px solid var(--color-border-subtle);-webkit-backdrop-filter:blur(16px);backdrop-filter:blur(16px);background:#07111ebd;border-radius:18px;min-width:118px;padding:10px 14px;top:18px;box-shadow:0 12px 36px #00000040}.top-left{left:18px}.top-center{text-align:center;left:50%;transform:translate(-50%)}.top-right{text-align:right;right:18px}.label,.unit{color:var(--color-text-3);letter-spacing:.14em;text-transform:uppercase;font-size:.66rem;font-weight:800;display:block}.hud strong{color:var(--color-text-0);font-family:var(--font-mono);font-size:clamp(1.3rem,3vw,2.2rem);line-height:1;display:inline-block}.boost-meter{background:#07111eb8;border:1px solid #8df8ff52;border-radius:999px;height:15px;bottom:18px;left:18px;right:18px;overflow:hidden;box-shadow:inset 0 0 18px #0000006b}.boost-meter span{border-radius:inherit;background:linear-gradient(90deg, var(--color-accent), #8df8ff, var(--color-warning));width:100%;height:100%;transition:width .12s linear;display:block;box-shadow:0 0 22px #33afbcd9}.mini-map{border:1px solid var(--color-border-subtle);border-radius:18px;width:min(220px,36vw);height:138px;bottom:44px;right:18px;box-shadow:0 18px 46px #00000059}.banner,.results{text-align:center;-webkit-backdrop-filter:blur(20px);backdrop-filter:blur(20px);background:linear-gradient(145deg,#08111cf0,#101a28e6);border:1px solid #8df8ff33;border-radius:30px;width:min(560px,100% - 36px);padding:clamp(22px,4vw,38px);inset:50% auto auto 50%;transform:translate(-50%,-50%);box-shadow:0 28px 90px #00000080,inset 0 1px #ffffff14}.banner:before,.results:before{content:"";z-index:-1;border-radius:inherit;background:conic-gradient(from 180deg, var(--color-accent), var(--color-danger), var(--color-warning), var(--color-accent));opacity:.18;filter:blur(12px);position:absolute;inset:-2px}.primary-button{color:#021016;background:linear-gradient(135deg, #8df8ff, var(--color-accent));letter-spacing:-.02em;cursor:pointer;border:0;border-radius:999px;padding:14px 24px;font-weight:900;transition:transform .18s,filter .18s;box-shadow:0 12px 30px #33afbc61}.primary-button:hover{filter:brightness(1.08);transform:translateY(-2px)scale(1.02)}.primary-button:active{transform:translateY(1px)scale(.99)}.results ol{max-height:min(42vh,360px);margin:0 0 20px;padding:0;list-style:none;overflow:auto}.results li{border-bottom:1px solid var(--color-border-subtle);color:var(--color-text-1);justify-content:space-between;gap:14px;padding:10px 0;font-weight:800;display:flex}.results strong{color:var(--color-accent);font-family:var(--font-mono)}.hidden{display:none!important}@media (width<=840px){.shell{grid-template-rows:auto minmax(620px,1fr);padding:10px}.hero-panel{grid-template-columns:1fr}.controls-card{grid-template-columns:repeat(2,minmax(0,1fr))}.controls-card div{flex-wrap:wrap;align-items:flex-start}.hud{min-width:auto;padding:8px 10px}.mini-map{width:165px;height:108px}}@media (width<=560px){.hero-panel{display:none}.shell{grid-template-rows:minmax(100svh,1fr)}.game-card,#raceCanvas{min-height:calc(100svh - 20px)}.top-center{top:86px}}
@@ -1,14 +0,0 @@
1
- <!doctype html>
2
- <html lang="en">
3
- <head>
4
- <meta charset="UTF-8" />
5
- <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
- <meta name="theme-color" content="#08111c" />
7
- <title>Apex Rush GP</title>
8
- <script type="module" crossorigin src="/assets/index-D-sGTraQ.js"></script>
9
- <link rel="stylesheet" crossorigin href="/assets/index-S75nJv69.css">
10
- </head>
11
- <body>
12
- <div id="app"></div>
13
- </body>
14
- </html>
@@ -1,13 +0,0 @@
1
- <!doctype html>
2
- <html lang="en">
3
- <head>
4
- <meta charset="UTF-8" />
5
- <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
- <meta name="theme-color" content="#08111c" />
7
- <title>Apex Rush GP</title>
8
- </head>
9
- <body>
10
- <div id="app"></div>
11
- <script type="module" src="/src/main.ts"></script>
12
- </body>
13
- </html>