feat(shaders): EdgeFade — per-edge alpha fade shader for both backends#99
Open
chiefcll wants to merge 1 commit into
Open
feat(shaders): EdgeFade — per-edge alpha fade shader for both backends#99chiefcll wants to merge 1 commit into
chiefcll wants to merge 1 commit into
Conversation
Adds an EdgeFade shader that multiplies a node's alpha by a linear ramp inward from each edge with a non-zero pixel distance (left/top/right/ bottom). Unlike LinearGradient, which blends a gradient color over the texture's RGB, EdgeFade masks the texture's own alpha — fading an image out to reveal whatever renders behind it, with a single node and no SubTexture splitting or RTT. WebGL: reuses the existing a_nodeCoords varying and system u_dimensions uniform; update() uploads reciprocals so the fragment adds 4 clamps + 4 multiplies with no division or branches. Uniforms are a pure function of resolved props, preserving the shader value-key cache contract. Canvas2D: renders the node's content into a shared grow-only scratch canvas via a new CanvasRenderer.renderNodeContent() hook, erases edges with destination-out gradients (sequential passes multiply, matching the WebGL ramp product), and composites back — keeping the background behind the node intact. Includes a visual regression test over a checkerboard (proving reveal, not darkening) with its certified CI snapshot, and unit tests for prop resolution. Verified on WebGL + Canvas2D in dev and prod (legacy transpile) modes. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Adds an EdgeFade shader: per-edge pixel distances (
left/top/right/bottom, all default 0) that multiply the node's alpha by a linear ramp inward from each edge — fading an image (or color rect) out to reveal whatever renders behind it.Why
The common "fade the edge of a hero image" effect previously required either an overlay scrim (which tints instead of masking, and breaks under parent alpha fades) or splitting the image into two nodes with a
SubTexture+ white-to-transparent corner colors.LinearGradientdoesn't cover this: it blends a gradient color over the texture's RGB and preserves the texture's alpha, so it can't reveal the background. EdgeFade does the alpha mask directly, with one node and no RTT.How
WebGL (
src/core/shaders/webgl/EdgeFade.ts)a_nodeCoordsvarying and the systemu_dimensionsuniform — no new attributes.update()uploads fade reciprocals (1e6sentinel for disabled edges), so the fragment shader is 4clamps + 4 multiplies with no division and no branches.vec4keeps it composable with tint, corner colors, andworldAlpha/parent fades.Canvas2D (
src/core/shaders/canvas/EdgeFade.ts)CanvasRenderer.renderNodeContent(node, ctx)hook (redirects the existing draw path to an arbitrary 2D context), erases each edge with adestination-outlinear gradient, and composites the result back. Sequential destination-out passes multiply — exactly the WebGL ramp product — and the background behind the node stays intact (a destination-out pass on the main canvas would erase it).Reviewer notes
Testing
EdgeFadeTemplate.test.ts); full suite green.examples/tests/shader-edge-fade.tsover a checkerboard background (proves the fade reveals what's behind, not just darkens): right-fade image, four-edge vignette, color rect, no-op identity vs default shader, composition withalpha+ corner colors, fade-larger-than-node. Certified CI snapshot captured via the Docker runner and manually inspected.vite buildlegacy transpile — Chrome 38 path) modes.🤖 Generated with Claude Code