One commited on
Commit
9755d7d
Β·
verified Β·
1 Parent(s): 46f1ea1

Upload index.html

Browse files
Files changed (1) hide show
  1. index.html +92 -12
index.html CHANGED
@@ -22,10 +22,11 @@
22
  <script>
23
  (() => {
24
  "use strict";
25
- // ============ Aquarium v10 ALT β€” hilly terrain (alt) ================================
26
- // Based on v10: same behavior, but the sand bed is generated as rolling hills that
27
- // differ on every refresh. Fish skim over crests, and night-time sleep clusters form
28
- // on the hilly seaweed/grass patches instead of a flat line.
 
29
  const canvas = document.getElementById("tank");
30
  const ctx = canvas.getContext("2d");
31
  let W = 0, H = 0;
@@ -41,7 +42,8 @@ function lerpAngle(a, b, t) {
41
  }
42
 
43
  const HUES = [8, 35, 46, 172, 195, 215, 262, 320];
44
- let fishes = [], bubbles = [], seaweeds = [], motes = [], rays = [], rocks = [], grass = [];
 
45
  let curNight = 0; // v7: shared night factor (dims the top-light + sheen)
46
  let plantPoints = []; // collision points along every stalk/branch, rebuilt each frame
47
  let sandHeights = [];
@@ -54,6 +56,7 @@ class Fish {
54
  this.y = rand(H * 0.15, H * 0.72);
55
  this.angle = Math.random() < 0.5 ? rand(-0.4, 0.4) : Math.PI + rand(-0.4, 0.4);
56
  this.hue = pick(HUES);
 
57
  this.phase = rand(0, Math.PI * 2);
58
  // v9: after dark, most fish bed down low in the grass β€” only a small share still
59
  // hovers by the seaweed, and each of those keeps to its own stalk (no pile-ups)
@@ -286,15 +289,33 @@ class Fish {
286
  // tail fin follows the body wave at its base, amplified (same phase β†’ no fighting)
287
  const sway = Math.sin(-s * waveK + this.phase) * s * 0.34;
288
 
289
- // tail fin (v7): rounded lobes instead of two pointed spikes β€” each tip is swept
290
- // around by a curve whose control point sits just past where the old spike was
 
291
  c.fillStyle = `hsla(${this.hue},75%,52%,0.92)`;
292
  c.beginPath();
293
- c.moveTo(-s * 0.5, 0);
294
- c.quadraticCurveTo(-s * 1.04, -s * 0.36 + sway, -s * 1.22, -s * 0.44 + sway); // upper edge out toward the tip
295
- c.quadraticCurveTo(-s * 1.34, -s * 0.52 + sway, -s * 0.86, sway * 0.5); // rounded upper lobe β†’ notch
296
- c.quadraticCurveTo(-s * 1.34, s * 0.52 + sway, -s * 1.22, s * 0.44 + sway); // notch β†’ rounded lower lobe
297
- c.quadraticCurveTo(-s * 1.04, s * 0.36 + sway, -s * 0.5, 0); // lower edge back to the base
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
298
  c.fill();
299
 
300
  // body β€” undulates while swimming: the ellipse flexes along a traveling wave (v3)
@@ -471,6 +492,8 @@ function buildScene() {
471
  rays = [];
472
  rocks = [];
473
  sandHeights = [];
 
 
474
 
475
  // ALT: rolling hills instead of a flat bed β€” three octaves of random sine waves
476
  // (broad swells + mid undulations + fine ripples), re-rolled on every refresh.
@@ -566,6 +589,30 @@ function buildScene() {
566
  }
567
  }
568
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
569
  const nFish = Math.max(7, Math.floor(W / 130));
570
  for (let i = 0; i < nFish; i++) fishes.push(new Fish());
571
 
@@ -944,6 +991,37 @@ function drawGrass(t) {
944
  }
945
  }
946
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
947
  function drawVignette() {
948
  const g = ctx.createRadialGradient(W / 2, H * 0.45, Math.min(W, H) * 0.35, W / 2, H * 0.55, Math.max(W, H) * 0.78);
949
  g.addColorStop(0, "rgba(0,0,0,0)");
@@ -1064,6 +1142,8 @@ function frame(now) {
1064
  b.draw(ctx);
1065
  }
1066
 
 
 
1067
  // ambient day/night wash over the whole scene
1068
  if (light.washA > 0.005) {
1069
  ctx.fillStyle = `rgba(${light.washRGB[0]},${light.washRGB[1]},${light.washRGB[2]},${light.washA})`;
 
22
  <script>
23
  (() => {
24
  "use strict";
25
+ // ============ Aquarium v12 ALT-FG β€” hilly terrain + foreground grass (50% size) =====
26
+ // Based on v10 ALT (rolling-hills sand bed), plus front-glass foreground grass planted
27
+ // in the low band below the sand line and drawn on top of everything. The fg clumps are
28
+ // 50% smaller than the original fg version: half height, half width, half spread β€”
29
+ // so they read as near-glass flora without swallowing the hilly scene.
30
  const canvas = document.getElementById("tank");
31
  const ctx = canvas.getContext("2d");
32
  let W = 0, H = 0;
 
42
  }
43
 
44
  const HUES = [8, 35, 46, 172, 195, 215, 262, 320];
45
+ const TAIL_TYPES = ['classic', 'fan', 'streamer']; // v11: three tail-fin styles, one per fish
46
+ let fishes = [], bubbles = [], seaweeds = [], motes = [], rays = [], rocks = [], grass = [], fgGrass = [];
47
  let curNight = 0; // v7: shared night factor (dims the top-light + sheen)
48
  let plantPoints = []; // collision points along every stalk/branch, rebuilt each frame
49
  let sandHeights = [];
 
56
  this.y = rand(H * 0.15, H * 0.72);
57
  this.angle = Math.random() < 0.5 ? rand(-0.4, 0.4) : Math.PI + rand(-0.4, 0.4);
58
  this.hue = pick(HUES);
59
+ this.tailType = pick(TAIL_TYPES); // v11: random tail-fin style for variety
60
  this.phase = rand(0, Math.PI * 2);
61
  // v9: after dark, most fish bed down low in the grass β€” only a small share still
62
  // hovers by the seaweed, and each of those keeps to its own stalk (no pile-ups)
 
289
  // tail fin follows the body wave at its base, amplified (same phase β†’ no fighting)
290
  const sway = Math.sin(-s * waveK + this.phase) * s * 0.34;
291
 
292
+ // tail fin (v7 rounded / v11 three styles): each tip is swept around by a curve
293
+ // whose control point sits just past where the old spike was. The style is fixed
294
+ // per fish at spawn so the school has variety in its tails.
295
  c.fillStyle = `hsla(${this.hue},75%,52%,0.92)`;
296
  c.beginPath();
297
+ if (this.tailType === 'fan') {
298
+ // Broad, rounded fan (betta/goldfish-style): wide spread, tips high and far out,
299
+ // with only a shallow dip between the two lobes.
300
+ c.moveTo(-s * 0.5, 0);
301
+ c.quadraticCurveTo(-s * 1.3, -s * 0.28 + sway, -s * 1.42, -s * 0.5 + sway); // up to upper tip
302
+ c.quadraticCurveTo(-s * 1.12, sway * 0.5, -s * 1.42, s * 0.5 + sway); // shallow notch β†’ lower tip
303
+ c.quadraticCurveTo(-s * 1.3, s * 0.28 + sway, -s * 0.5, 0); // back to the base
304
+ } else if (this.tailType === 'streamer') {
305
+ // Long forked streamers (angelfish/fancy-guppy-style): two flowing lobes that
306
+ // reach further back with a deeper notch between them.
307
+ c.moveTo(-s * 0.5, 0);
308
+ c.quadraticCurveTo(-s * 1.35, -s * 0.24 + sway, -s * 1.68, -s * 0.56 + sway); // long upper lobe
309
+ c.quadraticCurveTo(-s * 0.98, sway * 0.35, -s * 1.68, s * 0.56 + sway); // deep fork β†’ lower tip
310
+ c.quadraticCurveTo(-s * 1.35, s * 0.24 + sway, -s * 0.5, 0); // long lower lobe back to base
311
+ } else {
312
+ // classic (v7): rounded lobes with a soft notch β€” the original look
313
+ c.moveTo(-s * 0.5, 0);
314
+ c.quadraticCurveTo(-s * 1.04, -s * 0.36 + sway, -s * 1.22, -s * 0.44 + sway); // upper edge out toward the tip
315
+ c.quadraticCurveTo(-s * 1.34, -s * 0.52 + sway, -s * 0.86, sway * 0.5); // rounded upper lobe β†’ notch
316
+ c.quadraticCurveTo(-s * 1.34, s * 0.52 + sway, -s * 1.22, s * 0.44 + sway); // notch β†’ rounded lower lobe
317
+ c.quadraticCurveTo(-s * 1.04, s * 0.36 + sway, -s * 0.5, 0); // lower edge back to the base
318
+ }
319
  c.fill();
320
 
321
  // body β€” undulates while swimming: the ellipse flexes along a traveling wave (v3)
 
492
  rays = [];
493
  rocks = [];
494
  sandHeights = [];
495
+ grass = []; // v10.1: clear on rebuild so resize/F11 doesn't stack a second row
496
+ fgGrass = []; // v12: same reset for the foreground layer (resize/F11 safety)
497
 
498
  // ALT: rolling hills instead of a flat bed β€” three octaves of random sine waves
499
  // (broad swells + mid undulations + fine ripples), re-rolled on every refresh.
 
589
  }
590
  }
591
 
592
+ // v12: foreground grass β€” planted on the FRONT glass (closest to the viewer), so it is
593
+ // drawn last and foreshortened. It grows in the low band below the sand line, i.e. the
594
+ // zone fish never reach, and sways with the water like the other flora but has no
595
+ // fish-push physics (purely decorative). ALT-FG: all sizes halved vs the original fg.
596
+ const nFgClusters = Math.max(8, Math.floor(W / 120));
597
+ for (let i = 0; i < nFgClusters; i++) {
598
+ const cx = rand(-10, W + 10);
599
+ const clusterBaseY = sandAt(cx) + rand(4, H * 0.05); // rooted just in front of the sand bed
600
+ const baseHue = rand(46, 76); // v12.1: yellowish-green β€” pops against the mid-ground green grass
601
+ const nBlades = 3 + ((Math.random() * 4) | 0); // 3..6 blades per clump
602
+ for (let b = 0; b < nBlades; b++) {
603
+ fgGrass.push({
604
+ x: cx + rand(-7.5, 7.5), // 50%: tighter clumps (was -15..15)
605
+ y: clusterBaseY + rand(-2, 4), // 50%: finer vertical jitter (was -4..8)
606
+ h: rand(H * 0.08, H * 0.18), // 50%: half height (was H*0.16..H*0.36)
607
+ lean: rand(-0.25, 0.25), // base tilt from vertical
608
+ phase: rand(0, Math.PI * 2),
609
+ speed: rand(0.8, 1.6), // slower, heavier sway than the tiny mid-ground grass
610
+ hue: baseHue + rand(-10, 10),
611
+ width: rand(1.75, 3.5) // 50%: half thickness (was 3.5..7)
612
+ });
613
+ }
614
+ }
615
+
616
  const nFish = Math.max(7, Math.floor(W / 130));
617
  for (let i = 0; i < nFish; i++) fishes.push(new Fish());
618
 
 
991
  }
992
  }
993
 
994
+ // v12: foreground grass sways with the water β€” decorative only, no physics.
995
+ // Drawn on top of everything else (it is closest to the viewer). Each blade gets a
996
+ // thin lighter inner stroke over a darker body for a lush, voluminous "closer" look.
997
+ function drawFgGrass(t) {
998
+ ctx.lineCap = "round";
999
+ for (const g of fgGrass) {
1000
+ const amp = 4 + g.h * 0.03; // taller blades swing wider at the tip
1001
+ const sway = Math.sin(t * g.speed + g.phase) * amp;
1002
+ const tipX = g.x + g.lean * g.h + sway;
1003
+ const tipY = g.y - g.h;
1004
+ const cpx = (g.x + tipX) / 2 + sway * 0.5;
1005
+ const cpy = (g.y + tipY) / 2;
1006
+
1007
+ // dark body of the blade (in front)
1008
+ ctx.strokeStyle = `hsla(${g.hue},60%,31%,0.96)`;
1009
+ ctx.lineWidth = g.width;
1010
+ ctx.beginPath();
1011
+ ctx.moveTo(g.x, g.y);
1012
+ ctx.quadraticCurveTo(cpx, cpy, tipX, tipY);
1013
+ ctx.stroke();
1014
+
1015
+ // lighter inner highlight for depth (cheap: one extra thin stroke)
1016
+ ctx.strokeStyle = `hsla(${g.hue + 6},64%,45%,0.5)`;
1017
+ ctx.lineWidth = g.width * 0.45;
1018
+ ctx.beginPath();
1019
+ ctx.moveTo(g.x, g.y);
1020
+ ctx.quadraticCurveTo(cpx, cpy, tipX, tipY);
1021
+ ctx.stroke();
1022
+ }
1023
+ }
1024
+
1025
  function drawVignette() {
1026
  const g = ctx.createRadialGradient(W / 2, H * 0.45, Math.min(W, H) * 0.35, W / 2, H * 0.55, Math.max(W, H) * 0.78);
1027
  g.addColorStop(0, "rgba(0,0,0,0)");
 
1142
  b.draw(ctx);
1143
  }
1144
 
1145
+ drawFgGrass(t); // v12: foreground grass β€” closest to the viewer, drawn on top
1146
+
1147
  // ambient day/night wash over the whole scene
1148
  if (light.washA > 0.005) {
1149
  ctx.fillStyle = `rgba(${light.washRGB[0]},${light.washRGB[1]},${light.washRGB[2]},${light.washA})`;