Upload index.html
Browse files- index.html +53 -39
index.html
CHANGED
|
@@ -22,11 +22,11 @@
|
|
| 22 |
<script>
|
| 23 |
(() => {
|
| 24 |
"use strict";
|
| 25 |
-
// ============ Aquarium
|
| 26 |
-
// Based on
|
| 27 |
-
// plus: a single spawn roll gives each fish one of
|
| 28 |
-
// ~20% tiger stripes (betta/tiger-barb style bars across the body),
|
| 29 |
-
//
|
| 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");
|
|
@@ -60,12 +60,12 @@ class Fish {
|
|
| 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 β
|
| 64 |
-
//
|
| 65 |
-
// scale with the fish
|
| 66 |
-
|
| 67 |
-
|
| 68 |
-
|
| 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++) {
|
|
@@ -79,19 +79,20 @@ class Fish {
|
|
| 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 |
-
|
| 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 |
-
|
| 90 |
-
}
|
| 91 |
-
|
| 92 |
-
//
|
| 93 |
-
|
| 94 |
-
|
|
|
|
| 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++) {
|
|
@@ -104,7 +105,7 @@ class Fish {
|
|
| 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 |
-
|
| 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,
|
|
@@ -117,6 +118,19 @@ class Fish {
|
|
| 117 |
tPh: rand(0, Math.PI * 2),
|
| 118 |
});
|
| 119 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 120 |
} else {
|
| 121 |
this.spots = null;
|
| 122 |
this.stripes = null;
|
|
@@ -407,27 +421,10 @@ class Fish {
|
|
| 407 |
c.fillStyle = g;
|
| 408 |
c.fill(bodyPath);
|
| 409 |
|
| 410 |
-
//
|
| 411 |
-
//
|
|
|
|
| 412 |
// BEFORE the additive sheen so the iridescent shimmer still plays across them.
|
| 413 |
-
if (this.spots) {
|
| 414 |
-
c.save();
|
| 415 |
-
c.clip(bodyPath);
|
| 416 |
-
for (const sp of this.spots) {
|
| 417 |
-
const sx = sp.x * s;
|
| 418 |
-
c.fillStyle = sp.style;
|
| 419 |
-
c.beginPath();
|
| 420 |
-
c.arc(sx, sp.y * s + wy(sx), sp.r * s, 0, Math.PI * 2);
|
| 421 |
-
c.fill();
|
| 422 |
-
}
|
| 423 |
-
c.restore();
|
| 424 |
-
}
|
| 425 |
-
|
| 426 |
-
// v14.1: tiger stripes on ~20% of fish (mutually exclusive with spots). Each bar is
|
| 427 |
-
// a wavy, tapering band β its centerline bends and its width varies down the body,
|
| 428 |
-
// so no stripe reads as a straight line. Sampled along both edges so it still rides
|
| 429 |
-
// the traveling wave (wy); clipped to the outline and drawn BEFORE the additive
|
| 430 |
-
// sheen so the iridescent shimmer still plays across the stripes.
|
| 431 |
if (this.stripes) {
|
| 432 |
c.save();
|
| 433 |
c.clip(bodyPath);
|
|
@@ -460,6 +457,23 @@ class Fish {
|
|
| 460 |
c.restore();
|
| 461 |
}
|
| 462 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 463 |
// v7: efficient iridescence β a sheen whose hue shimmers with the swim phase,
|
| 464 |
// so scales appear to catch the light while moving. One gradient + one fill.
|
| 465 |
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 v15 SPOTTY-3 β alt-fg base + spots / stripes / BOTH (~20/20/10) ==
|
| 26 |
+
// Based on v14 SPOTTY-2 (rolling hills, three tail styles, yellow-green foreground grass),
|
| 27 |
+
// plus: a single spawn roll gives each fish one of four looks β ~20% dark/cream spots,
|
| 28 |
+
// ~20% tiger stripes (betta/tiger-barb style bars across the body), ~10% BOTH (spots
|
| 29 |
+
// over stripes), or plain. 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");
|
|
|
|
| 60 |
this.hue = pick(HUES);
|
| 61 |
this.tailType = pick(TAIL_TYPES); // v11: random tail-fin style for variety
|
| 62 |
|
| 63 |
+
// v13/v14/v15: random body markings β one roll per fish decides the look:
|
| 64 |
+
// ~20% spots, ~20% tiger stripes, ~10% BOTH (spots over stripes), else plain.
|
| 65 |
+
// Sampled in units of `size` so they scale with the fish; stored as pre-built
|
| 66 |
+
// fill styles β zero per-frame string work.
|
| 67 |
+
const genSpots = () => {
|
| 68 |
+
const arr = [];
|
| 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++) {
|
|
|
|
| 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 |
+
arr.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 |
+
return arr;
|
| 90 |
+
};
|
| 91 |
+
const genStripes = () => {
|
| 92 |
+
// v14/v14.1: tiger stripes β vertical bars across the body (betta / tiger-barb
|
| 93 |
+
// style), spread from just behind the head to near the tail base with organic
|
| 94 |
+
// jitter; each bar bends and tapers instead of being a straight line.
|
| 95 |
+
const arr = [];
|
| 96 |
const nStr = 5 + ((Math.random() * 4) | 0); // 5..8 bars
|
| 97 |
const darkBars = Math.random() < 0.72; // mostly classic dark bars, sometimes pale
|
| 98 |
for (let i = 0; i < nStr; i++) {
|
|
|
|
| 105 |
// cream/ivory bars β pale tiger variant
|
| 106 |
style = `hsla(${this.hue + rand(-24, 24)},${rand(45, 70)}%,${rand(80, 93)}%,${rand(0.35, 0.6).toFixed(2)})`;
|
| 107 |
}
|
| 108 |
+
arr.push({
|
| 109 |
x: 0.72 - t * 1.62 + rand(-0.07, 0.07), // +0.72s β -0.90s along the body
|
| 110 |
w: rand(0.08, 0.2), // bar width, in units of s
|
| 111 |
style,
|
|
|
|
| 118 |
tPh: rand(0, Math.PI * 2),
|
| 119 |
});
|
| 120 |
}
|
| 121 |
+
return arr;
|
| 122 |
+
};
|
| 123 |
+
const markRoll = Math.random();
|
| 124 |
+
if (markRoll < 0.2) {
|
| 125 |
+
this.spots = genSpots();
|
| 126 |
+
this.stripes = null;
|
| 127 |
+
} else if (markRoll < 0.4) {
|
| 128 |
+
this.spots = null;
|
| 129 |
+
this.stripes = genStripes();
|
| 130 |
+
} else if (markRoll < 0.5) {
|
| 131 |
+
// v15: the mixed breed β stripes as the base pattern, spots scattered over them
|
| 132 |
+
this.spots = genSpots();
|
| 133 |
+
this.stripes = genStripes();
|
| 134 |
} else {
|
| 135 |
this.spots = null;
|
| 136 |
this.stripes = null;
|
|
|
|
| 421 |
c.fillStyle = g;
|
| 422 |
c.fill(bodyPath);
|
| 423 |
|
| 424 |
+
// v15: stripes first when both are present β bars form the base pattern,
|
| 425 |
+
// spots scatter on top. Each is clipped to the body so nothing spills, and both
|
| 426 |
+
// ride the traveling wave (wy) so they flex with the undulating body, drawn
|
| 427 |
// BEFORE the additive sheen so the iridescent shimmer still plays across them.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 428 |
if (this.stripes) {
|
| 429 |
c.save();
|
| 430 |
c.clip(bodyPath);
|
|
|
|
| 457 |
c.restore();
|
| 458 |
}
|
| 459 |
|
| 460 |
+
// v13: random spots on ~20% of fish (or over the stripes for the 10% mixed) β
|
| 461 |
+
// clipped to the body so they never spill, riding the traveling wave (wy) so they
|
| 462 |
+
// flex with the undulating body, and drawn BEFORE the additive sheen so the
|
| 463 |
+
// iridescent shimmer still plays across them.
|
| 464 |
+
if (this.spots) {
|
| 465 |
+
c.save();
|
| 466 |
+
c.clip(bodyPath);
|
| 467 |
+
for (const sp of this.spots) {
|
| 468 |
+
const sx = sp.x * s;
|
| 469 |
+
c.fillStyle = sp.style;
|
| 470 |
+
c.beginPath();
|
| 471 |
+
c.arc(sx, sp.y * s + wy(sx), sp.r * s, 0, Math.PI * 2);
|
| 472 |
+
c.fill();
|
| 473 |
+
}
|
| 474 |
+
c.restore();
|
| 475 |
+
}
|
| 476 |
+
|
| 477 |
// v7: efficient iridescence β a sheen whose hue shimmers with the swim phase,
|
| 478 |
// so scales appear to catch the light while moving. One gradient + one fill.
|
| 479 |
const shimmer = Math.sin(this.phase * 1.6) * 0.5 + 0.5; // 0..1 as it swims
|