JohnPork04 commited on
Commit
bb2ce28
·
verified ·
1 Parent(s): 25aa909

Add 1 files

Browse files
Files changed (1) hide show
  1. index.html +582 -607
index.html CHANGED
@@ -3,681 +3,656 @@
3
  <head>
4
  <meta charset="UTF-8">
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
- <title>Neural Canvas - Interactive AI Art</title>
7
  <script src="https://cdn.tailwindcss.com"></script>
8
- <script src="https://cdn.jsdelivr.net/npm/p5@1.9.0/p5.js"></script>
9
  <style>
10
  body {
 
 
11
  overflow: hidden;
12
- font-family: 'Inter', sans-serif;
13
- background: linear-gradient(135deg, #000428 0%, #004e92 100%);
14
  }
15
- .art-container {
16
- position: absolute;
17
- top: 0;
18
- left: 0;
19
- width: 100%;
20
- height: 100%;
21
- z-index: 1;
22
- }
23
- .control-panel {
24
- position: absolute;
25
- bottom: 2rem;
26
- left: 50%;
27
- transform: translateX(-50%);
28
- z-index: 10;
29
- background: rgba(0, 0, 0, 0.7);
30
- backdrop-filter: blur(10px);
31
- border-radius: 50px;
32
- padding: 1rem 2rem;
33
- display: flex;
34
- gap: 1rem;
35
- box-shadow: 0 10px 30px rgba(0, 0, 0, 0.5);
36
- }
37
- .art-button {
38
- padding: 0.8rem 1.5rem;
39
- border-radius: 50px;
40
- font-weight: 600;
41
- font-size: 0.9rem;
42
- letter-spacing: 1px;
43
- cursor: pointer;
44
- transition: all 0.3s ease;
45
- border: none;
46
- color: white;
47
- background: rgba(255, 255, 255, 0.1);
48
- }
49
- .art-button:hover {
50
- transform: translateY(-3px);
51
- background: rgba(255, 255, 255, 0.2);
52
  }
53
- .art-button.active {
54
- background: white;
55
- color: #004e92;
56
- font-weight: 700;
57
  }
58
- .title {
59
  position: absolute;
60
- top: 2rem;
61
- left: 0;
62
- width: 100%;
63
- text-align: center;
64
  color: white;
65
- font-size: 3rem;
66
- font-weight: 800;
67
- text-shadow: 0 2px 10px rgba(0, 0, 0, 0.5);
68
  z-index: 10;
69
- letter-spacing: 2px;
70
  }
71
- .subtitle {
72
  position: absolute;
73
- top: 6rem;
74
- left: 0;
75
- width: 100%;
76
- text-align: center;
77
- color: rgba(255, 255, 255, 0.8);
78
- font-size: 1.1rem;
79
- font-weight: 400;
80
- text-shadow: 0 1px 5px rgba(0, 0, 0, 0.3);
81
- z-index: 10;
82
- letter-spacing: 1px;
83
- }
84
- .interaction-info {
85
- position: absolute;
86
- bottom: 6rem;
87
  left: 0;
88
  width: 100%;
89
- text-align: center;
90
- color: rgba(255, 255, 255, 0.6);
91
- font-size: 0.9rem;
92
- z-index: 10;
 
 
 
 
93
  }
94
- .gradient-overlay {
95
  position: absolute;
96
  top: 0;
97
  left: 0;
98
  width: 100%;
99
  height: 100%;
100
- background: radial-gradient(circle at center, rgba(0,0,0,0.1) 0%, rgba(0,0,0,0.7) 100%);
101
- z-index: 2;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
102
  }
103
  </style>
104
  </head>
105
- <body class="h-screen w-screen relative">
106
- <div class="title">NEURAL CANVAS</div>
107
- <div class="subtitle">Interactive AI-Generated Art Experience</div>
108
-
109
- <div class="interaction-info">Move your mouse to influence the patterns • Click buttons to change styles</div>
110
-
111
- <div class="control-panel">
112
- <button id="fractal" class="art-button active">Fractal</button>
113
- <button id="fluid" class="art-button">Fluid</button>
114
- <button id="neural" class="art-button">Neural</button>
115
- <button id="quantum" class="art-button">Quantum</button>
116
- <button id="cosmic" class="art-button">Cosmic</button>
 
 
 
 
 
 
 
 
 
 
 
117
  </div>
118
-
119
- <div id="canvas-container" class="art-container"></div>
120
- <div class="gradient-overlay"></div>
121
 
122
  <script>
123
- let sketch = function(p) {
124
- let particles = [];
125
- let mode = 'fractal';
126
- let mouseX = 0;
127
- let mouseY = 0;
128
- let mouseIsMoving = false;
129
- let mouseMoveTimeout;
130
- let flowField = [];
131
- let fieldResolution = 20;
132
- let zoff = 0;
133
- let neuralWeights = [];
134
- let neuralLayers = [];
135
-
136
- // Color palettes for different modes
137
- const colorPalettes = {
138
- fractal: [
139
- p.color(255, 107, 107), // Red
140
- p.color(255, 159, 67), // Orange
141
- p.color(255, 206, 84), // Yellow
142
- p.color(29, 209, 161), // Teal
143
- p.color(72, 219, 251) // Blue
144
- ],
145
- fluid: [
146
- p.color(6, 82, 221), // Deep Blue
147
- p.color(0, 210, 255), // Cyan
148
- p.color(100, 255, 218), // Mint
149
- p.color(255, 255, 255) // White
150
- ],
151
- neural: [
152
- p.color(131, 58, 180), // Purple
153
- p.color(253, 29, 29), // Red
154
- p.color(252, 176, 69), // Orange
155
- p.color(255, 255, 0), // Yellow
156
- p.color(0, 255, 0) // Green
157
- ],
158
- quantum: [
159
- p.color(0, 255, 255), // Cyan
160
- p.color(255, 0, 255), // Magenta
161
- p.color(255, 255, 0), // Yellow
162
- p.color(255, 255, 255) // White
163
- ],
164
- cosmic: [
165
- p.color(12, 20, 69), // Deep Space
166
- p.color(65, 105, 225), // Royal Blue
167
- p.color(138, 43, 226), // Purple
168
- p.color(255, 215, 0) // Gold
169
- ]
170
- };
171
-
172
- // Initialize neural network weights for visualization
173
- function initNeuralWeights() {
174
- neuralWeights = [];
175
- neuralLayers = [];
176
-
177
- // Create 3-5 layers with random neuron counts
178
- const layerCount = p.floor(p.random(3, 6));
179
- for (let i = 0; i < layerCount; i++) {
180
- neuralLayers.push(p.floor(p.random(3, 8)));
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
181
  }
182
 
183
- // Create weights between layers
184
- for (let i = 0; i < layerCount - 1; i++) {
185
- const weights = [];
186
- for (let j = 0; j < neuralLayers[i] * neuralLayers[i+1]; j++) {
187
- weights.push(p.random(-1, 1));
188
- }
189
- neuralWeights.push(weights);
190
- }
 
 
 
 
 
 
 
 
 
 
191
  }
192
 
193
- p.setup = function() {
194
- let canvas = p.createCanvas(p.windowWidth, p.windowHeight);
195
- canvas.parent('canvas-container');
196
-
197
- // Create initial particles
198
- for (let i = 0; i < 500; i++) {
199
- particles.push(new Particle());
200
- }
201
-
202
- // Initialize flow field
203
- initFlowField();
204
-
205
- // Initialize neural weights
206
- initNeuralWeights();
207
- };
208
-
209
- function initFlowField() {
210
- flowField = [];
211
- for (let x = 0; x < p.width; x += fieldResolution) {
212
- for (let y = 0; y < p.height; y += fieldResolution) {
213
- flowField.push({
214
- x: x,
215
- y: y,
216
- angle: p.random(p.TWO_PI),
217
- strength: p.random(0.5, 2)
218
- });
219
- }
220
- }
221
  }
222
 
223
- p.draw = function() {
224
- // Different background styles for each mode
225
- switch(mode) {
226
- case 'fractal':
227
- p.background(0, 10);
228
- break;
229
- case 'fluid':
230
- p.background(6, 18, 42, 10);
231
- break;
232
- case 'neural':
233
- p.background(0, 5);
234
- break;
235
- case 'quantum':
236
- p.background(0, 15);
237
- break;
238
- case 'cosmic':
239
- p.background(12, 20, 69, 10);
240
- break;
241
- }
242
-
243
- // Update flow field for fluid mode
244
- if (mode === 'fluid') {
245
- updateFlowField();
246
- }
247
-
248
- // Update and display particles
249
- for (let particle of particles) {
250
- // Apply mouse influence
251
- if (mouseIsMoving) {
252
- const mouseDist = p.dist(particle.pos.x, particle.pos.y, mouseX, mouseY);
253
- if (mouseDist < 200) {
254
- const force = p.createVector(
255
- (mouseX - particle.pos.x) * 0.1,
256
- (mouseY - particle.pos.y) * 0.1
257
- );
258
- particle.applyForce(force);
259
- }
260
- }
261
-
262
- // Apply behaviors based on mode
263
- switch(mode) {
264
- case 'fractal':
265
- applyFractalBehavior(particle);
266
- break;
267
- case 'fluid':
268
- applyFluidBehavior(particle);
269
- break;
270
- case 'neural':
271
- applyNeuralBehavior(particle);
272
- break;
273
- case 'quantum':
274
- applyQuantumBehavior(particle);
275
- break;
276
- case 'cosmic':
277
- applyCosmicBehavior(particle);
278
- break;
279
- }
280
-
281
- particle.update();
282
- particle.display();
283
- }
284
-
285
- // Add new particles occasionally
286
- if (p.frameCount % 5 === 0 && particles.length < 1000) {
287
- particles.push(new Particle());
288
- }
289
-
290
- // Remove old particles if too many
291
- if (particles.length > 1000) {
292
- particles.shift();
293
- }
294
-
295
- // Special rendering for neural mode
296
- if (mode === 'neural') {
297
- renderNeuralNetwork();
298
- }
299
- };
300
 
301
- function updateFlowField() {
302
- zoff += 0.01;
303
- let yoff = 0;
304
-
305
- for (let point of flowField) {
306
- let xoff = p.map(point.x, 0, p.width, 0, 5);
307
- yoff = p.map(point.y, 0, p.height, 0, 5);
308
-
309
- // Update angle based on noise
310
- point.angle = p.map(p.noise(xoff, yoff, zoff), 0, 1, 0, p.TWO_PI);
311
-
312
- // Add some mouse influence
313
- const mouseDist = p.dist(point.x, point.y, mouseX, mouseY);
314
- if (mouseDist < 150) {
315
- point.angle = p.atan2(mouseY - point.y, mouseX - point.x);
316
- point.strength = p.map(mouseDist, 0, 150, 2, 0.5);
317
- }
318
- }
319
  }
320
 
321
- function applyFractalBehavior(particle) {
322
- // Fractal-inspired movement
323
- const noiseVal = p.noise(
324
- particle.pos.x * 0.005,
325
- particle.pos.y * 0.005,
326
- p.frameCount * 0.01
327
- );
328
-
329
- const angle = noiseVal * p.TWO_PI * 4;
330
- const force = p5.Vector.fromAngle(angle).mult(0.2);
331
- particle.applyForce(force);
332
-
333
- // Attract to center with some randomness
334
- const center = p.createVector(p.width/2, p.height/2);
335
- const toCenter = p5.Vector.sub(center, particle.pos);
336
- toCenter.normalize().mult(0.05 * noiseVal);
337
- particle.applyForce(toCenter);
338
  }
339
 
340
- function applyFluidBehavior(particle) {
341
- // Find closest flow field point
342
- const closestX = p.constrain(p.floor(particle.pos.x / fieldResolution) * fieldResolution, 0, p.width);
343
- const closestY = p.constrain(p.floor(particle.pos.y / fieldResolution) * fieldResolution, 0, p.height);
344
-
345
- let closestPoint = null;
346
- let minDist = Infinity;
347
-
348
- for (let point of flowField) {
349
- const dist = p.dist(particle.pos.x, particle.pos.y, point.x, point.y);
350
- if (dist < minDist) {
351
- minDist = dist;
352
- closestPoint = point;
353
- }
354
- }
355
-
356
- if (closestPoint) {
357
- const force = p5.Vector.fromAngle(closestPoint.angle).mult(closestPoint.strength * 0.1);
358
- particle.applyForce(force);
359
  }
360
  }
361
 
362
- function applyNeuralBehavior(particle) {
363
- // Neural network-inspired behavior
364
- const inputX = p.map(particle.pos.x, 0, p.width, -1, 1);
365
- const inputY = p.map(particle.pos.y, 0, p.height, -1, 1);
366
-
367
- // Simple neural network simulation
368
- let layerOutputs = [[inputX, inputY]];
369
-
370
- for (let i = 0; i < neuralWeights.length; i++) {
371
- const weights = neuralWeights[i];
372
- const inputLayer = layerOutputs[i];
373
- const outputSize = neuralLayers[i+1];
374
- const newLayer = new Array(outputSize).fill(0);
375
-
376
- for (let j = 0; j < outputSize; j++) {
377
- for (let k = 0; k < inputLayer.length; k++) {
378
- const weightIndex = j * inputLayer.length + k;
379
- newLayer[j] += inputLayer[k] * weights[weightIndex];
380
- }
381
- // Simple activation function
382
- newLayer[j] = Math.tanh(newLayer[j]);
383
- }
384
-
385
- layerOutputs.push(newLayer);
386
- }
387
-
388
- // Use final layer outputs to determine movement
389
- const finalOutputs = layerOutputs[layerOutputs.length - 1];
390
- const force = p.createVector(
391
- finalOutputs[0] * 2,
392
- finalOutputs.length > 1 ? finalOutputs[1] * 2 : 0
393
- );
394
-
395
- particle.applyForce(force);
396
  }
397
 
398
- function applyQuantumBehavior(particle) {
399
- // Quantum physics-inspired behavior
400
- const x = particle.pos.x * 0.01;
401
- const y = particle.pos.y * 0.01;
402
- const t = p.frameCount * 0.01;
403
-
404
- // Wave function collapse probability
405
- const prob = p.pow(p.sin(x + t) * p.cos(y - t), 2);
406
 
407
- if (prob > 0.5) {
408
- // Quantum tunneling effect
409
- const angle = p.random(p.TWO_PI);
410
- const force = p5.Vector.fromAngle(angle).mult(2);
411
- particle.applyForce(force);
412
  } else {
413
- // Quantum harmonic oscillator
414
- const centerForce = p.createVector(
415
- p.width/2 - particle.pos.x,
416
- p.height/2 - particle.pos.y
417
- ).normalize().mult(0.05);
418
-
419
- particle.applyForce(centerForce);
420
  }
421
  }
422
 
423
- function applyCosmicBehavior(particle) {
424
- // Cosmic/gravity-inspired behavior
425
- const center = p.createVector(p.width/2, p.height/2);
426
- const toCenter = p5.Vector.sub(center, particle.pos);
427
- const distance = toCenter.mag();
428
-
429
- // Inverse square law gravity
430
- const strength = 10000 / (distance * distance);
431
- toCenter.normalize().mult(strength);
432
- particle.applyForce(toCenter);
433
-
434
- // Add some random cosmic rays
435
- if (p.random() < 0.01) {
436
- const cosmicForce = p5.Vector.random2D().mult(5);
437
- particle.applyForce(cosmicForce);
438
- }
439
  }
440
 
441
- function renderNeuralNetwork() {
442
- p.push();
443
- p.noFill();
444
- p.stroke(255, 50);
445
- p.strokeWeight(1);
446
-
447
- const layerSpacing = p.width / (neuralLayers.length + 1);
448
- const maxNeurons = Math.max(...neuralLayers);
449
-
450
- // Draw connections between layers
451
- for (let i = 0; i < neuralWeights.length; i++) {
452
- const weights = neuralWeights[i];
453
- const neuronsIn = neuralLayers[i];
454
- const neuronsOut = neuralLayers[i+1];
455
-
456
- const x1 = (i + 1) * layerSpacing;
457
- const x2 = (i + 2) * layerSpacing;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
458
 
459
- for (let j = 0; j < neuronsIn; j++) {
460
- const y1 = p.map(j, 0, neuronsIn - 1, 100, p.height - 100);
461
-
462
- for (let k = 0; k < neuronsOut; k++) {
463
- const y2 = p.map(k, 0, neuronsOut - 1, 100, p.height - 100);
464
- const weight = weights[k * neuronsIn + j];
465
-
466
- // Color based on weight value
467
- if (weight > 0) {
468
- p.stroke(0, 255, 0, p.map(weight, 0, 1, 50, 200));
469
- } else {
470
- p.stroke(255, 0, 0, p.map(weight, -1, 0, 50, 200));
471
- }
472
-
473
- p.line(x1, y1, x2, y2);
474
- }
475
- }
476
- }
477
-
478
- // Draw neurons
479
- for (let i = 0; i < neuralLayers.length; i++) {
480
- const neuronCount = neuralLayers[i];
481
- const x = (i + 1) * layerSpacing;
482
 
483
- for (let j = 0; j < neuronCount; j++) {
484
- const y = p.map(j, 0, neuronCount - 1, 100, p.height - 100);
485
-
486
- // Color based on layer
487
- const layerColor = p.color(colorPalettes.neural[i % colorPalettes.neural.length]);
488
- p.fill(layerColor);
489
- p.noStroke();
490
- p.circle(x, y, 15);
491
- }
492
  }
493
 
494
- p.pop();
495
  }
496
 
497
- p.mouseMoved = function() {
498
- mouseX = p.mouseX;
499
- mouseY = p.mouseY;
500
- mouseIsMoving = true;
501
-
502
- clearTimeout(mouseMoveTimeout);
503
- mouseMoveTimeout = setTimeout(() => {
504
- mouseIsMoving = false;
505
- }, 100);
506
-
507
- // Add particles at mouse position
508
- if (mode === 'fluid' || mode === 'quantum') {
509
- for (let i = 0; i < 5; i++) {
510
- particles.push(new Particle(mouseX, mouseY));
511
- }
512
- }
513
- };
514
-
515
- p.touchMoved = function() {
516
- p.mouseMoved();
517
- return false;
518
- };
519
-
520
- p.windowResized = function() {
521
- p.resizeCanvas(p.windowWidth, p.windowHeight);
522
- initFlowField();
523
- };
524
-
525
- class Particle {
526
- constructor(x, y) {
527
- this.pos = x && y ?
528
- p.createVector(x, y) :
529
- p.createVector(p.random(p.width), p.random(p.height));
530
-
531
- this.vel = p5.Vector.random2D().mult(p.random(0.5, 2));
532
- this.acc = p.createVector();
533
- this.life = p.random(100, 200);
534
- this.maxLife = this.life;
535
- this.size = p.random(2, 8);
536
- this.color = p.random(colorPalettes[mode]);
537
- this.rotation = p.random(p.TWO_PI);
538
- this.rotationSpeed = p.random(-0.02, 0.02);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
539
  }
540
-
541
- applyForce(force) {
542
- this.acc.add(force);
 
 
 
 
 
 
 
 
 
 
 
 
 
543
  }
544
-
545
- update() {
546
- this.vel.add(this.acc);
547
-
548
- // Different velocity limits per mode
549
- switch(mode) {
550
- case 'fractal':
551
- this.vel.limit(3);
552
- break;
553
- case 'fluid':
554
- this.vel.limit(2);
555
- break;
556
- case 'neural':
557
- this.vel.limit(4);
558
- break;
559
- case 'quantum':
560
- this.vel.limit(5);
561
- break;
562
- case 'cosmic':
563
- this.vel.limit(8);
564
- break;
565
- }
566
-
567
- this.pos.add(this.vel);
568
- this.acc.mult(0);
569
- this.life--;
570
- this.rotation += this.rotationSpeed;
571
-
572
- // Wrap around edges
573
- if (this.pos.x < 0) this.pos.x = p.width;
574
- if (this.pos.x > p.width) this.pos.x = 0;
575
- if (this.pos.y < 0) this.pos.y = p.height;
576
- if (this.pos.y > p.height) this.pos.y = 0;
577
  }
578
 
579
- display() {
580
- p.push();
581
- p.translate(this.pos.x, this.pos.y);
582
- p.rotate(this.rotation);
583
-
584
- const alpha = p.map(this.life, 0, this.maxLife, 0, 255);
585
- this.color.setAlpha(alpha);
586
- p.fill(this.color);
587
- p.noStroke();
588
-
589
- // Different shapes per mode
590
- switch(mode) {
591
- case 'fractal':
592
- p.circle(0, 0, this.size);
593
- break;
594
- case 'fluid':
595
- p.ellipse(0, 0, this.size * 1.5, this.size);
596
- break;
597
- case 'neural':
598
- p.rect(0, 0, this.size, this.size, this.size/4);
599
- break;
600
- case 'quantum':
601
- p.triangle(
602
- -this.size/2, this.size/2,
603
- 0, -this.size/2,
604
- this.size/2, this.size/2
605
- );
606
- break;
607
- case 'cosmic':
608
- p.stroke(this.color);
609
- p.strokeWeight(1);
610
- p.line(-this.size/2, 0, this.size/2, 0);
611
- p.line(0, -this.size/2, 0, this.size/2);
612
- break;
613
- }
614
-
615
- p.pop();
616
  }
617
  }
618
 
619
- // Change mode based on button clicks
620
- this.setMode = function(newMode) {
621
- mode = newMode;
622
-
623
- // Update active button styling
624
- document.querySelectorAll('.art-button').forEach(btn => {
625
- btn.classList.remove('active');
626
- });
627
- document.getElementById(newMode).classList.add('active');
628
-
629
- // Reset all particles with new colors
630
- particles = [];
631
- for (let i = 0; i < 500; i++) {
632
- particles.push(new Particle());
633
  }
 
 
 
 
 
 
634
 
635
- // Reinitialize components for specific modes
636
- if (mode === 'fluid') {
637
- initFlowField();
638
- } else if (mode === 'neural') {
639
- initNeuralWeights();
640
  }
641
 
642
- // Change background gradient
643
- switch(mode) {
644
- case 'fractal':
645
- document.body.style.background = 'linear-gradient(135deg, #000428 0%, #004e92 100%)';
646
- break;
647
- case 'fluid':
648
- document.body.style.background = 'linear-gradient(135deg, #020111 0%, #3a3a52 100%)';
649
- break;
650
- case 'neural':
651
- document.body.style.background = 'linear-gradient(135deg, #0f0c29 0%, #302b63 50%, #24243e 100%)';
652
- break;
653
- case 'quantum':
654
- document.body.style.background = 'linear-gradient(135deg, #000000 0%, #0f2027 50%, #203a43 100%)';
655
- break;
656
- case 'cosmic':
657
- document.body.style.background = 'linear-gradient(135deg, #000000 0%, #1a1a2e 50%, #16213e 100%)';
658
- break;
659
  }
660
- };
661
- };
662
-
663
- let myp5 = new p5(sketch);
664
-
665
- // Button event listeners
666
- document.getElementById('fractal').addEventListener('click', function() {
667
- myp5.setMode('fractal');
668
- });
669
- document.getElementById('fluid').addEventListener('click', function() {
670
- myp5.setMode('fluid');
671
- });
672
- document.getElementById('neural').addEventListener('click', function() {
673
- myp5.setMode('neural');
674
- });
675
- document.getElementById('quantum').addEventListener('click', function() {
676
- myp5.setMode('quantum');
677
- });
678
- document.getElementById('cosmic').addEventListener('click', function() {
679
- myp5.setMode('cosmic');
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
680
  });
 
 
 
 
681
  </script>
682
  <p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-deepsite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >DeepSite</a> - 🧬 <a href="https://enzostvs-deepsite.hf.space?remix=JohnPork04/neural-canvas" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body>
683
  </html>
 
3
  <head>
4
  <meta charset="UTF-8">
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Cosmic Evasion</title>
7
  <script src="https://cdn.tailwindcss.com"></script>
 
8
  <style>
9
  body {
10
+ margin: 0;
11
+ padding: 0;
12
  overflow: hidden;
13
+ font-family: 'Arial', sans-serif;
 
14
  }
15
+ #game-container {
16
+ position: relative;
17
+ width: 100vw;
18
+ height: 100vh;
19
+ overflow: hidden;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
20
  }
