Movement spills translucent pigment into a living watercolor field: soft pools, wet edges, curling washes and subtle paper grain.
GLSL fragment shader
The effect's own code. The uniforms and helpers above it — uTex, uFeedback, the depth proxy, the frame ring, depthAt(), timeAt() — are the same header every Ether-MOSH shader opens with, and are documented once on the registry rather than reprinted on all 143 pages.
void main(){ vec4 base=texture2D(uTex,vUv); vec2 curl=vec2(sin(vUv.y*23.0+sin(vUv.x*11.0)+uTime*.16),cos(vUv.x*19.0+sin(vUv.y*13.0)-uTime*.12)); vec2 uv=clamp(vUv+curl*.008*uWetness,0.0,1.0); vec4 dye=texture2D(uMotionTex,uv); vec2 texel=vec2(1.0/128.0); float edge=length(vec2(texture2D(uMotionTex,uv+vec2(texel.x,0.0)).a-texture2D(uMotionTex,uv-vec2(texel.x,0.0)).a,texture2D(uMotionTex,uv+vec2(0.0,texel.y)).a-texture2D(uMotionTex,uv-vec2(0.0,texel.y)).a)); vec3 pigment=dye.rgb/max(dye.a,.02); float paper=motionHash(floor(vUv*uResolution*.6)); float wash=smoothstep(.025,.6,dye.a); // Soft concentration contours leave pigment at the edge of each wet pool. float pools=.5+.5*sin(dye.a*38.0+curl.x*.65); float rim=pow(1.0-abs(pools*2.0-1.0),6.0)*smoothstep(.07,.3,dye.a); vec3 artwork=mix(vec3(.92,.91,.88),pigment,clamp(wash*.92+edge*3.0,0.0,1.0)); artwork*=1.0-clamp(edge*2.5+rim*.16*uWetness,0.0,.32); artwork=mix(artwork,artwork*mix(vec3(.82),base.rgb+vec3(.35),.5),.18); artwork*=1.0-uGrain*(paper-.35)*.12; gl_FragColor=vec4(mix(base.rgb,artwork,clamp(uAmount,0.0,1.0)),base.a); }