HAL1993 commited on
Commit
bfdde3d
·
verified ·
1 Parent(s): 99fc26b

Upload folder using huggingface_hub

Browse files
Files changed (1) hide show
  1. index.html +1207 -19
index.html CHANGED
@@ -1,19 +1,1207 @@
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, user-scalable=no">
6
+ <title>Dino Runner - Bitcoin Edition</title>
7
+ <link rel="preconnect" href="https://fonts.googleapis.com">
8
+ <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
9
+ <link href="https://fonts.googleapis.com/css2?family=Bangers&family=Orbitron:wght@400;700&display=swap" rel="stylesheet">
10
+ <style>
11
+ * {
12
+ margin: 0;
13
+ padding: 0;
14
+ box-sizing: border-box;
15
+ }
16
+
17
+ body {
18
+ overflow: hidden;
19
+ background: linear-gradient(135deg, #1a1a2e 0%, #16213e 50%, #0f3460 100%);
20
+ font-family: 'Orbitron', sans-serif;
21
+ touch-action: none;
22
+ }
23
+
24
+ #gameCanvas {
25
+ display: block;
26
+ margin: 0 auto;
27
+ background: linear-gradient(180deg, #87CEEB 0%, #E0F6FF 100%);
28
+ }
29
+
30
+ .ui-overlay {
31
+ position: fixed;
32
+ top: 0;
33
+ left: 0;
34
+ width: 100%;
35
+ height: 100%;
36
+ pointer-events: none;
37
+ z-index: 100;
38
+ }
39
+
40
+ .screen {
41
+ position: absolute;
42
+ top: 0;
43
+ left: 0;
44
+ width: 100%;
45
+ height: 100%;
46
+ display: flex;
47
+ flex-direction: column;
48
+ align-items: center;
49
+ justify-content: center;
50
+ background: rgba(0, 0, 0, 0.85);
51
+ opacity: 0;
52
+ transition: opacity 0.5s ease;
53
+ pointer-events: none;
54
+ }
55
+
56
+ .screen.active {
57
+ opacity: 1;
58
+ pointer-events: all;
59
+ }
60
+
61
+ .title {
62
+ font-family: 'Bangers', cursive;
63
+ font-size: clamp(2.5rem, 8vw, 5rem);
64
+ color: #F7931A;
65
+ text-shadow: 0 0 20px #F7931A, 0 0 40px #F7931A, 4px 4px 0 #000;
66
+ letter-spacing: 4px;
67
+ animation: pulse 2s ease-in-out infinite;
68
+ }
69
+
70
+ .subtitle {
71
+ font-size: clamp(1rem, 3vw, 1.5rem);
72
+ color: #4ade80;
73
+ margin-top: 10px;
74
+ text-shadow: 0 0 10px #4ade80;
75
+ }
76
+
77
+ @keyframes pulse {
78
+ 0%, 100% { transform: scale(1); }
79
+ 50% { transform: scale(1.05); }
80
+ }
81
+
82
+ .btn {
83
+ margin-top: 30px;
84
+ padding: 15px 50px;
85
+ font-family: 'Bangers', cursive;
86
+ font-size: 1.8rem;
87
+ color: #fff;
88
+ background: linear-gradient(180deg, #F7931A 0%, #c77a15 100%);
89
+ border: none;
90
+ border-radius: 50px;
91
+ cursor: pointer;
92
+ transition: all 0.3s ease;
93
+ box-shadow: 0 6px 0 #8c5a10, 0 10px 20px rgba(247, 147, 26, 0.4);
94
+ text-transform: uppercase;
95
+ letter-spacing: 2px;
96
+ }
97
+
98
+ .btn:hover {
99
+ transform: translateY(-3px);
100
+ box-shadow: 0 9px 0 #8c5a10, 0 15px 30px rgba(247, 147, 26, 0.5);
101
+ }
102
+
103
+ .btn:active {
104
+ transform: translateY(3px);
105
+ box-shadow: 0 3px 0 #8c5a10, 0 5px 10px rgba(247, 147, 26, 0.4);
106
+ }
107
+
108
+ .controls-info {
109
+ margin-top: 40px;
110
+ color: #aaa;
111
+ text-align: center;
112
+ font-size: 0.9rem;
113
+ line-height: 2;
114
+ }
115
+
116
+ .controls-info span {
117
+ color: #4ade80;
118
+ font-weight: bold;
119
+ }
120
+
121
+ .hud {
122
+ position: fixed;
123
+ top: 20px;
124
+ left: 50%;
125
+ transform: translateX(-50%);
126
+ display: flex;
127
+ gap: 20px;
128
+ z-index: 50;
129
+ width: 90%;
130
+ max-width: 600px;
131
+ justify-content: space-between;
132
+ }
133
+
134
+ .hud-item {
135
+ background: rgba(0, 0, 0, 0.7);
136
+ padding: 10px 20px;
137
+ border-radius: 25px;
138
+ border: 2px solid #F7931A;
139
+ box-shadow: 0 0 15px rgba(247, 147, 26, 0.3);
140
+ }
141
+
142
+ .hud-label {
143
+ font-size: 0.7rem;
144
+ color: #888;
145
+ text-transform: uppercase;
146
+ letter-spacing: 1px;
147
+ }
148
+
149
+ .hud-value {
150
+ font-size: 1.2rem;
151
+ color: #F7931A;
152
+ font-weight: bold;
153
+ text-shadow: 0 0 10px #F7931A;
154
+ }
155
+
156
+ .hud-value.distance {
157
+ color: #4ade80;
158
+ text-shadow: 0 0 10px #4ade80;
159
+ }
160
+
161
+ .powerup-indicator {
162
+ position: fixed;
163
+ top: 80px;
164
+ left: 50%;
165
+ transform: translateX(-50%);
166
+ display: flex;
167
+ gap: 10px;
168
+ z-index: 50;
169
+ }
170
+
171
+ .powerup-badge {
172
+ padding: 8px 16px;
173
+ border-radius: 20px;
174
+ font-size: 0.8rem;
175
+ font-weight: bold;
176
+ opacity: 0;
177
+ transform: translateY(-20px);
178
+ transition: all 0.3s ease;
179
+ }
180
+
181
+ .powerup-badge.active {
182
+ opacity: 1;
183
+ transform: translateY(0);
184
+ }
185
+
186
+ .powerup-badge.magnet { background: #9333ea; color: #fff; }
187
+ .powerup-badge.multiplier { background: #eab308; color: #000; }
188
+ .powerup-badge.shield { background: #3b82f6; color: #fff; }
189
+ .powerup-badge.speed { background: #ef4444; color: #fff; }
190
+
191
+ .game-over-stats {
192
+ text-align: center;
193
+ margin: 20px 0;
194
+ }
195
+
196
+ .stat-row {
197
+ display: flex;
198
+ justify-content: space-between;
199
+ padding: 10px 30px;
200
+ font-size: 1.2rem;
201
+ color: #fff;
202
+ }
203
+
204
+ .stat-value {
205
+ color: #F7931A;
206
+ font-weight: bold;
207
+ }
208
+
209
+ .pause-btn {
210
+ position: fixed;
211
+ top: 20px;
212
+ right: 20px;
213
+ width: 50px;
214
+ height: 50px;
215
+ background: rgba(0, 0, 0, 0.7);
216
+ border: 2px solid #F7931A;
217
+ border-radius: 50%;
218
+ color: #F7931A;
219
+ font-size: 1.5rem;
220
+ cursor: pointer;
221
+ z-index: 60;
222
+ transition: all 0.3s ease;
223
+ }
224
+
225
+ .pause-btn:hover {
226
+ background: #F7931A;
227
+ color: #000;
228
+ }
229
+
230
+ .built-with {
231
+ position: fixed;
232
+ bottom: 10px;
233
+ left: 50%;
234
+ transform: translateX(-50%);
235
+ color: rgba(255, 255, 255, 0.5);
236
+ font-size: 0.8rem;
237
+ z-index: 200;
238
+ }
239
+
240
+ .built-with a {
241
+ color: #F7931A;
242
+ text-decoration: none;
243
+ }
244
+
245
+ .combo-display {
246
+ position: fixed;
247
+ top: 50%;
248
+ left: 50%;
249
+ transform: translate(-50%, -50%);
250
+ font-family: 'Bangers', cursive;
251
+ font-size: 3rem;
252
+ color: #eab308;
253
+ text-shadow: 0 0 20px #eab308, 0 0 40px #eab308;
254
+ opacity: 0;
255
+ z-index: 70;
256
+ pointer-events: none;
257
+ }
258
+
259
+ .combo-display.show {
260
+ animation: comboPopup 1s ease-out forwards;
261
+ }
262
+
263
+ @keyframes comboPopup {
264
+ 0% { opacity: 0; transform: translate(-50%, -50%) scale(0.5); }
265
+ 20% { opacity: 1; transform: translate(-50%, -50%) scale(1.2); }
266
+ 100% { opacity: 0; transform: translate(-50%, -80%) scale(1); }
267
+ }
268
+
269
+ @media (max-width: 600px) {
270
+ .hud { gap: 10px; }
271
+ .hud-item { padding: 8px 12px; }
272
+ .hud-value { font-size: 1rem; }
273
+ }
274
+ </style>
275
+ </head>
276
+ <body>
277
+ <canvas id="gameCanvas"></canvas>
278
+
279
+ <div class="hud" id="hud" style="display: none;">
280
+ <div class="hud-item">
281
+ <div class="hud-label">Distance</div>
282
+ <div class="hud-value distance" id="distanceDisplay">0m</div>
283
+ </div>
284
+ <div class="hud-item">
285
+ <div class="hud-label">₿alance</div>
286
+ <div class="hud-value" id="btcDisplay">₿ 0.00000000</div>
287
+ </div>
288
+ <div class="hud-item">
289
+ <div class="hud-label">Speed</div>
290
+ <div class="hud-value" id="speedDisplay">1x</div>
291
+ </div>
292
+ </div>
293
+
294
+ <div class="powerup-indicator" id="powerupIndicator" style="display: none;"></div>
295
+
296
+ <button class="pause-btn" id="pauseBtn" style="display: none;">⏸</button>
297
+
298
+ <div class="combo-display" id="comboDisplay"></div>
299
+
300
+ <div class="ui-overlay">
301
+ <div class="screen active" id="startScreen">
302
+ <div class="title">🦖 DINO RUNNER</div>
303
+ <div class="subtitle">₿ITCOIN EDITION</div>
304
+ <button class="btn" id="startBtn">PLAY</button>
305
+ <div class="controls-info">
306
+ <span>← →</span> Move Lanes<br>
307
+ <span>↑</span> Jump | <span>↓</span> Slide<br>
308
+ <span>SPACE</span> Jump | <span>SHIFT</span> Slide
309
+ </div>
310
+ </div>
311
+
312
+ <div class="screen" id="pauseScreen">
313
+ <div class="title" style="font-size: 3rem;">⏸ PAUSED</div>
314
+ <button class="btn" id="resumeBtn">RESUME</button>
315
+ <button class="btn" id="quitBtn" style="margin-top: 15px; background: linear-gradient(180deg, #ef4444 0%, #b91c1c 100%);">QUIT</button>
316
+ </div>
317
+
318
+ <div class="screen" id="gameOverScreen">
319
+ <div class="title" style="color: #ef4444;">GAME OVER</div>
320
+ <div class="game-over-stats">
321
+ <div class="stat-row">
322
+ <span>Distance</span>
323
+ <span class="stat-value" id="finalDistance">0m</span>
324
+ </div>
325
+ <div class="stat-row">
326
+ <span>Total BTC</span>
327
+ <span class="stat-value" id="finalBtc">₿ 0.00000000</span>
328
+ </div>
329
+ <div class="stat-row">
330
+ <span>Best Combo</span>
331
+ <span class="stat-value" id="bestCombo">x1</span>
332
+ </div>
333
+ </div>
334
+ <button class="btn" id="restartBtn">PLAY AGAIN</button>
335
+ </div>
336
+ </div>
337
+
338
+ <div class="built-with">
339
+ Built with <a href="https://huggingface.co/spaces/akhaliq/anycoder" target="_blank">anycoder</a>
340
+ </div>
341
+
342
+ <script>
343
+ // ============================================
344
+ // GAME CONSTANTS & CONFIGURATION
345
+ // ============================================
346
+ const CANVAS_WIDTH = 800;
347
+ const CANVAS_HEIGHT = 500;
348
+ const LANE_WIDTH = 120;
349
+ const LANES = [-1, 0, 1]; // Left, Center, Right
350
+ const LANE_POSITIONS = [
351
+ CANVAS_WIDTH / 2 - LANE_WIDTH,
352
+ CANVAS_WIDTH / 2,
353
+ CANVAS_WIDTH / 2 + LANE_WIDTH
354
+ ];
355
+
356
+ const GROUND_Y = CANVAS_HEIGHT - 80;
357
+ const GRAVITY = 0.8;
358
+ const JUMP_FORCE = -16;
359
+ const BASE_SPEED = 5;
360
+ const MAX_SPEED = 15;
361
+ const SPEED_INCREMENT = 0.001;
362
+
363
+ // ============================================
364
+ // GAME STATE
365
+ // ============================================
366
+ const game = {
367
+ canvas: null,
368
+ ctx: null,
369
+ running: false,
370
+ paused: false,
371
+ gameOver: false,
372
+ distance: 0,
373
+ speed: BASE_SPEED,
374
+ lastTime: 0,
375
+ deltaTime: 0,
376
+ screenShake: 0,
377
+ combo: 1,
378
+ bestCombo: 1,
379
+ comboTimer: 0
380
+ };
381
+
382
+ // Bitcoin economy
383
+ const btc = {
384
+ balance: 0,
385
+ perCoin: 0.00000001,
386
+ bonusCoinValue: 0.00000005
387
+ };
388
+
389
+ // Power-up states
390
+ const powerups = {
391
+ magnet: { active: false, duration: 0 },
392
+ multiplier: { active: false, duration: 0, value: 2 },
393
+ shield: { active: false },
394
+ speed: { active: false, duration: 0 }
395
+ };
396
+
397
+ // ============================================
398
+ // DINOSAUR CHARACTER
399
+ // ============================================
400
+ const dino = {
401
+ x: CANVAS_WIDTH / 2,
402
+ y: GROUND_Y,
403
+ lane: 1,
404
+ targetLane: 1,
405
+ width: 60,
406
+ height: 80,
407
+ velocityY: 0,
408
+ isJumping: false,
409
+ isSliding: false,
410
+ slideTimer: 0,
411
+ runFrame: 0,
412
+ runTimer: 0,
413
+ bobOffset: 0,
414
+ eyeBlink: 0,
415
+ isHit: false,
416
+ hitTimer: 0,
417
+
418
+ reset() {
419
+ this.lane = 1;
420
+ this.targetLane = 1;
421
+ this.x = LANE_POSITIONS[1];
422
+ this.y = GROUND_Y;
423
+ this.velocityY = 0;
424
+ this.isJumping = false;
425
+ this.isSliding = false;
426
+ this.slideTimer = 0;
427
+ this.runFrame = 0;
428
+ this.bobOffset = 0;
429
+ this.eyeBlink = 0;
430
+ this.isHit = false;
431
+ this.hitTimer = 0;
432
+ },
433
+
434
+ update(dt) {
435
+ // Lane movement with smooth interpolation
436
+ this.targetLane = Math.max(0, Math.min(2, this.targetLane));
437
+ const targetX = LANE_POSITIONS[this.targetLane];
438
+ this.x += (targetX - this.x) * 0.15;
439
+ this.lane = this.targetLane;
440
+
441
+ // Jump physics
442
+ if (this.isJumping) {
443
+ this.velocityY += GRAVITY;
444
+ this.y += this.velocityY;
445
+ if (this.y >= GROUND_Y) {
446
+ this.y = GROUND_Y;
447
+ this.isJumping = false;
448
+ this.velocityY = 0;
449
+ }
450
+ }
451
+
452
+ // Slide mechanics
453
+ if (this.isSliding) {
454
+ this.slideTimer -= dt;
455
+ if (this.slideTimer <= 0) {
456
+ this.isSliding = false;
457
+ }
458
+ }
459
+
460
+ // Running animation
461
+ this.runTimer += dt * 0.01 * game.speed;
462
+ if (this.runTimer > 1) {
463
+ this.runTimer = 0;
464
+ this.runFrame = (this.runFrame + 1) % 4;
465
+ }
466
+
467
+ // Bouncy idle animation
468
+ if (!this.isJumping && !this.isSliding) {
469
+ this.bobOffset = Math.sin(Date.now() * 0.01) * 3;
470
+ } else {
471
+ this.bobOffset = 0;
472
+ }
473
+
474
+ // Eye blink
475
+ this.eyeBlink = Math.random() < 0.005 ? 10 : Math.max(0, this.eyeBlink - 1);
476
+
477
+ // Hit effect
478
+ if (this.isHit) {
479
+ this.hitTimer -= dt;
480
+ if (this.hitTimer <= 0) {
481
+ this.isHit = false;
482
+ }
483
+ }
484
+ },
485
+
486
+ jump() {
487
+ if (!this.isJumping && !this.isSliding) {
488
+ this.isJumping = true;
489
+ this.velocityY = JUMP_FORCE;
490
+ }
491
+ },
492
+
493
+ slide() {
494
+ if (!this.isJumping && !this.isSliding) {
495
+ this.isSliding = true;
496
+ this.slideTimer = 800;
497
+ }
498
+ },
499
+
500
+ moveLeft() {
501
+ if (this.targetLane > 0) {
502
+ this.targetLane--;
503
+ }
504
+ },
505
+
506
+ moveRight() {
507
+ if (this.targetLane < 2) {
508
+ this.targetLane++;
509
+ }
510
+ },
511
+
512
+ draw(ctx) {
513
+ ctx.save();
514
+ ctx.translate(this.x, this.y + this.bobOffset);
515
+
516
+ // Hit flash effect
517
+ if (this.isHit && Math.floor(this.hitTimer / 100) % 2 === 0) {
518
+ ctx.globalAlpha = 0.5;
519
+ }
520
+
521
+ const slideOffset = this.isSliding ? 30 : 0;
522
+ const height = this.isSliding ? this.height - 30 : this.height;
523
+
524
+ // Body (green dinosaur)
525
+ const bodyColor = '#22c55e';
526
+ const bodyDark = '#15803d';
527
+
528
+ // Main body
529
+ ctx.fillStyle = bodyColor;
530
+ ctx.beginPath();
531
+ ctx.ellipse(0, -height/2 + slideOffset, 28, 35, 0, 0, Math.PI * 2);
532
+ ctx.fill();
533
+
534
+ // Tail
535
+ ctx.beginPath();
536
+ ctx.moveTo(-25, -height/2 + slideOffset);
537
+ ctx.quadraticCurveTo(-45, -height/2 + slideOffset - 10, -40, -height/2 + slideOffset + 15);
538
+ ctx.quadraticCurveTo(-35, -height/2 + slideOffset + 20, -25, -height/2 + slideOffset + 10);
539
+ ctx.fill();
540
+
541
+ // Legs (animated)
542
+ const legOffset = this.isSliding ? 0 : Math.sin(this.runFrame * Math.PI / 2) * 8;
543
+ ctx.fillStyle = bodyDark;
544
+ // Left leg
545
+ ctx.beginPath();
546
+ ctx.ellipse(-12, -10 + slideOffset + legOffset, 8, 15, 0.2, 0, Math.PI * 2);
547
+ ctx.fill();
548
+ // Right leg
549
+ ctx.beginPath();
550
+ ctx.ellipse(12, -10 + slideOffset - legOffset, 8, 15, -0.2, 0, Math.PI * 2);
551
+ ctx.fill();
552
+
553
+ // Head
554
+ ctx.fillStyle = bodyColor;
555
+ ctx.beginPath();
556
+ ctx.ellipse(0, -height - 5, 25, 22, 0, 0, Math.PI * 2);
557
+ ctx.fill();
558
+
559
+ // Snout
560
+ ctx.beginPath();
561
+ ctx.ellipse(20, -height - 5, 15, 12, 0, 0, Math.PI * 2);
562
+ ctx.fill();
563
+
564
+ // Nostril
565
+ ctx.fillStyle = bodyDark;
566
+ ctx.beginPath();
567
+ ctx.ellipse(28, -height - 8, 3, 2, 0, 0, Math.PI * 2);
568
+ ctx.fill();
569
+
570
+ // Eye white
571
+ ctx.fillStyle = '#fff';
572
+ ctx.beginPath();
573
+ ctx.ellipse(8, -height - 12, 10, 11, 0, 0, Math.PI * 2);
574
+ ctx.fill();
575
+
576
+ // Eye pupil
577
+ ctx.fillStyle = '#000';
578
+ ctx.beginPath();
579
+ ctx.ellipse(10, -height - 10, 5, 6, 0, 0, Math.PI * 2);
580
+ ctx.fill();
581
+
582
+ // Eye shine
583
+ ctx.fillStyle = '#fff';
584
+ ctx.beginPath();
585
+ ctx.ellipse(12, -height - 13, 2, 2, 0, 0, Math.PI * 2);
586
+ ctx.fill();
587
+
588
+ // Eyelid (blink)
589
+ if (this.eyeBlink > 0) {
590
+ ctx.fillStyle = bodyDark;
591
+ ctx.beginPath();
592
+ ctx.ellipse(8, -height - 12, 11, this.eyeBlink, 0, 0, Math.PI * 2);
593
+ ctx.fill();
594
+ }
595
+
596
+ // Headband
597
+ ctx.fillStyle = '#F7931A';
598
+ ctx.fillRect(-28, -height - 22, 56, 10);
599
+
600
+ // Headband knot
601
+ ctx.beginPath();
602
+ ctx.moveTo(-28, -height - 22);
603
+ ctx.lineTo(-35, -height - 15);
604
+ ctx.lineTo(-28, -height - 12);
605
+ ctx.fill();
606
+
607
+ // Bitcoin symbol on headband
608
+ ctx.fillStyle = '#fff';
609
+ ctx.font = 'bold 8px Arial';
610
+ ctx.textAlign = 'center';
611
+ ctx.fillText('₿', 0, -height - 15);
612
+
613
+ // Shield effect
614
+ if (powerups.shield.active) {
615
+ ctx.strokeStyle = '#3b82f6';
616
+ ctx.lineWidth = 3;
617
+ ctx.globalAlpha = 0.6 + Math.sin(Date.now() * 0.01) * 0.3;
618
+ ctx.beginPath();
619
+ ctx.arc(0, -height/2, 50, 0, Math.PI * 2);
620
+ ctx.stroke();
621
+ ctx.globalAlpha = 1;
622
+ }
623
+
624
+ ctx.restore();
625
+ },
626
+
627
+ getBounds() {
628
+ const slideOffset = this.isSliding ? 30 : 0;
629
+ return {
630
+ x: this.x - 25,
631
+ y: this.y - this.height + slideOffset,
632
+ width: 50,
633
+ height: this.height - slideOffset
634
+ };
635
+ }
636
+ };
637
+
638
+ // ============================================
639
+ // OBSTACLE SYSTEM
640
+ // ============================================
641
+ const obstacles = [];
642
+ const obstacleTypes = [
643
+ { name: 'barrier', width: 80, height: 60, color: '#ef4444', yOffset: 0 },
644
+ { name: 'lowBarrier', width: 80, height: 40, color: '#f97316', yOffset: 0 },
645
+ { name: 'arch', width: 100, height: 120, color: '#8b5cf6', yOffset: -40 }
646
+ ];
647
+
648
+ function spawnObstacle() {
649
+ const type = obstacleTypes[Math.floor(Math.random() * obstacleTypes.length)];
650
+ const lane = Math.floor(Math.random() * 3);
651
+
652
+ obstacles.push({
653
+ x: LANE_POSITIONS[lane],
654
+ y: GROUND_Y,
655
+ lane: lane,
656
+ ...type,
657
+ passed: false
658
+ });
659
+ }
660
+
661
+ function updateObstacles(dt) {
662
+ // Spawn new obstacles based on speed
663
+ const spawnChance = 0.02 + game.speed * 0.001;
664
+ if (Math.random() < spawnChance && obstacles.length < 5) {
665
+ const lastObstacle = obstacles[obstacles.length - 1];
666
+ if (!lastObstacle || lastObstacle.x < CANVAS_WIDTH - 200) {
667
+ spawnObstacle();
668
+ }
669
+ }
670
+
671
+ // Move and remove obstacles
672
+ for (let i = obstacles.length - 1; i >= 0; i--) {
673
+ obstacles[i].x -= game.speed * 60 * (dt / 1000);
674
+
675
+ if (obstacles[i].x < -100) {
676
+ obstacles.splice(i, 1);
677
+ }
678
+ }
679
+ }
680
+
681
+ function drawObstacles(ctx) {
682
+ obstacles.forEach(obs => {
683
+ ctx.save();
684
+ ctx.translate(obs.x, obs.y + obs.yOffset);
685
+
686
+ // Glow effect
687
+ ctx.shadowColor = obs.color;
688
+ ctx.shadowBlur = 15;
689
+
690
+ if (obs.name === 'arch') {
691
+ // Draw arch obstacle (must slide to pass)
692
+ ctx.fillStyle = obs.color;
693
+ // Left pillar
694
+ ctx.fillRect(-50, -120, 20, 120);
695
+ // Right pillar
696
+ ctx.fillRect(30, -120, 20, 120);
697
+ // Top bar
698
+ ctx.fillRect(-50, -120, 100, 20);
699
+
700
+ // Warning stripes
701
+ ctx.fillStyle = '#fbbf24';
702
+ for (let i = 0; i < 3; i++) {
703
+ ctx.fillRect(-40 + i * 30, -110, 10, 100);
704
+ }
705
+ } else if (obs.name === 'lowBarrier') {
706
+ // Draw low barrier (must jump)
707
+ ctx.fillStyle = obs.color;
708
+ ctx.fillRect(-40, -40, 80, 40);
709
+
710
+ // Hazard stripes
711
+ ctx.fillStyle = '#fbbf24';
712
+ ctx.fillRect(-35, -35, 30, 5);
713
+ ctx.fillRect(-5, -25, 30, 5);
714
+ ctx.fillRect(-35, -15, 30, 5);
715
+ } else {
716
+ // Draw regular barrier
717
+ ctx.fillStyle = obs.color;
718
+ ctx.fillRect(-40, -60, 80, 60);
719
+
720
+ // Warning symbol
721
+ ctx.fillStyle = '#fbbf24';
722
+ ctx.beginPath();
723
+ ctx.moveTo(0, -45);
724
+ ctx.lineTo(-15, -25);
725
+ ctx.lineTo(15, -25);
726
+ ctx.closePath();
727
+ ctx.fill();
728
+
729
+ ctx.fillStyle = '#000';
730
+ ctx.font = 'bold 12px Arial';
731
+ ctx.textAlign = 'center';
732
+ ctx.fillText('!', 0, -30);
733
+ }
734
+
735
+ ctx.restore();
736
+ });
737
+ }
738
+
739
+ function checkObstacleCollision() {
740
+ const dinoBounds = dino.getBounds();
741
+
742
+ for (const obs of obstacles) {
743
+ const obsBounds = {
744
+ x: obs.x - obs.width / 2,
745
+ y: obs.y + obs.yOffset - (obs.name === 'arch' ? 120 : obs.height),
746
+ width: obs.width,
747
+ height: obs.name === 'arch' ? 120 : obs.height
748
+ };
749
+
750
+ // Adjust for low barrier (can jump over)
751
+ if (obs.name === 'lowBarrier' && dino.isJumping && dino.y < GROUND_Y - 30) {
752
+ continue;
753
+ }
754
+
755
+ // Adjust for arch (can slide under)
756
+ if (obs.name === 'arch' && dino.isSliding) {
757
+ continue;
758
+ }
759
+
760
+ // Check collision
761
+ if (dinoBounds.x < obsBounds.x + obsBounds.width &&
762
+ dinoBounds.x + dinoBounds.width > obsBounds.x &&
763
+ dinoBounds.y < obsBounds.y + obsBounds.height &&
764
+ dinoBounds.y + dinoBounds.height > obsBounds.y) {
765
+
766
+ if (powerups.shield.active) {
767
+ powerups.shield.active = false;
768
+ game.screenShake = 10;
769
+ updatePowerupUI();
770
+ return false;
771
+ }
772
+ return true;
773
+ }
774
+ }
775
+ return false;
776
+ }
777
+
778
+ // ============================================
779
+ // COIN SYSTEM (BITCOIN)
780
+ // ============================================
781
+ const coins = [];
782
+ const coinParticles = [];
783
+
784
+ function spawnCoins() {
785
+ const lane = Math.floor(Math.random() * 3);
786
+ const pattern = Math.random() < 0.3 ? 'arc' : 'line';
787
+ const isBonus = Math.random() < 0.1;
788
+
789
+ if (pattern === 'arc') {
790
+ for (let i = 0; i < 5; i++) {
791
+ coins.push({
792
+ x: LANE_POSITIONS[lane],
793
+ y: GROUND_Y - 40 - Math.sin(i * 0.5) * 30,
794
+ lane: lane,
795
+ rotation: Math.random() * Math.PI * 2,
796
+ glow: 0,
797
+ value: isBonus ? btc.bonusCoinValue : btc.perCoin,
798
+ isBonus: isBonus,
799
+ collected: false
800
+ });
801
+ }
802
+ } else {
803
+ const count = isBonus ? 3 : 5;
804
+ for (let i = 0; i < count; i++) {
805
+ coins.push({
806
+ x: LANE_POSITIONS[lane] - i * 40,
807
+ y: GROUND_Y - 30,
808
+ lane: lane,
809
+ rotation: Math.random() * Math.PI * 2,
810
+ glow: 0,
811
+ value: isBonus ? btc.bonusCoinValue : btc.perCoin,
812
+ isBonus: isBonus,
813
+ collected: false
814
+ });
815
+ }
816
+ }
817
+ }
818
+
819
+ function updateCoins(dt) {
820
+ // Spawn coins
821
+ if (Math.random() < 0.015) {
822
+ spawnCoins();
823
+ }
824
+
825
+ // Magnet effect
826
+ if (powerups.magnet.active) {
827
+ coins.forEach(coin => {
828
+ if (!coin.collected) {
829
+ const dx = dino.x - coin.x;
830
+ const dy = (dino.y - 30) - coin.y;
831
+ const dist = Math.sqrt(dx * dx + dy * dy);
832
+ if (dist < 200) {
833
+ coin.x += dx * 0.1;
834
+ coin.y += dy * 0.1;
835
+ }
836
+ }
837
+ });
838
+ }
839
+
840
+ // Update coins
841
+ for (let i = coins.length - 1; i >= 0; i--) {
842
+ const coin = coins[i];
843
+ coin.x -= game.speed * 60 * (dt / 1000);
844
+ coin.rotation += 0.05;
845
+ coin.glow = (Math.sin(Date.now() * 0.005) + 1) / 2;
846
+
847
+ // Collection check
848
+ if (!coin.collected) {
849
+ const dx = dino.x - coin.x;
850
+ const dy = (dino.y - 30) - coin.y;
851
+ const dist = Math.sqrt(dx * dx + dy * dy);
852
+
853
+ if (dist < 40) {
854
+ coin.collected = true;
855
+ collectCoin(coin);
856
+
857
+ // Spawn particles
858
+ for (let p = 0; p < 10; p++) {
859
+ coinParticles.push({
860
+ x: coin.x,
861
+ y: coin.y,
862
+ vx: (Math.random() - 0.5) * 8,
863
+ vy: (Math.random() - 0.5) * 8,
864
+ life: 1,
865
+ color: coin.isBonus ? '#eab308' : '#F7931A'
866
+ });
867
+ }
868
+ }
869
+ }
870
+
871
+ if (coin.x < -50 || coin.collected) {
872
+ coins.splice(i, 1);
873
+ }
874
+ }
875
+
876
+ // Update particles
877
+ for (let i = coinParticles.length - 1; i >= 0; i--) {
878
+ const p = coinParticles[i];
879
+ p.x += p.vx;
880
+ p.y += p.vy;
881
+ p.life -= 0.03;
882
+ if (p.life <= 0) {
883
+ coinParticles.splice(i, 1);
884
+ }
885
+ }
886
+ }
887
+
888
+ function collectCoin(coin) {
889
+ const value = coin.value * powerups.multiplier.value;
890
+ btc.balance += value;
891
+
892
+ // Combo system
893
+ game.comboTimer = 2000;
894
+ game.combo = Math.min(game.combo + 1, 10);
895
+ if (game.combo > game.bestCombo) {
896
+ game.bestCombo = game.combo;
897
+ }
898
+
899
+ // Show combo
900
+ if (game.combo >= 3) {
901
+ showCombo(game.combo);
902
+ }
903
+
904
+ updateHUD();
905
+ }
906
+
907
+ function showCombo(combo) {
908
+ const comboEl = document.getElementById('comboDisplay');
909
+ comboEl.textContent = `x${combo} COMBO!`;
910
+ comboEl.classList.remove('show');
911
+ void comboEl.offsetWidth;
912
+ comboEl.classList.add('show');
913
+ }
914
+
915
+ function drawCoins(ctx) {
916
+ // Draw coins
917
+ coins.forEach(coin => {
918
+ if (coin.collected) return;
919
+
920
+ ctx.save();
921
+ ctx.translate(coin.x, coin.y);
922
+
923
+ // Glow effect
924
+ const glowIntensity = coin.isBonus ? 25 : 15;
925
+ ctx.shadowColor = coin.isBonus ? '#eab308' : '#F7931A';
926
+ ctx.shadowBlur = glowIntensity + coin.glow * 10;
927
+
928
+ // Coin body (3D rotation effect)
929
+ const scaleX = Math.cos(coin.rotation);
930
+
931
+ ctx.fillStyle = coin.isBonus ? '#eab308' : '#F7931A';
932
+ ctx.beginPath();
933
+ ctx.ellipse(0, 0, 18 * Math.abs(scaleX), 18, 0, 0, Math.PI * 2);
934
+ ctx.fill();
935
+
936
+ // Bitcoin symbol
937
+ if (Math.abs(scaleX) > 0.3) {
938
+ ctx.fillStyle = '#fff';
939
+ ctx.font = 'bold 14px Arial';
940
+ ctx.textAlign = 'center';
941
+ ctx.textBaseline = 'middle';
942
+ ctx.fillText('₿', 0, 0);
943
+ }
944
+
945
+ // Shine
946
+ if (scaleX > 0.5) {
947
+ ctx.fillStyle = 'rgba(255,255,255,0.4)';
948
+ ctx.beginPath();
949
+ ctx.ellipse(-5, -5, 5, 3, -0.5, 0, Math.PI * 2);
950
+ ctx.fill();
951
+ }
952
+
953
+ ctx.restore();
954
+ });
955
+
956
+ // Draw particles
957
+ coinParticles.forEach(p => {
958
+ ctx.globalAlpha = p.life;
959
+ ctx.fillStyle = p.color;
960
+ ctx.beginPath();
961
+ ctx.arc(p.x, p.y, 3, 0, Math.PI * 2);
962
+ ctx.fill();
963
+ });
964
+ ctx.globalAlpha = 1;
965
+ }
966
+
967
+ // ============================================
968
+ // POWER-UP SYSTEM
969
+ // ============================================
970
+ const powerupItems = [];
971
+ const powerupTypes = [
972
+ { name: 'magnet', color: '#9333ea', symbol: '🧲', duration: 8000 },
973
+ { name: 'multiplier', color: '#eab308', symbol: 'x2', duration: 10000 },
974
+ { name: 'shield', color: '#3b82f6', symbol: '🛡', duration: 0 },
975
+ { name: 'speed', color: '#ef4444', symbol: '⚡', duration: 5000 }
976
+ ];
977
+
978
+ function spawnPowerup() {
979
+ const type = powerupTypes[Math.floor(Math.random() * powerupTypes.length)];
980
+ const lane = Math.floor(Math.random() * 3);
981
+
982
+ powerupItems.push({
983
+ x: LANE_POSITIONS[lane],
984
+ y: GROUND_Y - 50,
985
+ lane: lane,
986
+ ...type,
987
+ rotation: 0,
988
+ bobOffset: 0
989
+ });
990
+ }
991
+
992
+ function updatePowerups(dt) {
993
+ // Spawn powerups
994
+ if (Math.random() < 0.002) {
995
+ spawnPowerup();
996
+ }
997
+
998
+ // Update powerup timers
999
+ if (powerups.magnet.active) {
1000
+ powerups.magnet.duration -= dt;
1001
+ if (powerups.magnet.duration <= 0) {
1002
+ powerups.magnet.active = false;
1003
+ updatePowerupUI();
1004
+ }
1005
+ }
1006
+
1007
+ if (powerups.multiplier.active) {
1008
+ powerups.multiplier.duration -= dt;
1009
+ if (powerups.multiplier.duration <= 0) {
1010
+ powerups.multiplier.active = false;
1011
+ powerups.multiplier.value = 1;
1012
+ updatePowerupUI();
1013
+ }
1014
+ }
1015
+
1016
+ if (powerups.speed.active) {
1017
+ powerups.speed.duration -= dt;
1018
+ if (powerups.speed.duration <= 0) {
1019
+ powerups.speed.active = false;
1020
+ game.speed = Math.min(game.speed - 3, MAX_SPEED);
1021
+ updatePowerupUI();
1022
+ }
1023
+ }
1024
+
1025
+ // Update powerup items
1026
+ for (let i = powerupItems.length - 1; i >= 0; i--) {
1027
+ const p = powerupItems[i];
1028
+ p.x -= game.speed * 60 * (dt / 1000);
1029
+ p.rotation += 0.03;
1030
+ p.bobOffset = Math.sin(Date.now() * 0.005) * 5;
1031
+
1032
+ // Collection check
1033
+ const dx = dino.x - p.x;
1034
+ const dy = (dino.y - 30) - (p.y + p.bobOffset);
1035
+ const dist = Math.sqrt(dx * dx + dy * dy);
1036
+
1037
+ if (dist < 40) {
1038
+ activatePowerup(p.name, p.duration);
1039
+ powerupItems.splice(i, 1);
1040
+ continue;
1041
+ }
1042
+
1043
+ if (p.x < -50) {
1044
+ powerupItems.splice(i, 1);
1045
+ }
1046
+ }
1047
+ }
1048
+
1049
+ function activatePowerup(name, duration) {
1050
+ switch(name) {
1051
+ case 'magnet':
1052
+ powerups.magnet.active = true;
1053
+ powerups.magnet.duration = duration;
1054
+ break;
1055
+ case 'multiplier':
1056
+ powerups.multiplier.active = true;
1057
+ powerups.multiplier.value = 2;
1058
+ powerups.multiplier.duration = duration;
1059
+ break;
1060
+ case 'shield':
1061
+ powerups.shield.active = true;
1062
+ break;
1063
+ case 'speed':
1064
+ powerups.speed.active = true;
1065
+ powerups.speed.duration = duration;
1066
+ game.speed = Math.min(game.speed + 3, MAX_SPEED);
1067
+ break;
1068
+ }
1069
+ updatePowerupUI();
1070
+ }
1071
+
1072
+ function updatePowerupUI() {
1073
+ const indicator = document.getElementById('powerupIndicator');
1074
+ indicator.innerHTML = '';
1075
+
1076
+ if (powerups.magnet.active) {
1077
+ indicator.innerHTML += '<div class="powerup-badge magnet active">🧲 MAGNET</div>';
1078
+ }
1079
+ if (powerups.multiplier.active) {
1080
+ indicator.innerHTML += '<div class="powerup-badge multiplier active">x2 MULTIPLIER</div>';
1081
+ }
1082
+ if (powerups.shield.active) {
1083
+ indicator.innerHTML += '<div class="powerup-badge shield active">🛡 SHIELD</div>';
1084
+ }
1085
+ if (powerups.speed.active) {
1086
+ indicator.innerHTML += '<div class="powerup-badge speed active">⚡ SPEED</div>';
1087
+ }
1088
+ }
1089
+
1090
+ function drawPowerups(ctx) {
1091
+ powerupItems.forEach(p => {
1092
+ ctx.save();
1093
+ ctx.translate(p.x, p.y + p.bobOffset);
1094
+ ctx.rotate(p.rotation);
1095
+
1096
+ // Glow
1097
+ ctx.shadowColor = p.color;
1098
+ ctx.shadowBlur = 20;
1099
+
1100
+ // Background circle
1101
+ ctx.fillStyle = p.color;
1102
+ ctx.beginPath();
1103
+ ctx.arc(0, 0, 25, 0, Math.PI * 2);
1104
+ ctx.fill();
1105
+
1106
+ // Inner circle
1107
+ ctx.fillStyle = '#fff';
1108
+ ctx.beginPath();
1109
+ ctx.arc(0, 0, 18, 0, Math.PI * 2);
1110
+ ctx.fill();
1111
+
1112
+ // Symbol
1113
+ ctx.fillStyle = p.color;
1114
+ ctx.font = 'bold 16px Arial';
1115
+ ctx.textAlign = 'center';
1116
+ ctx.textBaseline = 'middle';
1117
+ ctx.fillText(p.symbol, 0, 0);
1118
+
1119
+ ctx.restore();
1120
+ });
1121
+ }
1122
+
1123
+ // ============================================
1124
+ // BACKGROUND & ENVIRONMENT
1125
+ // ============================================
1126
+ const background = {
1127
+ layers: [
1128
+ { speed: 0.2, y: 0, color: '#1e3a5f' },
1129
+ { speed: 0.4, y: 50, color: '#2563eb' },
1130
+ { speed: 0.6, y: 100, color: '#3b82f6' }
1131
+ ],
1132
+ clouds: [],
1133
+ buildings: [],
1134
+
1135
+ init() {
1136
+ // Generate clouds
1137
+ for (let i = 0; i < 10; i++) {
1138
+ this.clouds.push({
1139
+ x: Math.random() * CANVAS_WIDTH,
1140
+ y: 30 + Math.random() * 80,
1141
+ size: 30 + Math.random() * 40,
1142
+ speed: 0.3 + Math.random() * 0.3
1143
+ });
1144
+ }
1145
+
1146
+ // Generate buildings
1147
+ for (let i = 0; i < 15; i++) {
1148
+ this.buildings.push({
1149
+ x: i * 80,
1150
+ width: 40 + Math.random() * 40,
1151
+ height: 60 + Math.random() * 100,
1152
+ color: `hsl(${200 + Math.random() * 40}, 60%, ${20 + Math.random() * 20}%)`
1153
+ });
1154
+ }
1155
+ },
1156
+
1157
+ update(dt) {
1158
+ const moveAmount = game.speed * 60 * (dt / 1000);
1159
+
1160
+ // Move clouds
1161
+ this.clouds.forEach(cloud => {
1162
+ cloud.x -= cloud.speed * moveAmount * 0.5;
1163
+ if (cloud.x < -100) {
1164
+ cloud.x = CANVAS_WIDTH + 50;
1165
+ cloud.y = 30 + Math.random() * 80;
1166
+ }
1167
+ });
1168
+
1169
+ // Move buildings
1170
+ this.buildings.forEach(building => {
1171
+ building.x -= moveAmount * 0.3;
1172
+ if (building.x < -building.width) {
1173
+ building.x = CANVAS_WIDTH + Math.random() * 50;
1174
+ building.height = 60 + Math.random() * 100;
1175
+ }
1176
+ });
1177
+ },
1178
+
1179
+ draw(ctx) {
1180
+ // Sky gradient
1181
+ const gradient = ctx.createLinearGradient(0, 0, 0, CANVAS_HEIGHT);
1182
+ gradient.addColorStop(0, '#1e3a5f');
1183
+ gradient.addColorStop(0.5, '#3b82f6');
1184
+ gradient.addColorStop(1, '#60a5fa');
1185
+ ctx.fillStyle = gradient;
1186
+ ctx.fillRect(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT);
1187
+
1188
+ // Clouds
1189
+ ctx.fillStyle = 'rgba(255, 255, 255, 0.8)';
1190
+ this.clouds.forEach(cloud => {
1191
+ ctx.beginPath();
1192
+ ctx.arc(cloud.x, cloud.y, cloud.size * 0.6, 0, Math.PI * 2);
1193
+ ctx.arc(cloud.x + cloud.size * 0.4, cloud.y - cloud.size * 0.2, cloud.size * 0.4, 0, Math.PI * 2);
1194
+ ctx.arc(cloud.x + cloud.size * 0.8, cloud.y, cloud.size * 0.5, 0, Math.PI * 2);
1195
+ ctx.fill();
1196
+ });
1197
+
1198
+ // Distant buildings (parallax)
1199
+ this.buildings.forEach(building => {
1200
+ ctx.fillStyle = building.color;
1201
+ ctx.fillRect(building.x, GROUND_Y - building.height, building.width, building.height);
1202
+
1203
+ // Windows
1204
+ ctx.fillStyle = 'rgba(255, 255, 150, 0.6)';
1205
+ for (let wy = GROUND_Y - building.height + 10; wy < GROUND_Y - 10; wy += 15) {
1206
+ for (let wx = building.x + 5; wx < building.x + building.width - 10; wx += 12) {
1207
+ if