From 25e657793394ef0a0ea951c884bcb69260d609f5 Mon Sep 17 00:00:00 2001 From: Jake Date: Thu, 24 Sep 2026 23:47:31 -0400 Subject: [PATCH 1/2] Make the pool flow downstream from the fall foot and let the splash foam drift The owner reported that the pool the waterfall empties into read as stagnant. The pool section of the water shader is now a flow field: a line source along the whole foot of the lower curtain, water leaving it downward and fanning outward, blending into a drain toward the foreground-left. Two cross-faded downstream passes carry the photographed foam and reflections; bubbles at the splash drift and glint gently; open water shows faint streaks. Pool pixels may pull texture from the pool or the curtain, never from stones. Falls, masks, still image, lifecycle and uniforms are unchanged. Speeds are art speeds, not physical water. Owner review during the build replaced a first point source (read as a spring in the middle) with the line source, then tuned the centre. Cache v101. Local gate suite green. Before and after pixel-change measurements are in the calibration log. Proposal queued for cold read. Co-Authored-By: Claude Fable 5.1 --- Delta-Atlas-Tracer-Calibration.md | 12 +++ assets/garden-water-v1.js | 92 ++++++++++++++++---- assets/hanging-garden-v1.md | 4 + governance/harnesses/verify-atlas-runtime.js | 2 +- proposals.json | 23 +++++ sw.js | 2 +- 6 files changed, 116 insertions(+), 19 deletions(-) diff --git a/Delta-Atlas-Tracer-Calibration.md b/Delta-Atlas-Tracer-Calibration.md index d3fc6b0..7bb9e10 100644 --- a/Delta-Atlas-Tracer-Calibration.md +++ b/Delta-Atlas-Tracer-Calibration.md @@ -179,3 +179,15 @@ Pin-Check: `index.html` 12 of 12 values traced, `Delta-Atlas-Architecture.html` Browser observation in a local Chromium preview at 1280 x 800 and 375 x 812: the garden still, water motion and deer render over the stage, the hero card sits over the scenery on desktop and below the full landscape on the phone width, the three skill cards lay out in three columns on desktop and one on the phone, and the browser console reported no errors. These are bounded local observations, not a device or accessibility certification. Independent human usability testing remains open. The proposal `rebuild-the-home-around-the-thesis-three-usable` is queued for the owner's cold read; implementation is not acceptance. Adversarial review before commit, same day. Four independent reviewers (gates and ship path, claims and copy, links and runtime wiring, structure and CSS) produced findings, and a skeptic per finding tried to refute each by reproducing it. Twelve findings were confirmed and none refuted; sixteen lower-ranked findings were left unverified and are listed in the session record. Confirmed and fixed: a session planning file that the desktop app had copied into the repository root, naming unpublished probe identifiers, was moved out of the tree before any staging; the home-surface gate's OpenMirror check was scoped to the card and now fails when the receipt claims a law; the garden checks now require live script, link, image and scene markup rather than substring presence; the proven and not-proven checks are bound to their columns and the thesis-before-cards order is checked; the receipts page's proven list dropped bench result language and probe target names to keep unpublished work status-only, and the gate's denylist now catches that language; the printed Pin-Check command now matches the recorded run; the crosswalk receipt is worded as an author report with unpublished notes rather than an accepted state; the garden stylesheet's card rules were retargeted from the retired button cards to the new skill cards, the three-column grid is forced only above 1000 pixels, and the hero bottom margin was retuned for the taller thesis card; the section headings return to sentence case; tables gained a horizontal-scroll wrapper for narrow screens. Also applied from the unverified list: the Bridge Card copies in this repository now say six fields (the original said five while listing six), llms.txt no longer calls every definition fixed, the specification names Ed as the author's AI research partner, the citation release date is 2026-09-24, the Install control declares its button type, and the em dash check also catches numeric entities. Left as is and recorded: the register entry carries the UTC date 2026-09-25; the State-Delta Bridge history document keeps its original em dashes; the specification's remaining strong sentences are the owner's text framed by its limits section; skip links on standalone pages follow the shared return bar, as on the existing pages. All gates were green after the fixes, Pin-Check traced every value on the four checked documents with the recorded command, and the home page was re-inspected at 760, 1000 and 1400 pixel widths with the garden, water and deer rendering and no site resource failing to load. + +## 2026-09-25: Pool flow in the hanging garden (water script v1.1) + +The owner reported that the pool the waterfall empties into read as stagnant while the falls poured into it, and asked for a natural downstream flow with the bubbles near the drop-off moving slightly. The previous pool was a uniform drift of ten image pixels per second with a sub-pixel sideways ripple, so frame to frame it was effectively still. + +The pool section of `assets/garden-water-v1.js` is now a flow field. The splash source is a line along the whole foot of the lower curtain (image x 1140 to 1470 at y 698), not a point: water leaves that line downward, fans out gently from the centre and more firmly past the ends, and blends into a drain direction toward the foreground-left where the pool leaves the frame. The thin upper basin slides toward its spill lips. Two short downstream passes carry the photographed foam and reflections along that field and cross-fade with a triangular weight and a static per-pixel phase offset, the same technique the falls already used, so nothing snaps or pulses in lockstep. Ripples are elongated along the current and finer across it; bright low-saturation pixels are treated as foam and catch a gentle glint near the foot; open water shows faint streaks. Pool pixels may pull texture from the pool or the curtain above them, never from stones or banks. Speeds are image-space art speeds, five pixels per second on open water rising to sixteen at the splash, not physical water. The falls, the masks, the still image, the vertex shader, the uniforms and the motion lifecycle are unchanged. + +Owner review during the build: a first version used a point source at the foot, which read as water rising from a spring in the middle of the pool; it was replaced by the line source. A second pass, after the owner judged the centre slightly off, allowed curtain pixels into the splash samples so the water directly under the fall keeps moving, added the gentle fan under the foot, lowered the peak speed and shortened the drift cycle so foam does not double at the crossfade, and softened the glint. + +Measurement, local Chromium preview, pool region of the water canvas (image x 830 to 1500, y 665 to 955), mean absolute change per channel on a 0 to 255 scale between two draws: live site before, 0.17 between consecutive draws and 2.25 over 0.7 seconds, with 0.1 percent and 5.1 percent of pool pixels changing by more than 8; this build, 3.65 and 3.86, with 11.8 percent and 12.8 percent. The before figure over 0.7 seconds is mostly the fall pixels inside the region. These are pixel-difference readings from one machine, not a measure of realism; the owner's eye is the acceptance test, and the owner judged the second pass ready to ship. + +Cache v101 distributes the script. The local gate suite passed. The proposal `make-the-pool-flow-downstream-from-the-fall-foot` is queued for cold read. diff --git a/assets/garden-water-v1.js b/assets/garden-water-v1.js index aae56e2..62c92f8 100644 --- a/assets/garden-water-v1.js +++ b/assets/garden-water-v1.js @@ -7,6 +7,8 @@ * Optional #home integration suspends the scene while an Atlas tool is open. * The cover transform is derived from that computed image position on resize. * Masks are authored in pixels of hanging-garden-v1.webp (1672 x 941). + * The pool moves along a flow field from the foot of the lower fall toward the + * foreground-left drain (v1.1, 2026-09-25); the falls are unchanged from v1. * data-frame-count counts successful WebGL draw submissions, not proof of visible * motion or a GPU performance measurement. Inspect the actual browser rendering. */ @@ -161,6 +163,62 @@ float upper = ellipse(p, vec2(1310.0, 511.0), vec2(128.0, 14.0)); return max(m, upper); } + // The pool is a flow field, not a uniform drift. Water arrives at the foot + // of the lower fall, spreads outward through the splash, then drains toward + // the foreground-left, where the pool leaves the frame. The thin upper basin + // slides gently toward its spill lips. Speeds are image-space art speeds in + // pixels per second, not measurements of physical water. + vec2 poolField(vec2 p, out float near) { + // The splash is a line along the whole foot of the lower curtain, from + // its left edge to its right edge, not a point in the middle. Water + // leaves that line downward and outward, never back up the fall. + float footY = 698.0; + vec2 foot = vec2(clamp(p.x, 1140.0, 1470.0), footY); + vec2 drain = vec2(860.0, 968.0); + vec2 fromFoot = p - foot; + // Compress the vertical axis so the splash zone is wide and flat. + float d = length(fromFoot * vec2(1.0, 1.35)); + near = 1.0 - smoothstep(20.0, 260.0, d); + // Foam is heavier where the curtain lands hardest; vary it gently along the foot. + near *= 0.82 + 0.36 * noise(vec2(p.x * 0.012, 3.0)); + // Under the curtain the water fans out slowly from the centre line; past the + // ends it turns outward more firmly. Never a single point, never a flat sheet. + vec2 away = normalize(vec2(fromFoot.x * 0.45 + (p.x - 1305.0) * 0.14, max(fromFoot.y, 14.0))); + vec2 toDrain = drain - p; + vec2 down = toDrain / max(length(toDrain), 1.0); + float spread = 1.0 - smoothstep(40.0, 200.0, d); + vec2 blended = mix(down, away, spread); + vec2 dir = blended / max(length(blended), 0.05); + vec2 perp = vec2(-dir.y, dir.x); + // A slow static meander keeps the streaks from lining up like combed hair. + dir = normalize(dir + perp * (noise(p * 0.011 + vec2(21.0, 4.0)) - 0.5) * 0.45); + float upper = ellipse(p, vec2(1310.0, 511.0), vec2(128.0, 14.0)); + dir = normalize(mix(dir, vec2(-0.99, 0.12), upper)); + near = mix(near, 0.30, upper); + float speed = 5.0 + 11.0 * near; + return dir * speed; + } + // One downstream pass over the pool: ripples refract the reflection, + // photographed foam is carried along, bubbles at the splash catch light. + vec3 poolPass(vec2 src, vec2 dir, vec2 perp, float near, vec3 base) { + vec2 along = vec2(dot(src, dir), dot(src, perp)); + // Streaks stretch along the current; ripples are finer across it. + float ripple = noise(along * vec2(0.028, 0.115)) * 2.0 - 1.0; + float fine = noise(along * vec2(0.075, 0.21) + vec2(5.0, 2.0)) * 2.0 - 1.0; + float amp = 0.8 + 3.2 * near; + vec2 shift = (perp * (ripple * 0.85 + fine * 0.25) + dir * fine * 0.30) * amp; + vec3 c = texture2D(u_image, clamp((src + shift) / u_image_size, 0.0, 1.0)).rgb; + // Keep stones and banks still: only pool or curtain pixels are pulled + // downstream, so the splash directly under the fall keeps moving. + c = mix(base, c, max(pool(src), cascades(src))); + float lum = dot(c, vec3(0.2126, 0.7152, 0.0722)); + float sat = max(c.r, max(c.g, c.b)) - min(c.r, min(c.g, c.b)); + float foam = smoothstep(0.58, 0.82, lum) * (1.0 - smoothstep(0.10, 0.30, sat)); + float glint = noise(src * 0.31 + vec2(11.0, 17.0)) * 2.0 - 1.0; + c *= 1.0 + foam * near * glint * 0.10; + c += (1.0 - foam) * (ripple * 0.030 + fine * 0.012) * (0.35 + 0.65 * near) * vec3(0.62, 0.88, 0.90); + return c; + } void main() { // v_uv is bottom-up; HTML object-fit and authored masks are top-down. vec2 uv = u_origin + vec2(v_uv.x, 1.0 - v_uv.y) * u_span; @@ -198,28 +256,28 @@ passB = mix(base, passB, cascades(sourceB)); vec3 falling = mix(passB, passA, weightA); - // Pools drift toward the foreground-left. Two-dimensional texture - // avoids the ambiguous sideways direction of parallel wave stripes. - vec2 poolFlow = p - vec2(-6.0, 10.0) * u_time; - float surface = noise(poolFlow * vec2(0.035, 0.11)) * 2.0 - 1.0; - float detail = noise(poolFlow * vec2(0.061, 0.17) + vec2(7.0, 3.0)) * 2.0 - 1.0; - // A small wash returns sideways beneath the bottom fall. Its pattern - // still advances down the image; it never climbs the falling strands. - float washZone = ellipse(p, vec2(1285.0, 700.0), vec2(160.0, 32.0)); - vec2 washFlow = p - vec2(5.0, 3.0) * u_time; - float wash = noise(washFlow * vec2(0.045, 0.15)) * 2.0 - 1.0; - surface = mix(surface, wash, washZone * 0.65); - detail = mix(detail, wash, washZone * 0.45); - // Distort reflection edges sideways only, keeping their height fixed. - vec2 rippling = vec2(surface * 0.65 + detail * 0.20, 0.0); - vec3 reflection = texture2D(u_image, clamp(uv + rippling / u_image_size, 0.0, 1.0)).rgb; - vec3 moved = mix(reflection, falling, fall / max(fall + pond, 0.001)); + // Pool. Two short downstream passes carry the surface along the flow + // field; each pass resets only when its own weight is zero, so foam and + // reflections drift without snapping. A static phase offset keeps the + // whole pool from pulsing in lockstep. + float near; + vec2 flowVec = poolField(p, near); + vec2 dir = normalize(flowVec); + vec2 perp = vec2(-dir.y, dir.x); + float cycle = 1.6; + float phaseP = fract(u_time / cycle + noise(p * vec2(0.013, 0.019) + vec2(3.0, 9.0))); + float phaseQ = fract(phaseP + 0.5); + float weightP = 1.0 - abs(2.0 * phaseP - 1.0); + vec2 sourceP = p - flowVec * (cycle * phaseP); + vec2 sourceQ = p - flowVec * (cycle * phaseQ); + vec3 pondColor = mix(poolPass(sourceQ, dir, perp, near, base), + poolPass(sourceP, dir, perp, near, base), weightP); + vec3 moved = mix(pondColor, falling, fall / max(fall + pond, 0.001)); // Irregular, elongated variations follow the same downstream field. // Modulate existing color gently; no added white stripe or sine bands. float filament = noise(fallFlow * vec2(0.23, 0.08) + vec2(13.0, 5.0)); moved *= 1.0 + fall * ((filament - 0.5) * 0.045 + (stream - 0.5) * 0.025); - moved += pond * (surface * 0.006 + detail * 0.002) * vec3(0.60, 0.88, 0.87); gl_FragColor = vec4(clamp(moved, 0.0, 1.0), max(fall, pond)); } `; diff --git a/assets/hanging-garden-v1.md b/assets/hanging-garden-v1.md index bc103bf..ecf6b2e 100644 --- a/assets/hanging-garden-v1.md +++ b/assets/hanging-garden-v1.md @@ -5,3 +5,7 @@ Generated with OpenAI image generation on 2026-09-05 for Delta Atlas, following The served `hanging-garden-v1.webp` is 1672 x 941 native pixels, 597,704 bytes. It was converted from the retained generated PNG without resizing. This is not a 4K asset. Its SHA-256 is recorded with the publication receipt. `garden-water-v1.js` adds optional image refraction/highlights over water regions. The still image is independently rendered beneath the canvas. `garden-home-v1.css` keeps foreground content readable and shows the complete landscape above the content on narrow screens. The decoration is not connected to tool results, authority, evidence acceptance or user data. + +## Pool flow, 2026-09-25 (water script v1.1) + +The owner reported that the pool the waterfall empties into read as stagnant. The pool section of `garden-water-v1.js` now moves along a flow field: water arrives at the foot of the lower fall, spreads outward through the splash, then drains toward the foreground-left where the pool leaves the frame; the thin upper basin slides toward its spill lips. Two short downstream passes carry the photographed foam and reflections along that field and cross-fade so nothing snaps. Bubbles near the drop-off drift outward and catch light; open water shows faint streaks along the current. The falls, the masks, the still image and the motion lifecycle (pause, reduced motion, hidden page, tool open, context loss) are unchanged. Speeds are image-space art speeds, not physical water. diff --git a/governance/harnesses/verify-atlas-runtime.js b/governance/harnesses/verify-atlas-runtime.js index 1c476b1..197fc94 100644 --- a/governance/harnesses/verify-atlas-runtime.js +++ b/governance/harnesses/verify-atlas-runtime.js @@ -7,7 +7,7 @@ const fail=m=>{throw new Error(m);}; const contract=JSON.parse(read('governance/contracts/atlas-runtime-contract.v1.json')); if(contract.type!=='delta-atlas-runtime-contract'||contract.version!==1) fail('contract identity'); const sw=read('sw.js'); -if(!sw.includes("const CACHE='aaig-v100'")) fail('cache version'); +if(!sw.includes("const CACHE='aaig-v101'")) fail('cache version'); if(/allSettled/.test(sw)) fail('install must not accept partial cache'); if(!/Promise\.all\(CORE\.map\(u=>c\.add\(u\)\)\)/.test(sw)) fail('install is not fail-closed'); const coreMatch=sw.match(/const CORE=\[([\s\S]*?)\];/); if(!coreMatch) fail('CORE not found'); diff --git a/proposals.json b/proposals.json index 5177d9c..52c94ae 100644 --- a/proposals.json +++ b/proposals.json @@ -822,6 +822,29 @@ "action": "queued" } ] + }, + { + "id": "make-the-pool-flow-downstream-from-the-fall-foot", + "date": "2026-09-25", + "source": { + "kind": "model", + "name": "Owner direction 2026-09-25: the pond read as stagnant; Claude Code shader implementation. Falls, masks and still image unchanged." + }, + "stream": "site-tools", + "type": "tool", + "title": "Make the pool flow downstream from the fall foot and let the splash foam drift", + "status": "cold-read-pending", + "gates": { + "schema": true, + "corpus": "n/a", + "bench": "n/a" + }, + "log": [ + { + "date": "2026-09-25", + "action": "queued" + } + ] } ] } diff --git a/sw.js b/sw.js index 3e79e23..4f45e73 100644 --- a/sw.js +++ b/sw.js @@ -3,7 +3,7 @@ // and does not collect application inputs. // Installation is all-or-nothing: a claimed offline shell must have every // declared core dependency, not a silently partial cache. -const CACHE='aaig-v100'; +const CACHE='aaig-v101'; const CORE=[ 'index.html','manifest.webmanifest','evaluate.html','404.html','terms.enriched.json', 'Agentic-AI-Governance-Chat.html','Agentic-AI-Governance-GroundTruth.html','Delta-Atlas-Start.html','Delta-Atlas-Field.html', From 705b120e8f256f3d79754f5109eefd005d5d238d Mon Sep 17 00:00:00 2001 From: Jake Date: Thu, 24 Sep 2026 23:50:14 -0400 Subject: [PATCH 2/2] Sample the pool ripple noise on a fixed axis and correct the record Adversarial review found that the pool ripple noise was sampled in a basis that rotated from pixel to pixel, which aliased the ripples into grain across the pool centre; an independent port confirmed about four in ten pool pixels sampled above the Nyquist limit. The noise domain now uses one fixed downstream axis while the motion and refraction still follow the local field. The asset record states the trade-off. The calibration entry is corrected: the owner judged the first pass, the splash speed varies fourteen to eighteen, the pixel-difference figures are a session observation with no retained script, the removed drift was about twelve pixels per second, the sampling guard is described exactly, and the upper basin slides leftward. Co-Authored-By: Claude Fable 5.1 --- Delta-Atlas-Tracer-Calibration.md | 8 +++++--- assets/garden-water-v1.js | 15 +++++++++++---- assets/hanging-garden-v1.md | 2 +- 3 files changed, 17 insertions(+), 8 deletions(-) diff --git a/Delta-Atlas-Tracer-Calibration.md b/Delta-Atlas-Tracer-Calibration.md index 7bb9e10..48be7cb 100644 --- a/Delta-Atlas-Tracer-Calibration.md +++ b/Delta-Atlas-Tracer-Calibration.md @@ -182,12 +182,14 @@ Adversarial review before commit, same day. Four independent reviewers (gates an ## 2026-09-25: Pool flow in the hanging garden (water script v1.1) -The owner reported that the pool the waterfall empties into read as stagnant while the falls poured into it, and asked for a natural downstream flow with the bubbles near the drop-off moving slightly. The previous pool was a uniform drift of ten image pixels per second with a sub-pixel sideways ripple, so frame to frame it was effectively still. +The owner reported that the pool the waterfall empties into read as stagnant while the falls poured into it, and asked for a natural downstream flow with the bubbles near the drop-off moving slightly. The previous pool was a uniform drift of about twelve image pixels per second (ten down, six sideways) with a sub-pixel sideways ripple, so frame to frame it was effectively still. -The pool section of `assets/garden-water-v1.js` is now a flow field. The splash source is a line along the whole foot of the lower curtain (image x 1140 to 1470 at y 698), not a point: water leaves that line downward, fans out gently from the centre and more firmly past the ends, and blends into a drain direction toward the foreground-left where the pool leaves the frame. The thin upper basin slides toward its spill lips. Two short downstream passes carry the photographed foam and reflections along that field and cross-fade with a triangular weight and a static per-pixel phase offset, the same technique the falls already used, so nothing snaps or pulses in lockstep. Ripples are elongated along the current and finer across it; bright low-saturation pixels are treated as foam and catch a gentle glint near the foot; open water shows faint streaks. Pool pixels may pull texture from the pool or the curtain above them, never from stones or banks. Speeds are image-space art speeds, five pixels per second on open water rising to sixteen at the splash, not physical water. The falls, the masks, the still image, the vertex shader, the uniforms and the motion lifecycle are unchanged. +The pool section of `assets/garden-water-v1.js` is now a flow field. The splash source is a line along the whole foot of the lower curtain (image x 1140 to 1470 at y 698), not a point: water leaves that line downward, fans out gently from the centre and more firmly past the ends, and blends into a drain direction toward the foreground-left where the pool leaves the frame. The thin upper basin slides slowly leftward. Two short downstream passes carry the photographed foam and reflections along that field and cross-fade with a triangular weight and a static per-pixel phase offset, the same technique the falls already used, so nothing snaps or pulses in lockstep. Ripples are elongated along the current and finer across it; bright low-saturation pixels are treated as foam and catch a gentle glint near the foot; open water shows faint streaks. Pool pixels pull texture only where the pool or curtain masks hold at the source point; the refraction shift applied after that guard can still reach a few pixels past a mask edge at the splash. Speeds are image-space art speeds, five pixels per second on open water rising to roughly fourteen to eighteen at the splash, varying along the foot with a static noise, not physical water. Ripple noise is sampled on one fixed downstream axis for the whole pool rather than on the local flow direction, because a per-pixel rotating domain aliased into grain where the field bends. The falls, the masks, the still image, the vertex shader, the uniforms and the motion lifecycle are unchanged. Owner review during the build: a first version used a point source at the foot, which read as water rising from a spring in the middle of the pool; it was replaced by the line source. A second pass, after the owner judged the centre slightly off, allowed curtain pixels into the splash samples so the water directly under the fall keeps moving, added the gentle fan under the foot, lowered the peak speed and shortened the drift cycle so foam does not double at the crossfade, and softened the glint. -Measurement, local Chromium preview, pool region of the water canvas (image x 830 to 1500, y 665 to 955), mean absolute change per channel on a 0 to 255 scale between two draws: live site before, 0.17 between consecutive draws and 2.25 over 0.7 seconds, with 0.1 percent and 5.1 percent of pool pixels changing by more than 8; this build, 3.65 and 3.86, with 11.8 percent and 12.8 percent. The before figure over 0.7 seconds is mostly the fall pixels inside the region. These are pixel-difference readings from one machine, not a measure of realism; the owner's eye is the acceptance test, and the owner judged the second pass ready to ship. +Measurement, local Chromium preview, pool region of the water canvas (image x 830 to 1500, y 665 to 955), mean absolute change per channel on a 0 to 255 scale between two draws: live site before, 0.17 between consecutive draws and 2.25 over 0.7 seconds, with 0.1 percent and 5.1 percent of pool pixels changing by more than 8; this build, 3.65 and 3.86, with 11.8 percent and 12.8 percent. The before figure over 0.7 seconds is mostly the fall pixels inside the region. The sampled box was clamped to the bottom of the image. The measurement snippet was run in the browser during the session and is not retained in this repository, so these figures are a session observation and cannot be rerun from the tree. They are pixel-difference readings from one machine, not a measure of realism. The owner's eye is the acceptance test: the owner judged the first pass 95 percent there with the centre slightly off and asked for a fine tune and a live ship; the second pass and the aliasing fix ship on that instruction without a further owner look before publication. Cache v101 distributes the script. The local gate suite passed. The proposal `make-the-pool-flow-downstream-from-the-fall-foot` is queued for cold read. + +Adversarial review before merge, same day: two reviewers (shader correctness, ship path and copy) and one skeptic per finding. Four findings confirmed, none refuted. The shader finding was a real defect: the ripple noise was sampled in a basis that rotated from pixel to pixel, so across the pool centre about four in ten pool pixels sampled the ripple noise above the Nyquist limit and read as grain rather than streaks; the noise domain now uses one fixed downstream axis, confirmed by an independent double-precision port. The copy findings corrected this entry: the owner judged the first pass, not the second; the splash speed varies from about fourteen to eighteen, not sixteen; the pixel-difference figures are a session observation with no retained script; and the removed drift was about twelve pixels per second. Two lower-ranked findings were also applied: the sampling guard wording and the upper basin direction. After the aliasing fix, the same browser measurement gave 3.95 between consecutive draws and 4.17 over 0.7 seconds, and the shader still compiled and drew with no console errors. diff --git a/assets/garden-water-v1.js b/assets/garden-water-v1.js index 62c92f8..42a5a46 100644 --- a/assets/garden-water-v1.js +++ b/assets/garden-water-v1.js @@ -166,7 +166,7 @@ // The pool is a flow field, not a uniform drift. Water arrives at the foot // of the lower fall, spreads outward through the splash, then drains toward // the foreground-left, where the pool leaves the frame. The thin upper basin - // slides gently toward its spill lips. Speeds are image-space art speeds in + // slides slowly leftward. Speeds are image-space art speeds in // pixels per second, not measurements of physical water. vec2 poolField(vec2 p, out float near) { // The splash is a line along the whole foot of the lower curtain, from @@ -201,15 +201,22 @@ // One downstream pass over the pool: ripples refract the reflection, // photographed foam is carried along, bubbles at the splash catch light. vec3 poolPass(vec2 src, vec2 dir, vec2 perp, float near, vec3 base) { - vec2 along = vec2(dot(src, dir), dot(src, perp)); + // The noise domain uses one fixed downstream axis for the whole pool. + // Projecting onto the local flow direction instead would rotate the + // domain from pixel to pixel and alias the ripples into grain wherever + // the field bends, which is exactly across the pool centre. + vec2 streakDir = vec2(-0.45, 0.89); + vec2 streakPerp = vec2(-streakDir.y, streakDir.x); + vec2 along = vec2(dot(src, streakDir), dot(src, streakPerp)); // Streaks stretch along the current; ripples are finer across it. float ripple = noise(along * vec2(0.028, 0.115)) * 2.0 - 1.0; float fine = noise(along * vec2(0.075, 0.21) + vec2(5.0, 2.0)) * 2.0 - 1.0; float amp = 0.8 + 3.2 * near; vec2 shift = (perp * (ripple * 0.85 + fine * 0.25) + dir * fine * 0.30) * amp; vec3 c = texture2D(u_image, clamp((src + shift) / u_image_size, 0.0, 1.0)).rgb; - // Keep stones and banks still: only pool or curtain pixels are pulled - // downstream, so the splash directly under the fall keeps moving. + // Pull texture only where the pool or curtain masks hold at the source, + // so the splash directly under the fall keeps moving. The refraction + // shift above can still reach a few pixels past a mask edge. c = mix(base, c, max(pool(src), cascades(src))); float lum = dot(c, vec3(0.2126, 0.7152, 0.0722)); float sat = max(c.r, max(c.g, c.b)) - min(c.r, min(c.g, c.b)); diff --git a/assets/hanging-garden-v1.md b/assets/hanging-garden-v1.md index ecf6b2e..d38b0ed 100644 --- a/assets/hanging-garden-v1.md +++ b/assets/hanging-garden-v1.md @@ -8,4 +8,4 @@ The served `hanging-garden-v1.webp` is 1672 x 941 native pixels, 597,704 bytes. ## Pool flow, 2026-09-25 (water script v1.1) -The owner reported that the pool the waterfall empties into read as stagnant. The pool section of `garden-water-v1.js` now moves along a flow field: water arrives at the foot of the lower fall, spreads outward through the splash, then drains toward the foreground-left where the pool leaves the frame; the thin upper basin slides toward its spill lips. Two short downstream passes carry the photographed foam and reflections along that field and cross-fade so nothing snaps. Bubbles near the drop-off drift outward and catch light; open water shows faint streaks along the current. The falls, the masks, the still image and the motion lifecycle (pause, reduced motion, hidden page, tool open, context loss) are unchanged. Speeds are image-space art speeds, not physical water. +The owner reported that the pool the waterfall empties into read as stagnant. The pool section of `garden-water-v1.js` now moves along a flow field: water arrives at the foot of the lower fall, spreads outward through the splash, then drains toward the foreground-left where the pool leaves the frame; the thin upper basin slides slowly leftward. Two short downstream passes carry the photographed foam and reflections along that field and cross-fade so nothing snaps. Bubbles near the drop-off drift outward and catch light; open water shows faint streaks. The streak noise is sampled on one fixed downstream axis for the whole pool rather than on the local flow direction, so streak elongation follows the mean drain direction while the motion itself follows the local field; a per-pixel rotating noise domain was found to alias into grain across the pool centre. The falls, the masks, the still image and the motion lifecycle (pause, reduced motion, hidden page, tool open, context loss) are unchanged. Speeds are image-space art speeds, not physical water.