JavaScript · 23126 bytes Raw Blame History
1 // game.js - Main game loop and state management
2
3 // Game objects
4 let spider;
5 let obstacles = [];
6 let webStrands = [];
7 let flies = [];
8 let foodBoxes = [];
9 let particles = [];
10 let webNodes = [];
11
12 // Game state
13 let isDeployingWeb = false;
14 let currentStrand = null;
15 let spacePressed = false;
16 let isMunching = false;
17
18 // Resources
19 let webSilk = 100;
20 let maxWebSilk = 100;
21 let silkRechargeRate = 0.05;
22 let silkDrainRate = 2;
23
24 // Game phases
25 let gamePhase = 'DUSK';
26 let phaseTimer = 0;
27 let DUSK_DURATION = 1500; // 25 seconds
28 let TRANSITION_DURATION = 180; // 3 seconds
29 let skyColor1, skyColor2, currentSkyColor1, currentSkyColor2;
30 let moonY = 100;
31 let moonOpacity = 0;
32 let fliesCaught = 0;
33 let fliesMunched = 0;
34
35 function setup() {
36 let canvas = createCanvas(window.innerWidth, window.innerHeight);
37 canvas.parent('game-container');
38
39 skyColor1 = color(135, 206, 235);
40 skyColor2 = color(255, 183, 77);
41 currentSkyColor1 = skyColor1;
42 currentSkyColor2 = skyColor2;
43
44 // Create home branch for spider
45 let homeBranchSide = random() < 0.5 ? 'left' : 'right';
46 let homeBranchLength = random(width * 0.33, width * 0.5);
47 let homeBranchY = random(height * 0.7, height * 0.85);
48 let homeBranchThickness = 25;
49
50 // Calculate start and end positions ONCE
51 let branchStartX = homeBranchSide === 'left' ? -20 : width + 20;
52 let branchEndX = homeBranchSide === 'left' ? homeBranchLength : width - homeBranchLength;
53
54 // Generate leaves with FIXED positions (simplified)
55 let leaves = [];
56 for (let i = 0; i < 3; i++) {
57 let t = 0.3 + (0.4 * i / 2);
58 let x = lerp(branchStartX, branchEndX, t);
59 leaves.push({
60 t: t, // Store position as percentage for proper rotation
61 yOffset: -homeBranchThickness - 10,
62 rotation: random(-PI/8, PI/8),
63 width: 16,
64 height: 8
65 });
66 }
67
68 // Generate bark textures with FIXED positions
69 let barkTextures = [];
70 for (let x = Math.min(branchStartX, branchEndX); x < Math.max(branchStartX, branchEndX); x += 16) {
71 barkTextures.push({
72 x: x,
73 yOff: -5 + (x % 10), // Deterministic offset based on position
74 endYOff: -2 + (x % 5)
75 });
76 }
77
78 // Store home branch info for rendering (simplified)
79 window.homeBranch = {
80 side: homeBranchSide,
81 startX: branchStartX,
82 endX: branchEndX,
83 y: homeBranchY,
84 thickness: homeBranchThickness,
85 angle: homeBranchSide === 'left' ? 0.05 : -0.05,
86 leaves: leaves,
87 barkTextures: barkTextures
88 };
89
90 // Place spider at the tip of the branch
91 let spiderStartX = branchEndX; // Place at the end/tip
92
93 // The branch is drawn with a taper - at the tip it's 35% thickness
94 // The branch rendering uses push/translate/rotate, so we need to account for that
95 let branchTopThickness = homeBranchThickness * 0.35;
96
97 // The branch is drawn centered at branch.y after rotation
98 // Since the rotation is small, we can approximate
99 let branchSurfaceY = homeBranchY - branchTopThickness;
100
101 // The branch rotates around (0, homeBranchY), so points further from origin rotate more
102 // For small angles: y_rotated ≈ y + x * sin(angle) ≈ y + x * angle
103 let rotationOffset = spiderStartX * window.homeBranch.angle;
104 branchSurfaceY += rotationOffset;
105
106 // Place spider on top of the visual branch at the tip (8 is spider radius)
107 spider = new Spider(spiderStartX, branchSurfaceY - 8);
108
109 // Add invisible obstacles along the branch for web anchor points
110 let numBranchAnchors = 3;
111 for (let i = 0; i < numBranchAnchors; i++) {
112 let t = (i + 1) / (numBranchAnchors + 1);
113 let x = homeBranchSide === 'left' ?
114 homeBranchLength * t :
115 width - homeBranchLength * t;
116 let y = homeBranchY + sin(t * PI) * 10; // Slight curve
117 obstacles.push(new Obstacle(x, y, 20, 'leaf')); // Use leaf as invisible anchor
118 }
119
120 // Create fewer, bigger, quirkier obstacles
121 let numObstacles = Math.floor((width * height) / 120000); // Much fewer
122 numObstacles = constrain(numObstacles, 8, 15);
123
124 // Create ant balloons (2-3)
125 let numBalloons = Math.floor(random(2, 4));
126 for (let i = 0; i < numBalloons; i++) {
127 let attempts = 0;
128 let placed = false;
129
130 while (!placed && attempts < 30) {
131 let x = random(120, width - 120);
132 let y = random(80, height * 0.5); // Balloons float in upper half
133 let radius = random(40, 55); // Bigger
134
135 let valid = true;
136 // Check distance from other obstacles
137 for (let obstacle of obstacles) {
138 if (dist(x, y, obstacle.x, obstacle.y) < radius + obstacle.radius + 80) {
139 valid = false;
140 break;
141 }
142 }
143
144 // Check distance from home branch
145 if (valid && window.homeBranch) {
146 let branchY = window.homeBranch.y;
147 if (Math.abs(y - branchY) < radius + 50) {
148 valid = false;
149 }
150 }
151
152 if (valid) {
153 obstacles.push(new Obstacle(x, y, radius, 'balloon'));
154 placed = true;
155 }
156 attempts++;
157 }
158 }
159
160 // Create beetles (2-3)
161 let numBeetles = Math.floor(random(2, 4));
162 for (let i = 0; i < numBeetles; i++) {
163 let attempts = 0;
164 let placed = false;
165
166 while (!placed && attempts < 30) {
167 let x = random(100, width - 100);
168 let y = random(height * 0.3, height * 0.7); // Middle areas
169 let radius = random(35, 50);
170
171 let valid = true;
172 for (let obstacle of obstacles) {
173 if (dist(x, y, obstacle.x, obstacle.y) < radius + obstacle.radius + 70) {
174 valid = false;
175 break;
176 }
177 }
178
179 // Check distance from home branch
180 if (valid && window.homeBranch) {
181 let branchY = window.homeBranch.y;
182 if (Math.abs(y - branchY) < radius + 40) {
183 valid = false;
184 }
185 }
186
187 if (valid) {
188 obstacles.push(new Obstacle(x, y, radius, 'beetle'));
189 placed = true;
190 }
191 attempts++;
192 }
193 }
194
195 // Create leaves (3-4) for more stable anchor points
196 let numLeaves = Math.floor(random(3, 5));
197 for (let i = 0; i < numLeaves; i++) {
198 let attempts = 0;
199 let placed = false;
200
201 while (!placed && attempts < 30) {
202 let x = random(80, width - 80);
203 let y = random(100, height - 150);
204 let radius = random(30, 40);
205
206 let valid = true;
207 for (let obstacle of obstacles) {
208 if (dist(x, y, obstacle.x, obstacle.y) < radius + obstacle.radius + 60) {
209 valid = false;
210 break;
211 }
212 }
213
214 if (valid) {
215 obstacles.push(new Obstacle(x, y, radius, 'leaf'));
216 placed = true;
217 }
218 attempts++;
219 }
220 }
221
222 // Add guaranteed edge anchor points (smaller, stable leaves)
223 obstacles.push(new Obstacle(50, height/2, 25, 'leaf'));
224 obstacles.push(new Obstacle(width - 50, height/2, 25, 'leaf'));
225 obstacles.push(new Obstacle(width/2, 60, 25, 'leaf'));
226
227 // Bottom anchors for better coverage
228 if (width > 1000) {
229 obstacles.push(new Obstacle(width/3, height - 130, 25, 'leaf'));
230 obstacles.push(new Obstacle(2*width/3, height - 130, 25, 'leaf'));
231 }
232
233 // Spawn initial food boxes
234 let numBoxes = Math.max(3, Math.floor(width / 400));
235 for (let i = 0; i < numBoxes; i++) {
236 spawnFoodBox();
237 }
238 }
239
240 function draw() {
241 // Update phase timer
242 phaseTimer++;
243
244 // Phase transitions
245 if (gamePhase === 'DUSK' && phaseTimer >= DUSK_DURATION) {
246 gamePhase = 'TRANSITION';
247 phaseTimer = 0;
248 } else if (gamePhase === 'TRANSITION' && phaseTimer >= TRANSITION_DURATION) {
249 gamePhase = 'NIGHT';
250 phaseTimer = 0;
251 for (let i = 0; i < 5; i++) {
252 flies.push(new Fly());
253 }
254 for (let i = 0; i < 3; i++) {
255 spawnFoodBox();
256 }
257 }
258
259 // Update sky colors
260 updateSkyColors();
261
262 // Draw sky gradient
263 drawSkyGradient();
264
265 // Draw moon and stars
266 if (moonOpacity > 0) {
267 drawMoon();
268 }
269
270 // Update and display game objects
271 for (let obstacle of obstacles) {
272 obstacle.update(); // Update movement and animations
273 obstacle.display();
274 }
275
276 for (let box of foodBoxes) {
277 box.display();
278 }
279
280 for (let i = particles.length - 1; i >= 0; i--) {
281 particles[i].update();
282 particles[i].display();
283 if (particles[i].isDead()) {
284 particles.splice(i, 1);
285 }
286 }
287
288 for (let i = webStrands.length - 1; i >= 0; i--) {
289 let strand = webStrands[i];
290 strand.update();
291
292 // Remove broken strands
293 if (strand.broken) {
294 // Create particles for breaking effect
295 if (strand.path && strand.path.length > 0) {
296 let midPoint = strand.path[Math.floor(strand.path.length / 2)];
297 for (let j = 0; j < 5; j++) {
298 let p = new Particle(midPoint.x, midPoint.y);
299 p.color = color(255, 255, 255);
300 p.vel = createVector(random(-2, 2), random(-3, 0));
301 particles.push(p);
302 }
303 }
304 webStrands.splice(i, 1);
305 } else {
306 strand.display();
307 }
308 }
309
310 for (let node of webNodes) {
311 node.update();
312 }
313
314 // Display current strand being created
315 if (currentStrand && isDeployingWeb && spider.isAirborne) {
316 let opacity = map(webSilk, 0, 20, 50, 150);
317 stroke(255, 255, 255, opacity);
318 strokeWeight(1.5);
319
320 if (currentStrand.path && currentStrand.path.length > 0) {
321 noFill();
322 beginShape();
323 curveVertex(currentStrand.path[0].x, currentStrand.path[0].y);
324 for (let point of currentStrand.path) {
325 curveVertex(point.x, point.y);
326 }
327 curveVertex(spider.pos.x, spider.pos.y);
328 curveVertex(spider.pos.x, spider.pos.y);
329 endShape();
330 } else {
331 line(currentStrand.start.x, currentStrand.start.y, spider.pos.x, spider.pos.y);
332 }
333 }
334
335 for (let i = flies.length - 1; i >= 0; i--) {
336 flies[i].update();
337 flies[i].display();
338 }
339
340 spider.update();
341 spider.display();
342
343 // Update resources
344 updateResources();
345
346 // Handle web deployment
347 handleWebDeployment();
348
349 // Update UI
350 updateUI();
351
352 // Spawn entities during night
353 if (gamePhase === 'NIGHT') {
354 if (phaseTimer % 120 === 0 && flies.length < 15) {
355 flies.push(new Fly());
356 }
357 if (phaseTimer % 300 === 0 && foodBoxes.length < 6) {
358 spawnFoodBox();
359 }
360 }
361 }
362
363 function updateSkyColors() {
364 if (gamePhase === 'DUSK') {
365 currentSkyColor1 = lerpColor(color(135, 206, 235), color(255, 140, 90), phaseTimer / DUSK_DURATION);
366 currentSkyColor2 = lerpColor(color(255, 183, 77), color(120, 60, 120), phaseTimer / DUSK_DURATION);
367 } else if (gamePhase === 'TRANSITION') {
368 let t = phaseTimer / TRANSITION_DURATION;
369 currentSkyColor1 = lerpColor(color(255, 140, 90), color(25, 25, 112), t);
370 currentSkyColor2 = lerpColor(color(120, 60, 120), color(0, 0, 40), t);
371 moonOpacity = t * 255;
372 moonY = lerp(100, 60, t);
373 } else if (gamePhase === 'NIGHT') {
374 currentSkyColor1 = color(25, 25, 112);
375 currentSkyColor2 = color(0, 0, 40);
376 moonOpacity = 255;
377 }
378 }
379
380 function drawSkyGradient() {
381 for(let i = 0; i <= height; i++) {
382 let inter = map(i, 0, height, 0, 1);
383 let c = lerpColor(currentSkyColor1, currentSkyColor2, inter);
384 stroke(c);
385 line(0, i, width, i);
386 }
387
388 // Draw home branch
389 if (window.homeBranch) {
390 push();
391 let branch = window.homeBranch;
392
393 // Branch shadow
394 push();
395 translate(0, branch.y + 5);
396 rotate(branch.angle);
397 noStroke();
398 fill(0, 0, 0, 30);
399
400 // Shadow with taper
401 beginShape();
402 vertex(branch.startX, 10);
403 bezierVertex(
404 branch.startX + (branch.endX - branch.startX) * 0.3, 8,
405 branch.startX + (branch.endX - branch.startX) * 0.7, 5,
406 branch.endX, 3
407 );
408 vertex(branch.endX, -3);
409 bezierVertex(
410 branch.startX + (branch.endX - branch.startX) * 0.7, -5,
411 branch.startX + (branch.endX - branch.startX) * 0.3, -8,
412 branch.startX, -10
413 );
414 endShape(CLOSE);
415 pop();
416
417 // Main branch with organic shape and taper
418 push();
419 translate(0, branch.y);
420 rotate(branch.angle);
421
422 noStroke();
423
424 // Base color
425 if (gamePhase === 'NIGHT') {
426 fill(30, 15, 5);
427 } else {
428 fill(92, 51, 23);
429 }
430
431 // Branch body with taper
432 beginShape();
433 vertex(branch.startX, -branch.thickness);
434 bezierVertex(
435 branch.startX + (branch.endX - branch.startX) * 0.3, -branch.thickness * 0.9,
436 branch.startX + (branch.endX - branch.startX) * 0.7, -branch.thickness * 0.6,
437 branch.endX, -branch.thickness * 0.35
438 );
439 vertex(branch.endX, branch.thickness * 0.35);
440 bezierVertex(
441 branch.startX + (branch.endX - branch.startX) * 0.7, branch.thickness * 0.6,
442 branch.startX + (branch.endX - branch.startX) * 0.3, branch.thickness * 0.9,
443 branch.startX, branch.thickness
444 );
445 endShape(CLOSE);
446
447 // Add a fork around 70% down the branch
448 push();
449 let forkX = branch.startX + (branch.endX - branch.startX) * 0.7;
450 let forkY = 0;
451 translate(forkX, forkY);
452 rotate((branch.side === 'right' ? -1 : 1) * PI/6);
453
454 // Fork branch
455 if (gamePhase === 'NIGHT') {
456 fill(35, 18, 6);
457 } else {
458 fill(102, 58, 28);
459 }
460
461 beginShape();
462 vertex(0, -8);
463 bezierVertex(20, -7, 35, -5, 50, -3);
464 vertex(50, 3);
465 bezierVertex(35, 5, 20, 7, 0, 8);
466 endShape(CLOSE);
467 pop();
468
469 // Add lighter highlights
470 if (gamePhase === 'NIGHT') {
471 fill(50, 25, 10, 150);
472 } else {
473 fill(139, 90, 43, 180);
474 }
475
476 // Highlight on top ridge
477 beginShape();
478 vertex(branch.startX + 20, -branch.thickness * 0.8);
479 bezierVertex(
480 branch.startX + (branch.endX - branch.startX) * 0.4, -branch.thickness * 0.7,
481 branch.startX + (branch.endX - branch.startX) * 0.6, -branch.thickness * 0.5,
482 branch.endX - 20, -branch.thickness * 0.25
483 );
484 vertex(branch.endX - 20, -branch.thickness * 0.15);
485 bezierVertex(
486 branch.startX + (branch.endX - branch.startX) * 0.6, -branch.thickness * 0.4,
487 branch.startX + (branch.endX - branch.startX) * 0.4, -branch.thickness * 0.6,
488 branch.startX + 20, -branch.thickness * 0.7
489 );
490 endShape(CLOSE);
491
492 // Bark texture lines
493 stroke(60, 30, 10, 100);
494 strokeWeight(1);
495 for (let texture of branch.barkTextures) {
496 if (texture.x % 20 < 10) {
497 line(texture.x, texture.yOff, texture.x + 3, texture.endYOff);
498 }
499 }
500
501 // Knots
502 noStroke();
503 if (gamePhase === 'NIGHT') {
504 fill(40, 20, 5);
505 } else {
506 fill(80, 40, 15);
507 }
508 ellipse(branch.startX + (branch.endX - branch.startX) * 0.3, -5, 12, 8);
509 ellipse(branch.startX + (branch.endX - branch.startX) * 0.65, 3, 8, 10);
510
511 pop();
512
513 // Small twigs - properly attached to the rotated branch
514 stroke(gamePhase === 'NIGHT' ? color(40, 20, 0) : color(101, 67, 33));
515
516 // Just add a couple simple twigs for visual interest
517 strokeWeight(3);
518 line(branch.startX + (branch.endX - branch.startX) * 0.3, -5,
519 branch.startX + (branch.endX - branch.startX) * 0.3 - 10, -15);
520 line(branch.startX + (branch.endX - branch.startX) * 0.6, 0,
521 branch.startX + (branch.endX - branch.startX) * 0.6 + 8, -12);
522
523 // Add leaves (properly positioned within rotated branch)
524 for (let leaf of branch.leaves) {
525 let leafX = branch.startX + (branch.endX - branch.startX) * leaf.t;
526 push();
527 translate(leafX, leaf.yOffset);
528 rotate(leaf.rotation);
529
530 // Leaf shadow
531 noStroke();
532 fill(0, 0, 0, 20);
533 ellipse(2, 2, leaf.width, leaf.height);
534
535 // Leaf body
536 if (gamePhase === 'NIGHT') {
537 fill(20, 40, 20);
538 } else {
539 fill(34, 139, 34);
540 }
541 ellipse(0, 0, leaf.width, leaf.height);
542
543 // Leaf vein
544 stroke(25, 100, 25, 100);
545 strokeWeight(0.5);
546 line(-leaf.width/2 + 2, 0, leaf.width/2 - 2, 0);
547 pop();
548 }
549
550 pop();
551 }
552 }
553
554 function drawMoon()
555 {
556 push();
557 noStroke();
558
559 // Brighter, farther-reaching moon glow
560 fill(255, 255, 240, moonOpacity);
561 ellipse(width - 100, moonY, 52);
562
563 // Multi-layer radial glow for reach
564 push();
565 blendMode(ADD);
566 fill(255, 255, 230, moonOpacity * 0.55);
567 ellipse(width - 100, moonY, 90);
568 fill(255, 255, 210, moonOpacity * 0.35);
569 ellipse(width - 100, moonY, 140);
570 fill(220, 230, 255, moonOpacity * 0.22);
571 ellipse(width - 100, moonY, 200);
572 pop();
573
574 // Moon craters with better contrast
575 fill(240, 240, 210, moonOpacity * 0.7);
576 ellipse(width - 105, moonY - 5, 8);
577 ellipse(width - 95, moonY + 8, 12);
578 ellipse(width - 110, moonY + 10, 6);
579
580 // Subtle "godrays" emanating from the moon
581 push();
582 blendMode(ADD);
583 let baseA = frameCount * 0.0023; // slow drift
584 let rayCount = 8;
585 for (let i = 0; i < rayCount; i++) {
586 let a = baseA + i * (Math.PI * 2 / rayCount) + (noise(i * 0.2, frameCount * 0.005) - 0.5) * 0.2;
587 let len = 140 + noise(i * 1.7, frameCount * 0.003) * 120; // 140-260px
588 let w0 = 6 + noise(i * 0.9) * 6; // near width
589 let w1 = 18 + noise(i * 0.7) * 16; // far width
590 let cx = width - 100;
591 let cy = moonY;
592 fill(220, 230, 255, (moonOpacity * 0.18));
593 noStroke();
594 beginShape();
595 vertex(cx + Math.cos(a + 0.03) * w0, cy + Math.sin(a + 0.03) * w0);
596 vertex(cx + Math.cos(a - 0.03) * w0, cy + Math.sin(a - 0.03) * w0);
597 vertex(cx + Math.cos(a) * len + Math.cos(a + 0.12) * w1, cy + Math.sin(a) * len + Math.sin(a + 0.12) * w1);
598 vertex(cx + Math.cos(a) * len + Math.cos(a - 0.12) * w1, cy + Math.sin(a) * len + Math.sin(a - 0.12) * w1);
599 endShape(CLOSE);
600 }
601 pop();
602
603 pop();
604 }
605
606 function updateResources() {
607 webSilk = min(webSilk + silkRechargeRate, maxWebSilk);
608
609 if (isDeployingWeb && spider.isAirborne && spacePressed && webSilk > 0) {
610 webSilk = max(0, webSilk - silkDrainRate);
611 if (webSilk <= 0) {
612 isDeployingWeb = false;
613 spacePressed = false;
614 if (currentStrand) {
615 webStrands.pop();
616 currentStrand = null;
617 }
618 }
619 }
620
621 if (!spacePressed && isDeployingWeb) {
622 isDeployingWeb = false;
623 }
624 }
625
626 function handleWebDeployment() {
627 if (spacePressed && spider.isAirborne && !isDeployingWeb && webSilk > 10) {
628 isDeployingWeb = true;
629 currentStrand = new WebStrand(spider.lastAnchorPoint.copy(), null);
630 currentStrand.path = [spider.lastAnchorPoint.copy()];
631 webStrands.push(currentStrand);
632 webNodes.push(new WebNode(spider.lastAnchorPoint.x, spider.lastAnchorPoint.y));
633 }
634
635 if (currentStrand && isDeployingWeb && spider.isAirborne) {
636 currentStrand.end = spider.pos.copy();
637 if (frameCount % 2 === 0) {
638 currentStrand.path.push(spider.pos.copy());
639 }
640 }
641 }
642
643 function updateUI() {
644 document.getElementById('strand-count').textContent = webStrands.length;
645 document.getElementById('flies-caught').textContent = fliesCaught;
646 document.getElementById('flies-munched').textContent = fliesMunched;
647 document.getElementById('phase').textContent = gamePhase === 'TRANSITION' ? 'NIGHTFALL' : gamePhase;
648
649 if (gamePhase === 'DUSK') {
650 let timeLeft = Math.ceil((DUSK_DURATION - phaseTimer) / 60);
651 document.getElementById('timer').textContent = `${timeLeft}s to prepare!`;
652 } else if (gamePhase === 'TRANSITION') {
653 document.getElementById('timer').textContent = 'Night approaches...';
654 } else {
655 document.getElementById('timer').textContent = `${flies.length} flies active`;
656 }
657
658 let meterPercent = (webSilk / maxWebSilk) * 100;
659 document.getElementById('web-meter-fill').style.width = meterPercent + '%';
660
661 if (webSilk < 20) {
662 let flash = sin(frameCount * 0.2) * 0.5 + 0.5;
663 document.getElementById('web-meter-fill').style.background =
664 `linear-gradient(90deg, rgb(255, ${100 + flash * 100}, ${100 + flash * 100}), rgb(255, ${150 + flash * 50}, ${150 + flash * 50}))`;
665 } else {
666 document.getElementById('web-meter-fill').style.background =
667 'linear-gradient(90deg, #87CEEB, #E0F6FF)';
668 }
669 }
670
671 // Input handlers
672 function keyPressed() {
673 if (key === ' ') {
674 spacePressed = true;
675 return false;
676 }
677 if (keyCode === SHIFT) {
678 spider.munch();
679 return false;
680 }
681 }
682
683 function keyReleased() {
684 if (key === ' ') {
685 spacePressed = false;
686 isDeployingWeb = false;
687 return false;
688 }
689 }
690
691 function mousePressed() {
692 if (!spider.isAirborne) {
693 spider.jump(mouseX, mouseY);
694 }
695 }
696
697 function mouseReleased() {
698 // No longer needed for web deployment
699 }
700
701 function touchStarted() {
702 if (!spider.isAirborne) {
703 spider.jump(touches[0].x, touches[0].y);
704 }
705 return false;
706 }
707
708 function touchEnded() {
709 return false;
710 }
711
712 function windowResized() {
713 resizeCanvas(window.innerWidth, window.innerHeight);
714 }