Upload index.html
Browse files- index.html +105 -5
index.html
CHANGED
|
@@ -22,11 +22,13 @@
|
|
| 22 |
<script>
|
| 23 |
(() => {
|
| 24 |
"use strict";
|
| 25 |
-
// ============ Aquarium
|
| 26 |
-
// Based on
|
| 27 |
-
//
|
| 28 |
-
//
|
| 29 |
-
//
|
|
|
|
|
|
|
| 30 |
const canvas = document.getElementById("tank");
|
| 31 |
const ctx = canvas.getContext("2d");
|
| 32 |
let W = 0, H = 0;
|
|
@@ -57,6 +59,61 @@ class Fish {
|
|
| 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)
|
|
@@ -343,6 +400,49 @@ class Fish {
|
|
| 343 |
c.fillStyle = g;
|
| 344 |
c.fill(bodyPath);
|
| 345 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 346 |
// v7: efficient iridescence β a sheen whose hue shimmers with the swim phase,
|
| 347 |
// so scales appear to catch the light while moving. One gradient + one fill.
|
| 348 |
const shimmer = Math.sin(this.phase * 1.6) * 0.5 + 0.5; // 0..1 as it swims
|
|
|
|
| 22 |
<script>
|
| 23 |
(() => {
|
| 24 |
"use strict";
|
| 25 |
+
// ============ Aquarium v14 SPOTTY-2 β alt-fg base + spots OR tiger stripes (~20% ea) ===
|
| 26 |
+
// Based on v13 SPOTTY (rolling hills, three tail styles, yellow-green foreground grass),
|
| 27 |
+
// plus: a single spawn roll gives each fish one of three looks β ~20% dark/cream spots,
|
| 28 |
+
// ~20% tiger stripes (betta/tiger-barb style bars across the body), or plain. The two
|
| 29 |
+
// markings are mutually exclusive (no fish wears both). Stripes ride the traveling body
|
| 30 |
+
// wave and sit under the additive iridescent sheen, so they catch light as each swims.
|
| 31 |
+
// Iridescence + overhead streak unchanged.
|
| 32 |
const canvas = document.getElementById("tank");
|
| 33 |
const ctx = canvas.getContext("2d");
|
| 34 |
let W = 0, H = 0;
|
|
|
|
| 59 |
this.angle = Math.random() < 0.5 ? rand(-0.4, 0.4) : Math.PI + rand(-0.4, 0.4);
|
| 60 |
this.hue = pick(HUES);
|
| 61 |
this.tailType = pick(TAIL_TYPES); // v11: random tail-fin style for variety
|
| 62 |
+
|
| 63 |
+
// v13/v14: random body markings β ~20% spots OR ~20% tiger stripes (mutually
|
| 64 |
+
// exclusive; one roll per fish, never both). Sampled in units of `size` so they
|
| 65 |
+
// scale with the fish, stored as pre-built fill styles β zero per-frame string work.
|
| 66 |
+
const markRoll = Math.random();
|
| 67 |
+
if (markRoll < 0.2) {
|
| 68 |
+
this.spots = [];
|
| 69 |
+
const nSpots = 7 + ((Math.random() * 9) | 0); // 7..15 spots
|
| 70 |
+
const pale = Math.random() < 0.45; // cream/ivory vs dark spotting style
|
| 71 |
+
for (let i = 0; i < nSpots; i++) {
|
| 72 |
+
const th = rand(0, Math.PI * 2);
|
| 73 |
+
const rr = Math.sqrt(Math.random()) * 0.9; // uniform in ellipse, kept off the rim
|
| 74 |
+
let style;
|
| 75 |
+
if (pale) {
|
| 76 |
+
// cream/ivory spots β pearl-gourami / leopard pattern
|
| 77 |
+
style = `hsla(${this.hue + rand(-24, 24)},${rand(45, 70)}%,${rand(82, 94)}%,${rand(0.35, 0.6).toFixed(2)})`;
|
| 78 |
+
} else {
|
| 79 |
+
// dark spots β dace / leopard pattern
|
| 80 |
+
style = `hsla(${this.hue + rand(-18, 18)},${rand(60, 85)}%,${rand(24, 34)}%,${rand(0.45, 0.7).toFixed(2)})`;
|
| 81 |
+
}
|
| 82 |
+
this.spots.push({
|
| 83 |
+
x: Math.cos(th) * rr, // along body axis, in units of s
|
| 84 |
+
y: Math.sin(th) * rr * 0.42, // across body (matches the 0.42 ellipse ratio)
|
| 85 |
+
r: rand(0.05, 0.13), // spot radius, in units of s
|
| 86 |
+
style,
|
| 87 |
+
});
|
| 88 |
+
}
|
| 89 |
+
this.stripes = null;
|
| 90 |
+
} else if (markRoll < 0.4) {
|
| 91 |
+
// v14: tiger stripes β vertical bars across the body (betta / tiger-barb style),
|
| 92 |
+
// spread from just behind the head to near the tail base with organic jitter.
|
| 93 |
+
this.spots = null;
|
| 94 |
+
this.stripes = [];
|
| 95 |
+
const nStr = 5 + ((Math.random() * 4) | 0); // 5..8 bars
|
| 96 |
+
const darkBars = Math.random() < 0.72; // mostly classic dark bars, sometimes pale
|
| 97 |
+
for (let i = 0; i < nStr; i++) {
|
| 98 |
+
const t = nStr > 1 ? i / (nStr - 1) : 0; // 0 behind head β 1 near tail base
|
| 99 |
+
let style;
|
| 100 |
+
if (darkBars) {
|
| 101 |
+
// classic dark tiger bars
|
| 102 |
+
style = `hsla(${this.hue + rand(-14, 14)},${rand(65, 90)}%,${rand(18, 30)}%,${rand(0.5, 0.75).toFixed(2)})`;
|
| 103 |
+
} else {
|
| 104 |
+
// cream/ivory bars β pale tiger variant
|
| 105 |
+
style = `hsla(${this.hue + rand(-24, 24)},${rand(45, 70)}%,${rand(80, 93)}%,${rand(0.35, 0.6).toFixed(2)})`;
|
| 106 |
+
}
|
| 107 |
+
this.stripes.push({
|
| 108 |
+
x: 0.72 - t * 1.62 + rand(-0.07, 0.07), // +0.72s β -0.90s along the body
|
| 109 |
+
w: rand(0.08, 0.2), // bar width, in units of s
|
| 110 |
+
style,
|
| 111 |
+
});
|
| 112 |
+
}
|
| 113 |
+
} else {
|
| 114 |
+
this.spots = null;
|
| 115 |
+
this.stripes = null;
|
| 116 |
+
}
|
| 117 |
this.phase = rand(0, Math.PI * 2);
|
| 118 |
// v9: after dark, most fish bed down low in the grass β only a small share still
|
| 119 |
// hovers by the seaweed, and each of those keeps to its own stalk (no pile-ups)
|
|
|
|
| 400 |
c.fillStyle = g;
|
| 401 |
c.fill(bodyPath);
|
| 402 |
|
| 403 |
+
// v13: random spots on ~20% of fish β clipped to the body so they never spill,
|
| 404 |
+
// riding the traveling wave (wy) so they flex with the undulating body, and drawn
|
| 405 |
+
// BEFORE the additive sheen so the iridescent shimmer still plays across them.
|
| 406 |
+
if (this.spots) {
|
| 407 |
+
c.save();
|
| 408 |
+
c.clip(bodyPath);
|
| 409 |
+
for (const sp of this.spots) {
|
| 410 |
+
const sx = sp.x * s;
|
| 411 |
+
c.fillStyle = sp.style;
|
| 412 |
+
c.beginPath();
|
| 413 |
+
c.arc(sx, sp.y * s + wy(sx), sp.r * s, 0, Math.PI * 2);
|
| 414 |
+
c.fill();
|
| 415 |
+
}
|
| 416 |
+
c.restore();
|
| 417 |
+
}
|
| 418 |
+
|
| 419 |
+
// v14: tiger stripes on ~20% of fish (mutually exclusive with spots) β vertical bars
|
| 420 |
+
// across the body. Each bar is a thin polygon sampled along its width so it bends
|
| 421 |
+
// with the traveling wave (wy), clipped to the outline, drawn BEFORE the additive
|
| 422 |
+
// sheen so the iridescent shimmer still plays across the stripes.
|
| 423 |
+
if (this.stripes) {
|
| 424 |
+
c.save();
|
| 425 |
+
c.clip(bodyPath);
|
| 426 |
+
for (const st of this.stripes) {
|
| 427 |
+
const sx = st.x * s; // bar center, fish-local x
|
| 428 |
+
const hw = st.w * s / 2; // half-width
|
| 429 |
+
const M = 5; // samples across the bar so it follows wy(x)
|
| 430 |
+
c.fillStyle = st.style;
|
| 431 |
+
c.beginPath();
|
| 432 |
+
for (let j = 0; j <= M; j++) {
|
| 433 |
+
const x = sx - hw + (j / M) * (2 * hw);
|
| 434 |
+
if (j === 0) c.moveTo(x, wy(x) - s * 0.55); else c.lineTo(x, wy(x) - s * 0.55);
|
| 435 |
+
}
|
| 436 |
+
for (let j = M; j >= 0; j--) {
|
| 437 |
+
const x = sx - hw + (j / M) * (2 * hw);
|
| 438 |
+
c.lineTo(x, wy(x) + s * 0.55);
|
| 439 |
+
}
|
| 440 |
+
c.closePath();
|
| 441 |
+
c.fill();
|
| 442 |
+
}
|
| 443 |
+
c.restore();
|
| 444 |
+
}
|
| 445 |
+
|
| 446 |
// v7: efficient iridescence β a sheen whose hue shimmers with the swim phase,
|
| 447 |
// so scales appear to catch the light while moving. One gradient + one fill.
|
| 448 |
const shimmer = Math.sin(this.phase * 1.6) * 0.5 + 0.5; // 0..1 as it swims
|