Skip to content

fix(shader): correct linear & radial gradient transparency#112

Merged
chiefcll merged 1 commit into
mainfrom
fix/gradient-transparency
Jun 25, 2026
Merged

fix(shader): correct linear & radial gradient transparency#112
chiefcll merged 1 commit into
mainfrom
fix/gradient-transparency

Conversation

@chiefcll

Copy link
Copy Markdown
Contributor

Fixes the linear gradient transparency issues from #111, with the WebGL portability/perf gaps addressed, and extends the fix to the radial gradient.

Problems

  • WebGL linear gradient rendered solid colors as semi-transparent (gradient alpha was never composited into the output and node opacity was ignored).
  • Canvas linear gradient forced transparent stops to solid. The "nearest opaque RGB" workaround read the high byte as alpha, but colors are RGBA (alpha is the low byte), so it overwrote the real alpha.

Changes

WebGL LinearGradient

  • Restore the getGradientColor fallthrough return — a non-void GLSL function falling off the end is undefined behavior and a hard compile error on many embedded GLES2 drivers (lenient only on desktop Chrome).
  • Composite gradient alpha into the output and apply node opacity via u_alpha.
  • Keep the mediump-overflow fix, but precompute the gradient ramp as dist = dot(v_textureCoords, u_grad_a) + u_grad_b on the CPU instead of recomputing cos/sin/projection per fragment (the prior approach regressed fill rate against the TV perf model). Cache-safe — createValueKey already includes node-width/node-height.
  • Drop the custom vertex shader; the Default.vertex fallback is geometrically identical.

Canvas LinearGradient

  • Remove the broken byte-mislabeled workaround; map each stop straight through toColorString.

WebGL RadialGradient (follow-up)

  • Apply the same alpha compositing and actually use the declared u_alpha (node opacity was previously ignored).

Tests

  • Unit tests: canvas color mapping (per-stop alpha preserved) and the WebGL ramp math (endpoints map to 0/1). Both fail against the old code.
  • New shader-linear-gradient-alpha visual test — gradients over a white backdrop covering solid-opaque, partial-alpha, fade-to-transparent, and 50% node opacity.
  • Regenerated affected CI snapshots in the Docker runtime: shader-linear-gradient-1, shader-radial-gradient-1, and the new shader-linear-gradient-alpha-1. Visually verified.

pnpm build clean · 257/257 unit tests pass · prettier/eslint clean.

🤖 Generated with Claude Code

WebGL LinearGradient:
- restore the getGradientColor fallthrough return — a non-void GLSL
  function that falls off the end is a hard compile error on many
  embedded GLES2 drivers (lenient only on desktop Chrome)
- apply node opacity via u_alpha and composite the gradient alpha into
  the output, so solid colors are no longer rendered semi-transparent
- precompute the gradient ramp as dot(texCoords, a) + b on the CPU
  instead of recomputing cos/sin/projection per fragment (fill-rate)

Canvas LinearGradient:
- drop the broken "nearest opaque RGB" workaround. It read the high
  byte as alpha, but colors are RGBA (alpha in the low byte), so it
  overwrote the real alpha and forced transparent stops opaque.

WebGL RadialGradient:
- apply the same alpha compositing and actually use the declared
  u_alpha (node opacity was previously ignored).

Tests:
- unit tests for canvas color mapping and the webgl ramp math
- shader-linear-gradient-alpha visual test + regenerated CI snapshots

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@chiefcll chiefcll merged commit a986ccf into main Jun 25, 2026
1 check passed
@chiefcll chiefcll deleted the fix/gradient-transparency branch June 25, 2026 16:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant