The page can respond correctly to scrolling while the figure still develops a seam. These are different systems. Scroll determines which pose is being visited; the shader determines how neighbouring particles move within and between those poses.
The scroll mapping is direct and reversible. The earlier motion shader, however, contained a discontinuity at the head–neck boundary. Replacing that rule required a spatial correction, not more smoothing of the reader’s scroll input.
Use the page’s real geometry
The homepage measures the Hero, Notes, Builds, and Now sections. Between two consecutive anchors, progress is the current scroll position’s fraction of that interval. Unequal section heights remain unequal; the controller does not manufacture a second animation-sized document.
return index +
(scrollY - anchors[index]) /
(anchors[index + 1] - anchors[index]);The scroll listener is passive. It reads the current position without cancelling the browser’s scroll event or moving the page itself. Reversing direction therefore revisits the same progress values, and a large jump goes straight to the corresponding chapter. The homepage also passes zero endpoint dwell to the renderer.
The figure’s overall scale and translation are eased spatially between chapter frames. That does not introduce a time-based follower for scroll progress. The distinction matters: an eased composition can still stay attached to the reader’s current position.
The old displacement boundary
The particle data assigns each grain an anatomical class. In the earlier shader below, a step function turned the head class into a binary face flag. The neck fell on the other side of that boundary and received the torso movement rules.
float face = 1.0 - step(0.5, aRegion);
float torso = (1.0 - face) * (1.0 - atmosphere);
offset += vec2(
(point.x - 0.75) * 6.0 * torso,
-1.15 * torso - 0.25 * face
) * breath;A head particle received a vertical breathing amplitude of 0.25, while an adjacent neck particle received 1.15 and a torso-only horizontal term. The source pixels could be neighbours, yet the displacement calculation gave them an abrupt change in motion.
Source-data adjacency analysis found 171 neighbouring head–neck pairs with approximately 0.90–1.02 units of breathing displacement discontinuity in the shader’s model CSS-pixel coordinate system. This is a measurement of the displacement calculation, not a measured gap in a browser screenshot.
Two other terms could amplify the difference. Small idle offsets used independent per-particle phases, and pointer gain changed from 4 for the face to 18 for the neck and body. Those were discontinuities in the movement rules, separate from the source image and scroll controller.
The correction is spatial, not temporal
The correction uses a continuous chest-centred displacement field, with smooth protection around the head and hands. Every point follows the same 5.2-second breathing value. The chest rises and expands while the protected head and hand share a vertical lift, so adjacent regions do not receive unrelated idle phases.
The protection collars are C1: their values and first derivatives remain continuous through the boundaries. Pointer response is released smoothly through those same protected regions. Anatomical classes still help match particle identities between poses, but no longer act as abrupt switches for these breathing and pointer gains.
Head and hand bounds are derived once from the frozen particle geometry for each pose, then follow the pose interpolation in the existing master coordinate system. The input images, particle IDs, and source alpha remain unchanged; the correction is in how the existing particles are displaced.
What the checks do—and do not—show
The earlier CPU reference checks replayed the 171 original head–neck neighbour pairs and reduced their peak displacement difference below 0.000054 model CSS pixels in those samples, compared with the original 0.90–1.02 range. The 12 September revision also removed the remaining correlated flow and independent sway after a visible wave was reported. Its tests check that sampled idle offsets all follow one shared breathing phase, alongside protected anatomy, containment and local strain.
The useful debugging order is to separate progress, correspondence, and deformation. First establish where the animation should be. Then establish which particle is moving where. Finally inspect the field that adds motion around that path. Smooth input is only the first of those guarantees.