Void2377 commited on
Commit
53df2d9
·
verified ·
1 Parent(s): 8a4db60

Upload folder using huggingface_hub

Browse files
Files changed (1) hide show
  1. index.html +724 -19
index.html CHANGED
@@ -1,19 +1,724 @@
1
- <!doctype html>
2
- <html>
3
- <head>
4
- <meta charset="utf-8" />
5
- <meta name="viewport" content="width=device-width" />
6
- <title>My static Space</title>
7
- <link rel="stylesheet" href="style.css" />
8
- </head>
9
- <body>
10
- <div class="card">
11
- <h1>Welcome to your static Space!</h1>
12
- <p>You can modify this app directly by editing <i>index.html</i> in the Files and versions tab.</p>
13
- <p>
14
- Also don't forget to check the
15
- <a href="https://huggingface.co/docs/hub/spaces" target="_blank">Spaces documentation</a>.
16
- </p>
17
- </div>
18
- </body>
19
- </html>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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, maximum-scale=1.0, user-scalable=no">
6
+ <title>Neon Velocity: Cyber Racing</title>
7
+ <!-- Importing Google Fonts for Cyberpunk Aesthetic -->
8
+ <link rel="preconnect" href="https://fonts.googleapis.com">
9
+ <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
10
+ <link href="https://fonts.googleapis.com/css2?family=Orbitron:wght@400;700;900&family=Rajdhani:wght@300;500;700&display=swap" rel="stylesheet">
11
+
12
+ <style>
13
+ :root {
14
+ --primary: #00f3ff; /* Cyan */
15
+ --secondary: #ff0055; /* Magenta */
16
+ --accent: #ffee00; /* Yellow */
17
+ --bg-dark: #050510;
18
+ --glass: rgba(255, 255, 255, 0.05);
19
+ --border: rgba(255, 255, 255, 0.1);
20
+ --font-display: 'Orbitron', sans-serif;
21
+ --font-body: 'Rajdhani', sans-serif;
22
+ }
23
+
24
+ * {
25
+ box-sizing: border-box;
26
+ margin: 0;
27
+ padding: 0;
28
+ user-select: none;
29
+ -webkit-user-select: none;
30
+ }
31
+
32
+ body {
33
+ background-color: var(--bg-dark);
34
+ color: white;
35
+ font-family: var(--font-body);
36
+ overflow: hidden;
37
+ height: 100vh;
38
+ width: 100vw;
39
+ display: flex;
40
+ flex-direction: column;
41
+ }
42
+
43
+ /* --- Header & Branding --- */
44
+ header {
45
+ position: absolute;
46
+ top: 0;
47
+ left: 0;
48
+ width: 100%;
49
+ padding: 1rem 2rem;
50
+ display: flex;
51
+ justify-content: space-between;
52
+ align-items: center;
53
+ z-index: 100;
54
+ pointer-events: none; /* Let clicks pass through to canvas if needed */
55
+ }
56
+
57
+ .brand {
58
+ font-family: var(--font-display);
59
+ font-size: 1.5rem;
60
+ font-weight: 900;
61
+ text-transform: uppercase;
62
+ letter-spacing: 2px;
63
+ text-shadow: 0 0 10px var(--primary);
64
+ pointer-events: auto;
65
+ }
66
+
67
+ .brand span {
68
+ color: var(--secondary);
69
+ }
70
+
71
+ .built-with {
72
+ font-size: 0.8rem;
73
+ color: rgba(255,255,255,0.5);
74
+ text-decoration: none;
75
+ border: 1px solid var(--border);
76
+ padding: 5px 10px;
77
+ border-radius: 20px;
78
+ backdrop-filter: blur(5px);
79
+ transition: all 0.3s ease;
80
+ }
81
+
82
+ .built-with:hover {
83
+ background: var(--primary);
84
+ color: var(--bg-dark);
85
+ border-color: var(--primary);
86
+ box-shadow: 0 0 15px var(--primary);
87
+ }
88
+
89
+ /* --- Game Container --- */
90
+ #game-container {
91
+ position: relative;
92
+ width: 100%;
93
+ height: 100%;
94
+ display: flex;
95
+ justify-content: center;
96
+ align-items: center;
97
+ background: radial-gradient(circle at center, #1a1a2e 0%, #000000 100%);
98
+ }
99
+
100
+ canvas {
101
+ box-shadow: 0 0 50px rgba(0, 243, 255, 0.1);
102
+ max-width: 100%;
103
+ max-height: 100%;
104
+ }
105
+
106
+ /* --- UI Overlays --- */
107
+ .overlay {
108
+ position: absolute;
109
+ top: 0;
110
+ left: 0;
111
+ width: 100%;
112
+ height: 100%;
113
+ display: flex;
114
+ flex-direction: column;
115
+ justify-content: center;
116
+ align-items: center;
117
+ background: rgba(0, 0, 0, 0.7);
118
+ backdrop-filter: blur(8px);
119
+ z-index: 50;
120
+ transition: opacity 0.3s ease;
121
+ }
122
+
123
+ .overlay.hidden {
124
+ opacity: 0;
125
+ pointer-events: none;
126
+ }
127
+
128
+ h1 {
129
+ font-family: var(--font-display);
130
+ font-size: 4rem;
131
+ text-transform: uppercase;
132
+ background: linear-gradient(to right, var(--primary), var(--secondary));
133
+ -webkit-background-clip: text;
134
+ -webkit-text-fill-color: transparent;
135
+ margin-bottom: 1rem;
136
+ text-align: center;
137
+ filter: drop-shadow(0 0 20px rgba(0, 243, 255, 0.5));
138
+ animation: pulse 2s infinite;
139
+ }
140
+
141
+ .instructions {
142
+ margin-bottom: 2rem;
143
+ text-align: center;
144
+ color: #ccc;
145
+ font-size: 1.2rem;
146
+ line-height: 1.6;
147
+ }
148
+
149
+ .key-badge {
150
+ display: inline-block;
151
+ background: var(--glass);
152
+ border: 1px solid var(--primary);
153
+ padding: 5px 10px;
154
+ border-radius: 4px;
155
+ color: var(--primary);
156
+ font-weight: bold;
157
+ margin: 0 2px;
158
+ }
159
+
160
+ button.btn-primary {
161
+ background: transparent;
162
+ color: var(--primary);
163
+ font-family: var(--font-display);
164
+ font-size: 1.5rem;
165
+ padding: 1rem 3rem;
166
+ border: 2px solid var(--primary);
167
+ border-radius: 4px;
168
+ cursor: pointer;
169
+ text-transform: uppercase;
170
+ letter-spacing: 2px;
171
+ transition: all 0.2s ease;
172
+ box-shadow: 0 0 15px rgba(0, 243, 255, 0.2);
173
+ }
174
+
175
+ button.btn-primary:hover {
176
+ background: var(--primary);
177
+ color: var(--bg-dark);
178
+ box-shadow: 0 0 30px var(--primary);
179
+ transform: scale(1.05);
180
+ }
181
+
182
+ /* --- HUD (Heads Up Display) --- */
183
+ #hud {
184
+ position: absolute;
185
+ top: 20px;
186
+ left: 20px;
187
+ right: 20px;
188
+ display: flex;
189
+ justify-content: space-between;
190
+ pointer-events: none;
191
+ z-index: 40;
192
+ display: none; /* Hidden until game starts */
193
+ }
194
+
195
+ .hud-panel {
196
+ background: rgba(0, 0, 0, 0.5);
197
+ border-left: 3px solid var(--secondary);
198
+ padding: 10px 20px;
199
+ backdrop-filter: blur(4px);
200
+ }
201
+
202
+ .hud-label {
203
+ font-size: 0.8rem;
204
+ color: var(--secondary);
205
+ text-transform: uppercase;
206
+ letter-spacing: 1px;
207
+ }
208
+
209
+ .hud-value {
210
+ font-family: var(--font-display);
211
+ font-size: 1.5rem;
212
+ color: white;
213
+ }
214
+
215
+ /* --- Mobile Controls --- */
216
+ #mobile-controls {
217
+ position: absolute;
218
+ bottom: 20px;
219
+ width: 100%;
220
+ display: flex;
221
+ justify-content: space-between;
222
+ padding: 0 20px;
223
+ z-index: 60;
224
+ display: none; /* Shown via JS on touch devices */
225
+ }
226
+
227
+ .control-btn {
228
+ width: 80px;
229
+ height: 80px;
230
+ border-radius: 50%;
231
+ background: rgba(255, 255, 255, 0.1);
232
+ border: 2px solid var(--primary);
233
+ color: white;
234
+ font-size: 2rem;
235
+ display: flex;
236
+ justify-content: center;
237
+ align-items: center;
238
+ backdrop-filter: blur(5px);
239
+ touch-action: manipulation;
240
+ }
241
+
242
+ .control-btn:active {
243
+ background: var(--primary);
244
+ color: black;
245
+ }
246
+
247
+ /* --- Animations --- */
248
+ @keyframes pulse {
249
+ 0% { transform: scale(1); opacity: 1; }
250
+ 50% { transform: scale(1.02); opacity: 0.9; }
251
+ 100% { transform: scale(1); opacity: 1; }
252
+ }
253
+
254
+ @media (max-width: 768px) {
255
+ h1 { font-size: 2.5rem; }
256
+ .instructions { font-size: 1rem; }
257
+ #hud { top: 10px; }
258
+ .hud-value { font-size: 1.2rem; }
259
+ }
260
+ </style>
261
+ </head>
262
+ <body>
263
+
264
+ <header>
265
+ <div class="brand">Neon <span>Racer</span></div>
266
+ <a href="https://huggingface.co/spaces/akhaliq/anycoder" target="_blank" class="built-with">Built with anycoder</a>
267
+ </header>
268
+
269
+ <main id="game-container">
270
+ <!-- Canvas Layer -->
271
+ <canvas id="gameCanvas"></canvas>
272
+
273
+ <!-- Heads Up Display -->
274
+ <div id="hud">
275
+ <div class="hud-panel">
276
+ <div class="hud-label">Score</div>
277
+ <div class="hud-value" id="scoreDisplay">0</div>
278
+ </div>
279
+ <div class="hud-panel" style="border-left: none; border-right: 3px solid var(--primary); text-align: right;">
280
+ <div class="hud-label">Speed</div>
281
+ <div class="hud-value" id="speedDisplay">0 km/h</div>
282
+ </div>
283
+ </div>
284
+
285
+ <!-- Start Screen -->
286
+ <div id="startScreen" class="overlay">
287
+ <h1>Neon Velocity</h1>
288
+ <div class="instructions">
289
+ <p>Use <span class="key-badge">←</span> <span class="key-badge">→</span> or <span class="key-badge">A</span> <span class="key-badge">D</span> to steer.</p>
290
+ <p>Avoid the red obstacles. Collect yellow energy.</p>
291
+ <p style="font-size: 0.8rem; margin-top: 10px; color: #888;">(Mobile: Tap left/right sides of screen)</p>
292
+ </div>
293
+ <button class="btn-primary" id="startBtn">Start Engine</button>
294
+ </div>
295
+
296
+ <!-- Game Over Screen -->
297
+ <div id="gameOverScreen" class="overlay hidden">
298
+ <h1 style="color: var(--secondary); -webkit-text-fill-color: var(--secondary);">CRASHED!</h1>
299
+ <div class="instructions">
300
+ <p>Final Score: <span id="finalScore" style="color: white; font-weight: bold;">0</span></p>
301
+ <p>High Score: <span id="highScore" style="color: var(--accent);">0</span></p>
302
+ </div>
303
+ <button class="btn-primary" id="restartBtn">Try Again</button>
304
+ </div>
305
+
306
+ <!-- Mobile Controls -->
307
+ <div id="mobile-controls">
308
+ <div class="control-btn" id="btnLeft">←</div>
309
+ <div class="control-btn" id="btnRight">→</div>
310
+ </div>
311
+ </main>
312
+
313
+ <script>
314
+ /**
315
+ * AUDIO SYSTEM (Web Audio API)
316
+ * Synthesizes sounds locally without external assets.
317
+ */
318
+ const AudioSys = {
319
+ ctx: null,
320
+ init: function() {
321
+ window.AudioContext = window.AudioContext || window.webkitAudioContext;
322
+ this.ctx = new AudioContext();
323
+ },
324
+ playTone: function(freq, type, duration, vol = 0.1) {
325
+ if (!this.ctx) return;
326
+ const osc = this.ctx.createOscillator();
327
+ const gain = this.ctx.createGain();
328
+ osc.type = type;
329
+ osc.frequency.setValueAtTime(freq, this.ctx.currentTime);
330
+ gain.gain.setValueAtTime(vol, this.ctx.currentTime);
331
+ gain.gain.exponentialRampToValueAtTime(0.01, this.ctx.currentTime + duration);
332
+ osc.connect(gain);
333
+ gain.connect(this.ctx.destination);
334
+ osc.start();
335
+ osc.stop(this.ctx.currentTime + duration);
336
+ },
337
+ playCrash: function() {
338
+ this.playTone(100, 'sawtooth', 0.5, 0.3);
339
+ this.playTone(50, 'square', 0.5, 0.3);
340
+ },
341
+ playCollect: function() {
342
+ this.playTone(800, 'sine', 0.1, 0.1);
343
+ setTimeout(() => this.playTone(1200, 'sine', 0.2, 0.1), 50);
344
+ },
345
+ playEngine: function() {
346
+ // Simple hum for engine (simulated by random noise usually, but keeping it simple here)
347
+ }
348
+ };
349
+
350
+ /**
351
+ * GAME ENGINE & LOGIC
352
+ */
353
+ const canvas = document.getElementById('gameCanvas');
354
+ const ctx = canvas.getContext('2d');
355
+
356
+ // UI Elements
357
+ const startScreen = document.getElementById('startScreen');
358
+ const gameOverScreen = document.getElementById('gameOverScreen');
359
+ const hud = document.getElementById('hud');
360
+ const scoreDisplay = document.getElementById('scoreDisplay');
361
+ const speedDisplay = document.getElementById('speedDisplay');
362
+ const finalScoreDisplay = document.getElementById('finalScore');
363
+ const highScoreDisplay = document.getElementById('highScore');
364
+ const startBtn = document.getElementById('startBtn');
365
+ const restartBtn = document.getElementById('restartBtn');
366
+ const mobileControls = document.getElementById('mobile-controls');
367
+ const btnLeft = document.getElementById('btnLeft');
368
+ const btnRight = document.getElementById('btnRight');
369
+
370
+ // Game State
371
+ let gameRunning = false;
372
+ let score = 0;
373
+ let highScore = localStorage.getItem('neonRacerHighScore') || 0;
374
+ let speed = 5;
375
+ let roadOffset = 0;
376
+ let animationId;
377
+ let lastTime = 0;
378
+
379
+ // Dimensions
380
+ let canvasWidth, canvasHeight;
381
+
382
+ // Entities
383
+ const player = {
384
+ x: 0,
385
+ y: 0,
386
+ width: 40,
387
+ height: 70,
388
+ color: '#00f3ff',
389
+ speedX: 0,
390
+ maxSpeedX: 7,
391
+ tilt: 0
392
+ };
393
+
394
+ let obstacles = [];
395
+ let particles = [];
396
+ let roadLines = [];
397
+
398
+ // Inputs
399
+ const keys = {
400
+ ArrowLeft: false,
401
+ ArrowRight: false,
402
+ KeyA: false,
403
+ KeyD: false
404
+ };
405
+
406
+ // Resize Handling
407
+ function resize() {
408
+ canvasWidth = window.innerWidth;
409
+ canvasHeight = window.innerHeight;
410
+ canvas.width = canvasWidth;
411
+ canvas.height = canvasHeight;
412
+
413
+ // Reposition player on resize if game hasn't started
414
+ if (!gameRunning) {
415
+ player.x = canvasWidth / 2 - player.width / 2;
416
+ player.y = canvasHeight - 150;
417
+ }
418
+ }
419
+ window.addEventListener('resize', resize);
420
+
421
+ // Input Listeners
422
+ window.addEventListener('keydown', (e) => {
423
+ if (keys.hasOwnProperty(e.code)) keys[e.code] = true;
424
+ });
425
+ window.addEventListener('keyup', (e) => {
426
+ if (keys.hasOwnProperty(e.code)) keys[e.code] = false;
427
+ });
428
+
429
+ // Mobile Touch
430
+ const handleTouch = (dir) => (e) => {
431
+ e.preventDefault(); // Prevent scroll
432
+ if (dir === 'left') keys.ArrowLeft = true;
433
+ if (dir === 'right') keys.ArrowRight = true;
434
+ };
435
+ const handleTouchEnd = (dir) => (e) => {
436
+ e.preventDefault();
437
+ if (dir === 'left') keys.ArrowLeft = false;
438
+ if (dir === 'right') keys.ArrowRight = false;
439
+ };
440
+
441
+ if ('ontouchstart' in window) {
442
+ mobileControls.style.display = 'flex';
443
+ btnLeft.addEventListener('touchstart', handleTouch('left'));
444
+ btnLeft.addEventListener('touchend', handleTouchEnd('left'));
445
+ btnRight.addEventListener('touchstart', handleTouch('right'));
446
+ btnRight.addEventListener('touchend', handleTouchEnd('right'));
447
+ }
448
+
449
+ // Game Functions
450
+ function initGame() {
451
+ resize();
452
+ player.x = canvasWidth / 2 - player.width / 2;
453
+ player.y = canvasHeight - 150;
454
+ obstacles = [];
455
+ particles = [];
456
+ roadLines = [];
457
+ score = 0;
458
+ speed = 5;
459
+ gameRunning = true;
460
+
461
+ // Create initial road lines
462
+ for(let i=0; i<10; i++) {
463
+ roadLines.push({ y: i * 100 });
464
+ }
465
+
466
+ startScreen.classList.add('hidden');
467
+ gameOverScreen.classList.add('hidden');
468
+ hud.style.display = 'flex';
469
+
470
+ AudioSys.init();
471
+ lastTime = performance.now();
472
+ requestAnimationFrame(gameLoop);
473
+ }
474
+
475
+ function createObstacle() {
476
+ const laneWidth = canvasWidth / 4; // 4 lanes roughly
477
+ const lane = Math.floor(Math.random() * 4);
478
+ const obsWidth = 40;
479
+ const obsHeight = 70;
480
+ const obsX = (lane * laneWidth) + (laneWidth/2) - (obsWidth/2) + 20; // Center in lane with margin
481
+
482
+ // 20% chance for bonus coin
483
+ const isCoin = Math.random() > 0.8;
484
+
485
+ obstacles.push({
486
+ x: obsX,
487
+ y: -100,
488
+ width: obsWidth,
489
+ height: obsHeight,
490
+ color: isCoin ? '#ffee00' : '#ff0055',
491
+ type: isCoin ? 'coin' : 'obstacle',
492
+ rotation: 0
493
+ });
494
+ }
495
+
496
+ function createExplosion(x, y, color) {
497
+ for (let i = 0; i < 20; i++) {
498
+ particles.push({
499
+ x: x,
500
+ y: y,
501
+ vx: (Math.random() - 0.5) * 10,
502
+ vy: (Math.random() - 0.5) * 10,
503
+ life: 1.0,
504
+ color: color
505
+ });
506
+ }
507
+ }
508
+
509
+ function update(dt) {
510
+ // Player Movement
511
+ if (keys.ArrowLeft || keys.KeyA) {
512
+ player.x -= player.maxSpeedX;
513
+ player.tilt = -15; // degrees
514
+ } else if (keys.ArrowRight || keys.KeyD) {
515
+ player.x += player.maxSpeedX;
516
+ player.tilt = 15;
517
+ } else {
518
+ player.tilt = 0;
519
+ }
520
+
521
+ // Boundaries
522
+ if (player.x < 0) player.x = 0;
523
+ if (player.x + player.width > canvasWidth) player.x = canvasWidth - player.width;
524
+
525
+ // Road Animation
526
+ roadOffset += speed;
527
+ if (roadOffset >= 100) roadOffset = 0;
528
+
529
+ // Spawn Obstacles
530
+ if (Math.random() < 0.02) { // Adjust spawn rate based on speed
531
+ createObstacle();
532
+ }
533
+
534
+ // Update Obstacles
535
+ for (let i = obstacles.length - 1; i >= 0; i--) {
536
+ let obs = obstacles[i];
537
+ obs.y += speed;
538
+ obs.rotation += 0.05;
539
+
540
+ // Collision Detection (AABB)
541
+ if (
542
+ player.x < obs.x + obs.width &&
543
+ player.x + player.width > obs.x &&
544
+ player.y < obs.y + obs.height &&
545
+ player.y + player.height > obs.y
546
+ ) {
547
+ if (obs.type === 'coin') {
548
+ // Collect Coin
549
+ score += 100;
550
+ createExplosion(obs.x + obs.width/2, obs.y + obs.height/2, '#ffee00');
551
+ AudioSys.playCollect();
552
+ obstacles.splice(i, 1);
553
+ } else {
554
+ // Crash
555
+ createExplosion(player.x + player.width/2, player.y + player.height/2, '#ff0055');
556
+ AudioSys.playCrash();
557
+ gameOver();
558
+ }
559
+ } else if (obs.y > canvasHeight) {
560
+ obstacles.splice(i, 1);
561
+ score += 10; // Points for passing
562
+ }
563
+ }
564
+
565
+ // Update Particles
566
+ for (let i = particles.length - 1; i >= 0; i--) {
567
+ let p = particles[i];
568
+ p.x += p.vx;
569
+ p.y += p.vy;
570
+ p.life -= 0.02;
571
+ if (p.life <= 0) particles.splice(i, 1);
572
+ }
573
+
574
+ // Increase Difficulty
575
+ speed = 5 + (score / 500); // Cap speed at reasonable level
576
+ score++;
577
+
578
+ // Update UI
579
+ scoreDisplay.innerText = score;
580
+ speedDisplay.innerText = Math.floor(speed * 20) + " km/h";
581
+ }
582
+
583
+ function draw() {
584
+ // Clear Screen
585
+ ctx.fillStyle = '#050510';
586
+ ctx.fillRect(0, 0, canvasWidth, canvasHeight);
587
+
588
+ // Draw Road (Perspective effect simplified to top-down for clarity)
589
+ ctx.fillStyle = '#111';
590
+ ctx.fillRect(0, 0, canvasWidth, canvasHeight);
591
+
592
+ // Draw Road Borders
593
+ ctx.strokeStyle = '#00f3ff';
594
+ ctx.lineWidth = 4;
595
+ ctx.beginPath();
596
+ ctx.moveTo(canvasWidth * 0.1, 0);
597
+ ctx.lineTo(canvasWidth * 0.1, canvasHeight);
598
+ ctx.moveTo(canvasWidth * 0.9, 0);
599
+ ctx.lineTo(canvasWidth * 0.9, canvasHeight);
600
+ ctx.stroke();
601
+
602
+ // Draw Moving Lines
603
+ ctx.strokeStyle = 'rgba(0, 243, 255, 0.3)';
604
+ ctx.lineWidth = 2;
605
+ roadLines.forEach(line => {
606
+ line.y += speed;
607
+ if (line.y > canvasHeight) line.y = -100;
608
+
609
+ ctx.beginPath();
610
+ ctx.moveTo(canvasWidth * 0.3, line.y);
611
+ ctx.lineTo(canvasWidth * 0.3, line.y + 50);
612
+ ctx.moveTo(canvasWidth * 0.7, line.y);
613
+ ctx.lineTo(canvasWidth * 0.7, line.y + 50);
614
+ ctx.stroke();
615
+ });
616
+
617
+ // Draw Player Car
618
+ ctx.save();
619
+ ctx.translate(player.x + player.width / 2, player.y + player.height / 2);
620
+ ctx.rotate(player.tilt * Math.PI / 180);
621
+
622
+ // Car Body
623
+ ctx.shadowBlur = 15;
624
+ ctx.shadowColor = player.color;
625
+ ctx.fillStyle = player.color;
626
+ ctx.fillRect(-player.width/2, -player.height/2, player.width, player.height);
627
+
628
+ // Car Detail (Windshield)
629
+ ctx.fillStyle = '#000';
630
+ ctx.fillRect(-player.width/2 + 5, -player.height/2 + 10, player.width - 10, 15);
631
+
632
+ // Engine Glow
633
+ ctx.fillStyle = '#ff0055';
634
+ ctx.fillRect(-player.width/2 + 5, player.height/2 - 5, player.width - 10, 5);
635
+
636
+ ctx.restore();
637
+
638
+ // Draw Obstacles
639
+ obstacles.forEach(obs => {
640
+ ctx.save();
641
+ ctx.translate(obs.x + obs.width/2, obs.y + obs.height/2);
642
+ ctx.rotate(obs.rotation);
643
+
644
+ ctx.shadowBlur = 10;
645
+ ctx.shadowColor = obs.color;
646
+ ctx.fillStyle = obs.color;
647
+
648
+ // Draw shape based on type
649
+ if (obs.type === 'coin') {
650
+ ctx.beginPath();
651
+ ctx.arc(0, 0, obs.width/2, 0, Math.PI * 2);
652
+ ctx.fill();
653
+ // Shine
654
+ ctx.fillStyle = '#fff';
655
+ ctx.beginPath();
656
+ ctx.arc(-5, -5, 5, 0, Math.PI * 2);
657
+ ctx.fill();
658
+ } else {
659
+ ctx.fillRect(-obs.width/2, -obs.height/2, obs.width, obs.height);
660
+ // Inner detail
661
+ ctx.fillStyle = 'rgba(0,0,0,0.5)';
662
+ ctx.fillRect(-obs.width/2 + 5, -obs.height/2 + 5, obs.width - 10, obs.height - 10);
663
+ }
664
+
665
+ ctx.restore();
666
+ });
667
+
668
+ // Draw Particles
669
+ particles.forEach(p => {
670
+ ctx.globalAlpha = p.life;
671
+ ctx.fillStyle = p.color;
672
+ ctx.beginPath();
673
+ ctx.arc(p.x, p.y, 3, 0, Math.PI * 2);
674
+ ctx.fill();
675
+ ctx.globalAlpha = 1.0;
676
+ });
677
+ }
678
+
679
+ function gameLoop(timestamp) {
680
+ if (!gameRunning) return;
681
+
682
+ const dt = timestamp - lastTime;
683
+ lastTime = timestamp;
684
+
685
+ update(dt);
686
+ draw();
687
+
688
+ animationId = requestAnimationFrame(gameLoop);
689
+ }
690
+
691
+ function gameOver() {
692
+ gameRunning = false;
693
+ cancelAnimationFrame(animationId);
694
+
695
+ // Update High Score
696
+ if (score > highScore) {
697
+ highScore = score;
698
+ localStorage.setItem('neonRacerHighScore', highScore);
699
+ }
700
+
701
+ finalScoreDisplay.innerText = score;
702
+ highScoreDisplay.innerText = highScore;
703
+
704
+ hud.style.display = 'none';
705
+ gameOverScreen.classList.remove('hidden');
706
+ }
707
+
708
+ // Button Listeners
709
+ startBtn.addEventListener('click', initGame);
710
+ restartBtn.addEventListener('click', initGame);
711
+
712
+ // Initial Draw to show something before start
713
+ resize();
714
+ // Draw a static frame
715
+ ctx.fillStyle = '#050510';
716
+ ctx.fillRect(0, 0, canvasWidth, canvasHeight);
717
+ ctx.fillStyle = '#00f3ff';
718
+ ctx.font = '20px Orbitron';
719
+ ctx.textAlign = 'center';
720
+ ctx.fillText("READY TO RACE?", canvasWidth/2, canvasHeight/2);
721
+
722
+ </script>
723
+ </body>
724
+ </html>