Upload index.html
Browse files- index.html +26 -9
index.html
CHANGED
|
@@ -1489,8 +1489,8 @@ function stalkCurveX(w, f) {
|
|
| 1489 |
// rigid sprite rotation. Far stalks get a soft low-alpha halo pass to keep their
|
| 1490 |
// "far away" look without any runtime blur filters (no slowdown).
|
| 1491 |
function drawBackSeaweeds(t) {
|
| 1492 |
-
|
| 1493 |
-
|
| 1494 |
for (const w of backSeaweeds) {
|
| 1495 |
const baseY = sandAt(w.x) + 10;
|
| 1496 |
const n = w.segs;
|
|
@@ -1503,8 +1503,9 @@ function drawBackSeaweeds(t) {
|
|
| 1503 |
Math.sin(t * w.waveF2 + w.wavePh2 + f * 3.8) * w.waveA2 * f * f +
|
| 1504 |
Math.sin(t * w.waveF3 + w.wavePh3 + f * 5.4) * w.waveA3 * f;
|
| 1505 |
|
| 1506 |
-
|
| 1507 |
-
|
|
|
|
| 1508 |
ctx.strokeStyle = isHalo ? haloStyle : coreStyle;
|
| 1509 |
ctx.lineCap = 'round';
|
| 1510 |
ctx.lineJoin = 'round';
|
|
@@ -1576,7 +1577,6 @@ function drawBackSeaweeds(t) {
|
|
| 1576 |
}
|
| 1577 |
}
|
| 1578 |
}
|
| 1579 |
-
ctx.restore();
|
| 1580 |
}
|
| 1581 |
|
| 1582 |
// v5: pre-render ultra-far seaweed sprites with heavy blur baked in at build time
|
|
@@ -2009,12 +2009,24 @@ function drawFgGrass(t) {
|
|
| 2009 |
}
|
| 2010 |
}
|
| 2011 |
|
| 2012 |
-
|
| 2013 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2014 |
g.addColorStop(0, "rgba(0,0,0,0)");
|
| 2015 |
g.addColorStop(1, "rgba(0,10,20,0.45)");
|
| 2016 |
-
|
| 2017 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2018 |
}
|
| 2019 |
|
| 2020 |
// --- v8: mild film grain over the whole scene.
|
|
@@ -2047,7 +2059,9 @@ function drawGrain() {
|
|
| 2047 |
grainOx = (Math.random() * GRAIN_TILE) | 0;
|
| 2048 |
grainOy = (Math.random() * GRAIN_TILE) | 0;
|
| 2049 |
lastGrainTime = now;
|
|
|
|
| 2050 |
}
|
|
|
|
| 2051 |
const ox = grainOx, oy = grainOy;
|
| 2052 |
ctx.save();
|
| 2053 |
ctx.globalCompositeOperation = "overlay";
|
|
@@ -2056,7 +2070,9 @@ function drawGrain() {
|
|
| 2056 |
ctx.fillStyle = grainPattern;
|
| 2057 |
ctx.fillRect(0, 0, W + GRAIN_TILE, H + GRAIN_TILE); // cover full screen even with offset
|
| 2058 |
ctx.restore();
|
|
|
|
| 2059 |
}
|
|
|
|
| 2060 |
|
| 2061 |
// Precomputed static layers — the sand and rocks never move, so they are
|
| 2062 |
// rendered once to an offscreen canvas and blitted each frame (v6) instead of
|
|
@@ -2163,6 +2179,7 @@ function doResize() {
|
|
| 2163 |
resize();
|
| 2164 |
buildRaySprites(); // v23: rebuild the pre-blurred beam sprites for the new size
|
| 2165 |
buildFarSeaweedSprites(); // v5: rebuild ultra-far seaweed sprites for new size
|
|
|
|
| 2166 |
buildStaticLayer();
|
| 2167 |
if (!grainPattern) buildGrainTile(); // v8: grain tile is size-independent, build once
|
| 2168 |
}
|
|
|
|
| 1489 |
// rigid sprite rotation. Far stalks get a soft low-alpha halo pass to keep their
|
| 1490 |
// "far away" look without any runtime blur filters (no slowdown).
|
| 1491 |
function drawBackSeaweeds(t) {
|
| 1492 |
+
// v6: no runtime canvas filter — blur() forces a CPU re-rasterize every frame
|
| 1493 |
+
// and was the main FPS cost. Softness now comes from the halo pass below instead.
|
| 1494 |
for (const w of backSeaweeds) {
|
| 1495 |
const baseY = sandAt(w.x) + 10;
|
| 1496 |
const n = w.segs;
|
|
|
|
| 1503 |
Math.sin(t * w.waveF2 + w.wavePh2 + f * 3.8) * w.waveA2 * f * f +
|
| 1504 |
Math.sin(t * w.waveF3 + w.wavePh3 + f * 5.4) * w.waveA3 * f;
|
| 1505 |
|
| 1506 |
+
// v6: near stalks also get a halo pass (replaces the old blur(2px) filter)
|
| 1507 |
+
for (let pass = 0; pass < 2; pass++) {
|
| 1508 |
+
const isHalo = pass === 0; // v6: every stalk gets a halo pass (replaces the old blur filter)
|
| 1509 |
ctx.strokeStyle = isHalo ? haloStyle : coreStyle;
|
| 1510 |
ctx.lineCap = 'round';
|
| 1511 |
ctx.lineJoin = 'round';
|
|
|
|
| 1577 |
}
|
| 1578 |
}
|
| 1579 |
}
|
|
|
|
| 1580 |
}
|
| 1581 |
|
| 1582 |
// v5: pre-render ultra-far seaweed sprites with heavy blur baked in at build time
|
|
|
|
| 2009 |
}
|
| 2010 |
}
|
| 2011 |
|
| 2012 |
+
// v6: vignette is static -> pre-render once per resize, blit each frame
|
| 2013 |
+
// (cheaper than recreating the radial gradient + full-screen fill every frame)
|
| 2014 |
+
let vignetteLayer = null;
|
| 2015 |
+
function buildVignette() {
|
| 2016 |
+
vignetteLayer = document.createElement("canvas");
|
| 2017 |
+
vignetteLayer.width = canvas.width;
|
| 2018 |
+
vignetteLayer.height = canvas.height;
|
| 2019 |
+
const c2 = vignetteLayer.getContext("2d");
|
| 2020 |
+
c2.setTransform(ctx.getTransform());
|
| 2021 |
+
const g = c2.createRadialGradient(W / 2, H * 0.45, Math.min(W, H) * 0.35, W / 2, H * 0.55, Math.max(W, H) * 0.78);
|
| 2022 |
g.addColorStop(0, "rgba(0,0,0,0)");
|
| 2023 |
g.addColorStop(1, "rgba(0,10,20,0.45)");
|
| 2024 |
+
c2.fillStyle = g;
|
| 2025 |
+
c2.fillRect(0, 0, W, H);
|
| 2026 |
+
}
|
| 2027 |
+
function drawVignette() {
|
| 2028 |
+
if (!vignetteLayer) return;
|
| 2029 |
+
ctx.drawImage(vignetteLayer, 0, 0, W, H);
|
| 2030 |
}
|
| 2031 |
|
| 2032 |
// --- v8: mild film grain over the whole scene.
|
|
|
|
| 2059 |
grainOx = (Math.random() * GRAIN_TILE) | 0;
|
| 2060 |
grainOy = (Math.random() * GRAIN_TILE) | 0;
|
| 2061 |
lastGrainTime = now;
|
| 2062 |
+
lastGrainDrawn = false; // offset changed -> must repaint
|
| 2063 |
}
|
| 2064 |
+
if (lastGrainDrawn) return; // v6: skip the full-screen overlay blend when nothing changed
|
| 2065 |
const ox = grainOx, oy = grainOy;
|
| 2066 |
ctx.save();
|
| 2067 |
ctx.globalCompositeOperation = "overlay";
|
|
|
|
| 2070 |
ctx.fillStyle = grainPattern;
|
| 2071 |
ctx.fillRect(0, 0, W + GRAIN_TILE, H + GRAIN_TILE); // cover full screen even with offset
|
| 2072 |
ctx.restore();
|
| 2073 |
+
lastGrainDrawn = true;
|
| 2074 |
}
|
| 2075 |
+
let lastGrainDrawn = false;
|
| 2076 |
|
| 2077 |
// Precomputed static layers — the sand and rocks never move, so they are
|
| 2078 |
// rendered once to an offscreen canvas and blitted each frame (v6) instead of
|
|
|
|
| 2179 |
resize();
|
| 2180 |
buildRaySprites(); // v23: rebuild the pre-blurred beam sprites for the new size
|
| 2181 |
buildFarSeaweedSprites(); // v5: rebuild ultra-far seaweed sprites for new size
|
| 2182 |
+
buildVignette(); // v6: rebuild the static vignette layer
|
| 2183 |
buildStaticLayer();
|
| 2184 |
if (!grainPattern) buildGrainTile(); // v8: grain tile is size-independent, build once
|
| 2185 |
}
|