21
+ #game-canvas {
22
+ display: block;
23
+ background-color: #000;
 
24
  }
25
+ #ui {
26
  position: absolute;
27
+ top: 20px;
28
+ left: 20px;
 
 
29
  color: white;
30
+ font-size: 18px;
31
+ text-shadow: 0 0 5px rgba(0, 255, 255, 0.8);
 
32
  z-index: 10;
 
33
  }
34
+ #start-screen {
35
  position: absolute;
36
+ top: 0;
 
 
 
 
 
 
 
 
 
 
 
 
 
37
  left: 0;
38
  width: 100%;
39
+ height: 100%;
40
+ background-color: rgba(0, 0, 0, 0.7);
41
+ display: flex;
42
+ flex-direction: column;
43
+ justify-content: center;
44
+ align-items: center;
45
+ color: white;
46
+ z-index: 20;
47
  }
48
+ #game-over {
49
  position: absolute;
50
  top: 0;
51
  left: 0;
52
  width: 100%;
53
  height: 100%;
54
+ background-color: rgba(0, 0, 0, 0.7);
55
+ display: none;
56
+ flex-direction: column;
57
+ justify-content: center;
58
+ align-items: center;
59
+ color: white;
60
+ z-index: 20;
61
+ }
62
+ .btn {
63
+ margin-top: 20px;
64
+ padding: 10px 30px;
65
+ background: linear-gradient(135deg, #00d2ff 0%, #3a7bd5 100%);
66
+ border: none;
67
+ border-radius: 30px;
68
+ color: white;
69
+ font-size: 18px;
70
+ cursor: pointer;
71
+ transition: all 0.3s;
72
+ box-shadow: 0 5px 15px rgba(0, 210, 255, 0.4);
73
+ }
74
+ .btn:hover {
75
+ transform: translateY(-3px);
76
+ box-shadow: 0 8px 20px rgba(0, 210, 255, 0.6);
77
+ }
78
+ .btn:active {
79
+ transform: translateY(1px);
80
  }
81
  </style>
82
  </head>
83
+ <body class="bg-black">
84
+ <div id="game-container">
85
+ <canvas id="game-canvas"></canvas>
86
+ <div id="ui">
87
+ <div>Score: <span id="score">0</span></div>
88
+ <div>Distance: <span id="distance">0</span> light-years</div>
89
+ <div>Speed: <span id="speed">0</span></div>
90
+ </div>
91
+ <div id="start-screen">
92
+ <h1 class="text-4xl font-bold mb-4 text-transparent bg-clip-text bg-gradient-to-r from-cyan-400 to-blue-500">COSMIC EVASION</h1>
93
+ <p class="text-xl mb-8">Navigate through space and avoid obstacles!</p>
94
+ <button id="start-btn" class="btn">START GAME</button>
95
+ <div class="mt-8 text-sm opacity-70">
96
+ <p>Controls: Arrow Keys or WASD to move</p>
97
+ <p>Space to boost (limited fuel)</p>
98
+ </div>
99
+ </div>
100
+ <div id="game-over">
101
+ <h1 class="text-4xl font-bold mb-4 text-transparent bg-clip-text bg-gradient-to-r from-red-400 to-pink-600">GAME OVER</h1>
102
+ <p class="text-xl mb-2">Final Score: <span id="final-score">0</span></p>
103
+ <p class="text-xl mb-8">Distance Traveled: <span id="final-distance">0</span> light-years</p>
104
+ <button id="restart-btn" class="btn">PLAY AGAIN</button>
105
+ </div>
106
  </div>
 
 
 
107
 
108
  <script>
109
+ // Game variables
110
+ const canvas = document.getElementById('game-canvas');
111
+ const ctx = canvas.getContext('2d');
112
+ const scoreElement = document.getElementById('score');
113
+ const distanceElement = document.getElementById('distance');
114
+ const speedElement = document.getElementById('speed');
115
+ const finalScoreElement = document.getElementById('final-score');
116
+ const finalDistanceElement = document.getElementById('final-distance');
117
+ const startScreen = document.getElementById('start-screen');
118
+ const gameOverScreen = document.getElementById('game-over');
119
+ const startBtn = document.getElementById('start-btn');
120
+ const restartBtn = document.getElementById('restart-btn');
121
+
122
+ // Set canvas size
123
+ canvas.width = window.innerWidth;
124
+ canvas.height = window.innerHeight;
125
+
126
+ // Game state
127
+ let gameRunning = false;
128
+ let score = 0;
129
+ let distance = 0;
130
+ let speed = 3;
131
+ let gameSpeed = 3;
132
+ let boostFuel = 100;
133
+ let isBoosting = false;
134
+ let backgroundOffset = 0;
135
+ let currentBackground = 0;
136
+ let obstacleSpawnTimer = 0;
137
+ let starSpawnTimer = 0;
138
+ let planetSpawnTimer = 0;
139
+ let animationFrameId;
140
+
141
+ // Background colors for different zones
142
+ const backgroundColors = [
143
+ { top: '#000428', bottom: '#004e92' }, // Blue nebula
144
+ { top: '#1a1a2e', bottom: '#16213e' }, // Deep space
145
+ { top: '#0f0c29', bottom: '#302b63' }, // Purple nebula
146
+ { top: '#3a1c71', bottom: '#d76d77' }, // Pink/purple
147
+ { top: '#000000', bottom: '#0f2027' }, // Dark space
148
+ { top: '#1e3c72', bottom: '#2a5298' }, // Blue space
149
+ { top: '#614385', bottom: '#516395' }, // Purple space
150
+ { top: '#0f2027', bottom: '#203a43' } // Dark blue
151
+ ];
152
+
153
+ // Player
154
+ const player = {
155
+ x: canvas.width / 4,
156
+ y: canvas.height / 2,
157
+ width: 40,
158
+ height: 30,
159
+ speed: 5,
160
+ color: '#00d2ff',
161
+ boostColor: '#ff5e62',
162
+ isBoosting: false,
163
+ draw() {
164
+ ctx.save();
165
+ ctx.fillStyle = this.isBoosting ? this.boostColor : this.color;
166
+
167
+ // Draw spaceship
168
+ ctx.beginPath();
169
+ ctx.moveTo(this.x, this.y);
170
+ ctx.lineTo(this.x - this.width, this.y + this.height/2);
171
+ ctx.lineTo(this.x, this.y + this.height);
172
+ ctx.closePath();
173
+ ctx.fill();
174
+
175
+ // Draw boost flame if boosting
176
+ if (this.isBoosting) {
177
+ ctx.beginPath();
178
+ ctx.moveTo(this.x - this.width, this.y + this.height/2 - 5);
179
+ ctx.lineTo(this.x - this.width - 15, this.y + this.height/2);
180
+ ctx.lineTo(this.x - this.width, this.y + this.height/2 + 5);
181
+ ctx.closePath();
182
+ ctx.fill();
183
  }
184
 
185
+ ctx.restore();
186
+ },
187
+ update() {
188
+ // Boundary checking
189
+ if (this.y < 0) this.y = 0;
190
+ if (this.y > canvas.height - this.height) this.y = canvas.height - this.height;
191
+ }
192
+ };
193
+
194
+ // Stars for background
195
+ const stars = [];
196
+ class Star {
197
+ constructor() {
198
+ this.x = canvas.width;
199
+ this.y = Math.random() * canvas.height;
200
+ this.size = Math.random() * 3;
201
+ this.speed = speed + Math.random() * 3;
202
+ this.color = `rgba(255, 255, 255, ${Math.random()})`;
203
  }
204
 
205
+ update() {
206
+ this.x -= this.speed;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
207
  }
208
 
209
+ draw() {
210
+ ctx.fillStyle = this.color;
211
+ ctx.beginPath();
212
+ ctx.arc(this.x, this.y, this.size, 0, Math.PI * 2);
213
+ ctx.fill();
214
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
215
 
216
+ isOffScreen() {
217
+ return this.x + this.size < 0;
218
+ }
219
+ }
220
+
221
+ // Planets for background
222
+ const planets = [];
223
+ class Planet {
224
+ constructor() {
225
+ this.x = canvas.width;
226
+ this.y = Math.random() * canvas.height;
227
+ this.size = 50 + Math.random() * 100;
228
+ this.speed = speed * 0.5;
229
+ this.color = `hsl(${Math.random() * 360}, 70%, 50%)`;
230
+ this.hasRing = Math.random() > 0.7;
 
 
 
231
  }
232
 
233
+ update() {
234
+ this.x -= this.speed;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
235
  }
236
 
237
+ draw() {
238
+ // Planet
239
+ ctx.fillStyle = this.color;
240
+ ctx.beginPath();
241
+ ctx.arc(this.x, this.y, this.size, 0, Math.PI * 2);
242
+ ctx.fill();
243
+
244
+ // Ring
245
+ if (this.hasRing) {
246
+ ctx.strokeStyle = `hsla(${Math.random() * 360}, 80%, 60%, 0.7)`;
247
+ ctx.lineWidth = 5;
248
+ ctx.beginPath();
249
+ ctx.ellipse(this.x, this.y, this.size * 1.5, this.size * 0.3, 0, 0, Math.PI * 2);
250
+ ctx.stroke();
 
 
 
 
 
251
  }
252
  }
253
 
254
+ isOffScreen() {
255
+ return this.x + this.size < 0;
256
+ }
257
+ }
258
+
259
+ // Obstacles
260
+ const obstacles = [];
261
+ class Obstacle {
262
+ constructor() {
263
+ this.width = 40 + Math.random() * 60;
264
+ this.height = 40 + Math.random() * 100;
265
+ this.x = canvas.width;
266
+ this.y = Math.random() * (canvas.height - this.height);
267
+ this.speed = speed;
268
+ this.color = `hsl(${Math.random() * 60 + 20}, 80%, 50%)`;
269
+ this.type = Math.random() > 0.5 ? 'rectangle' : 'triangle';
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
270
  }
271
 
272
+ update() {
273
+ this.x -= this.speed;
274
+ }
275
+
276
+ draw() {
277
+ ctx.fillStyle = this.color;
 
 
278
 
279
+ if (this.type === 'rectangle') {
280
+ ctx.fillRect(this.x, this.y, this.width, this.height);
 
 
 
281
  } else {
282
+ ctx.beginPath();
283
+ ctx.moveTo(this.x, this.y);
284
+ ctx.lineTo(this.x + this.width, this.y + this.height/2);
285
+ ctx.lineTo(this.x, this.y + this.height);
286
+ ctx.closePath();
287
+ ctx.fill();
 
288
  }
289
  }
290
 
291
+ isOffScreen() {
292
+ return this.x + this.width < 0;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
293
  }
294
 
295
+ collidesWith(player) {
296
+ return player.x < this.x + this.width &&
297
+ player.x + player.width > this.x &&
298
+ player.y < this.y + this.height &&
299
+ player.y + player.height > this.y;
300
+ }
301
+ }
302
+
303
+ // Power-ups
304
+ const powerups = [];
305
+ class PowerUp {
306
+ constructor() {
307
+ this.x = canvas.width;
308
+ this.y = Math.random() * canvas.height;
309
+ this.radius = 15;
310
+ this.speed = speed;
311
+ this.type = Math.random() > 0.5 ? 'fuel' : 'shield';
312
+ }
313
+
314
+ update() {
315
+ this.x -= this.speed;
316
+ }
317
+
318
+ draw() {
319
+ ctx.save();
320
+
321
+ if (this.type === 'fuel') {
322
+ ctx.fillStyle = '#00d2ff';
323
+ ctx.beginPath();
324
+ ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2);
325
+ ctx.fill();
326
 
327
+ // Draw fuel symbol
328
+ ctx.fillStyle = '#000';
329
+ ctx.font = 'bold 20px Arial';
330
+ ctx.textAlign = 'center';
331
+ ctx.textBaseline = 'middle';
332
+ ctx.fillText('F', this.x, this.y);
333
+ } else {
334
+ // Shield
335
+ ctx.fillStyle = '#3a7bd5';
336
+ ctx.beginPath();
337
+ ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2);
338
+ ctx.fill();
 
 
 
 
 
 
 
 
 
 
 
339
 
340
+ // Draw shield symbol
341
+ ctx.strokeStyle = '#000';
342
+ ctx.lineWidth = 2;
343
+ ctx.beginPath();
344
+ ctx.arc(this.x, this.y, this.radius - 5, -Math.PI/4, Math.PI/4);
345
+ ctx.stroke();
346
+ ctx.beginPath();
347
+ ctx.arc(this.x, this.y, this.radius - 8, -Math.PI/4, Math.PI/4);
348
+ ctx.stroke();
349
  }
350
 
351
+ ctx.restore();
352
  }
353
 
354
+ isOffScreen() {
355
+ return this.x + this.radius < 0;
356
+ }
357
+
358
+ collidesWith(player) {
359
+ const dx = this.x - (player.x + player.width/2);
360
+ const dy = this.y - (player.y + player.height/2);
361
+ const distance = Math.sqrt(dx * dx + dy * dy);
362
+ return distance < this.radius + Math.max(player.width, player.height)/2;
363
+ }
364
+ }
365
+
366
+ // Input handling
367
+ const keys = {
368
+ ArrowUp: false,
369
+ ArrowDown: false,
370
+ ArrowLeft: false,
371
+ ArrowRight: false,
372
+ w: false,
373
+ a: false,
374
+ s: false,
375
+ d: false,
376
+ ' ': false
377
+ };
378
+
379
+ window.addEventListener('keydown', (e) => {
380
+ if (keys.hasOwnProperty(e.key)) {
381
+ keys[e.key] = true;
382
+ }
383
+ });
384
+
385
+ window.addEventListener('keyup', (e) => {
386
+ if (keys.hasOwnProperty(e.key)) {
387
+ keys[e.key] = false;
388
+ }
389
+ });
390
+
391
+ // Game functions
392
+ function startGame() {
393
+ gameRunning = true;
394
+ score = 0;
395
+ distance = 0;
396
+ speed = 3;
397
+ gameSpeed = 3;
398
+ boostFuel = 100;
399
+ currentBackground = 0;
400
+ backgroundOffset = 0;
401
+
402
+ obstacles.length = 0;
403
+ stars.length = 0;
404
+ planets.length = 0;
405
+ powerups.length = 0;
406
+
407
+ player.x = canvas.width / 4;
408
+ player.y = canvas.height / 2;
409
+ player.isBoosting = false;
410
+
411
+ startScreen.style.display = 'none';
412
+ gameOverScreen.style.display = 'none';
413
+
414
+ animationFrameId = requestAnimationFrame(gameLoop);
415
+ }
416
+
417
+ function endGame() {
418
+ gameRunning = false;
419
+ finalScoreElement.textContent = score;
420
+ finalDistanceElement.textContent = distance.toFixed(1);
421
+ gameOverScreen.style.display = 'flex';
422
+ cancelAnimationFrame(animationFrameId);
423
+ }
424
+
425
+ function handleInput() {
426
+ player.isBoosting = false;
427
+
428
+ // Vertical movement
429
+ if ((keys.ArrowUp || keys.w) && !(keys.ArrowDown || keys.s)) {
430
+ player.y -= player.speed;
431
+ } else if ((keys.ArrowDown || keys.s) && !(keys.ArrowUp || keys.w)) {
432
+ player.y += player.speed;
433
+ }
434
+
435
+ // Horizontal movement
436
+ if ((keys.ArrowLeft || keys.a) && !(keys.ArrowRight || keys.d)) {
437
+ player.x -= player.speed;
438
+ } else if ((keys.ArrowRight || keys.d) && !(keys.ArrowLeft || keys.a)) {
439
+ player.x += player.speed;
440
+ }
441
+
442
+ // Boost
443
+ if ((keys[' ']) && boostFuel > 0) {
444
+ player.isBoosting = true;
445
+ boostFuel -= 0.5;
446
+ gameSpeed = speed * 2;
447
+ } else {
448
+ gameSpeed = speed;
449
+ }
450
+
451
+ // Recharge boost when not in use
452
+ if (!keys[' '] && boostFuel < 100) {
453
+ boostFuel += 0.1;
454
+ }
455
+ }
456
+
457
+ function spawnObjects() {
458
+ // Spawn stars
459
+ starSpawnTimer++;
460
+ if (starSpawnTimer > 5) {
461
+ stars.push(new Star());
462
+ starSpawnTimer = 0;
463
+ }
464
+
465
+ // Spawn obstacles
466
+ obstacleSpawnTimer++;
467
+ if (obstacleSpawnTimer > 60 - Math.min(50, distance / 10)) {
468
+ obstacles.push(new Obstacle());
469
+ obstacleSpawnTimer = 0;
470
+
471
+ // Occasionally spawn power-up after obstacle
472
+ if (Math.random() > 0.7) {
473
+ powerups.push(new PowerUp());
474
  }
475
+ }
476
+
477
+ // Spawn planets
478
+ planetSpawnTimer++;
479
+ if (planetSpawnTimer > 300) {
480
+ planets.push(new Planet());
481
+ planetSpawnTimer = 0;
482
+ }
483
+ }
484
+
485
+ function updateObjects() {
486
+ // Update stars
487
+ for (let i = stars.length - 1; i >= 0; i--) {
488
+ stars[i].update();
489
+ if (stars[i].isOffScreen()) {
490
+ stars.splice(i, 1);
491
  }
492
+ }
493
+
494
+ // Update obstacles
495
+ for (let i = obstacles.length - 1; i >= 0; i--) {
496
+ obstacles[i].speed = gameSpeed;
497
+ obstacles[i].update();
498
+
499
+ if (obstacles[i].isOffScreen()) {
500
+ obstacles.splice(i, 1);
501
+ score += 10;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
502
  }
503
 
504
+ // Check collision
505
+ if (obstacles[i].collidesWith(player)) {
506
+ endGame();
507
+ return;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
508
  }
509
  }
510
 
511
+ // Update planets
512
+ for (let i = planets.length - 1; i >= 0; i--) {
513
+ planets[i].speed = gameSpeed * 0.5;
514
+ planets[i].update();
515
+ if (planets[i].isOffScreen()) {
516
+ planets.splice(i, 1);
 
 
 
 
 
 
 
 
517
  }
518
+ }
519
+
520
+ // Update power-ups
521
+ for (let i = powerups.length - 1; i >= 0; i--) {
522
+ powerups[i].speed = gameSpeed;
523
+ powerups[i].update();
524
 
525
+ if (powerups[i].isOffScreen()) {
526
+ powerups.splice(i, 1);
 
 
 
527
  }
528
 
529
+ // Check collision
530
+ if (powerups[i].collidesWith(player)) {
531
+ if (powerups[i].type === 'fuel') {
532
+ boostFuel = Math.min(100, boostFuel + 30);
533
+ } else {
534
+ // Shield - temporary invincibility
535
+ // For simplicity, we'll just add score
536
+ score += 50;
537
+ }
538
+ powerups.splice(i, 1);
 
 
 
 
 
 
 
539
  }
540
+ }
541
+ }
542
+
543
+ function drawBackground() {
544
+ // Gradient background based on current zone
545
+ const bgColor = backgroundColors[currentBackground % backgroundColors.length];
546
+ const gradient = ctx.createLinearGradient(0, 0, 0, canvas.height);
547
+ gradient.addColorStop(0, bgColor.top);
548
+ gradient.addColorStop(1, bgColor.bottom);
549
+ ctx.fillStyle = gradient;
550
+ ctx.fillRect(0, 0, canvas.width, canvas.height);
551
+
552
+ // Draw distant stars (parallax effect)
553
+ ctx.fillStyle = 'rgba(255, 255, 255, 0.8)';
554
+ for (let i = 0; i < 100; i++) {
555
+ const x = (i * 200 + backgroundOffset * 0.2) % canvas.width;
556
+ const y = (i * 150) % canvas.height;
557
+ const size = 1 + (i % 3);
558
+ ctx.beginPath();
559
+ ctx.arc(x, y, size, 0, Math.PI * 2);
560
+ ctx.fill();
561
+ }
562
+ }
563
+
564
+ function drawUI() {
565
+ // Boost fuel meter
566
+ ctx.fillStyle = 'rgba(0, 0, 0, 0.5)';
567
+ ctx.fillRect(20, canvas.height - 40, 200, 20);
568
+
569
+ ctx.fillStyle = '#00d2ff';
570
+ ctx.fillRect(20, canvas.height - 40, 200 * (boostFuel / 100), 20);
571
+
572
+ ctx.strokeStyle = 'white';
573
+ ctx.lineWidth = 2;
574
+ ctx.strokeRect(20, canvas.height - 40, 200, 20);
575
+
576
+ ctx.fillStyle = 'white';
577
+ ctx.font = '14px Arial';
578
+ ctx.fillText('BOOST', 25, canvas.height - 25);
579
+ }
580
+
581
+ function updateGameState() {
582
+ // Increase distance and speed over time
583
+ distance += gameSpeed * 0.01;
584
+ speed = 3 + Math.floor(distance / 20) * 0.5;
585
+
586
+ // Change background zone every 50 distance units
587
+ if (distance > (currentBackground + 1) * 50) {
588
+ currentBackground++;
589
+ }
590
+
591
+ // Update UI elements
592
+ scoreElement.textContent = score;
593
+ distanceElement.textContent = distance.toFixed(1);
594
+ speedElement.textContent = gameSpeed.toFixed(1);
595
+
596
+ // Move background for parallax effect
597
+ backgroundOffset += gameSpeed * 0.1;
598
+ }
599
+
600
+ function gameLoop() {
601
+ if (!gameRunning) return;
602
+
603
+ // Clear canvas
604
+ ctx.clearRect(0, 0, canvas.width, canvas.height);
605
+
606
+ // Draw background
607
+ drawBackground();
608
+
609
+ // Handle input
610
+ handleInput();
611
+
612
+ // Spawn objects
613
+ spawnObjects();
614
+
615
+ // Update objects
616
+ updateObjects();
617
+ if (!gameRunning) return; // Check again in case collision occurred
618
+
619
+ player.update();
620
+
621
+ // Draw objects
622
+ for (const star of stars) star.draw();
623
+ for (const planet of planets) planet.draw();
624
+ for (const obstacle of obstacles) obstacle.draw();
625
+ for (const powerup of powerups) powerup.draw();
626
+ player.draw();
627
+
628
+ // Draw UI
629
+ drawUI();
630
+
631
+ // Update game state
632
+ updateGameState();
633
+
634
+ // Next frame
635
+ animationFrameId = requestAnimationFrame(gameLoop);
636
+ }
637
+
638
+ // Event listeners for buttons
639
+ startBtn.addEventListener('click', startGame);
640
+ restartBtn.addEventListener('click', startGame);
641
+
642
+ // Handle window resize
643
+ window.addEventListener('resize', () => {
644
+ canvas.width = window.innerWidth;
645
+ canvas.height = window.innerHeight;
646
+
647
+ // Keep player in bounds if screen gets smaller
648
+ if (player.y > canvas.height - player.height) {
649
+ player.y = canvas.height - player.height;
650
+ }
651
  });
652
+
653
+ // Initial setup
654
+ canvas.width = window.innerWidth;
655
+ canvas.height = window.innerHeight;
656
  </script>
657
  <p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-deepsite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >DeepSite</a> - 🧬 <a href="https://enzostvs-deepsite.hf.space?remix=JohnPork04/neural-canvas" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body>
658
  </html>