Skip to content

Keep zoomed-in canvas sharp; fix blur edge artifacts#86

Merged
mucow24 merged 3 commits into
mainfrom
claude/affectionate-lamarr-2d31e9
Apr 29, 2026
Merged

Keep zoomed-in canvas sharp; fix blur edge artifacts#86
mucow24 merged 3 commits into
mainfrom
claude/affectionate-lamarr-2d31e9

Conversation

@mucow24
Copy link
Copy Markdown
Owner

@mucow24 mucow24 commented Apr 29, 2026

Summary

Three rendering fixes that all surface as "everything goes blurry past 100% zoom":

  1. Text rasterizes once at renderer resolution; pass resolution = zoom × dpr to pixiText so glyphs re-rasterize on zoom-in.
  2. Generators rasterize to a Canvas2D bitmap at canvas dimensions; render the buffer at a quantized pixel scale (1×/2×/4×) tied to zoom and ctx.scale into it so vector ops stay in logical units. Bands' ctx.filter blur and noise's putImageData bypass ctx.scale and need explicit physical-pixel handling.
  3. Blur/shadow filters showed three layers of edge artifacts: viewport-clipped FBO (panning a heavy blur near a viewport edge), undersized auto-padding (Gaussian tail clipped at FBO boundary), and Pixi v8 BlurFilter sampling raw UVs into TexturePool's stale po2 padding. Fix: new ClampingBlurFilter that clamps sample UVs to uInputClamp, set clipToViewport: false, bump padding to 6× strength.

Image color-adjustment filters get the same offscreen-FBO resolution treatment as text (capped at 2× to avoid GPU max-texture issues).

Test plan

  • Typecheck and lint clean
  • e2e: 128/130 pass; 2 image-crop failures confirmed flakes (pass in isolation, unrelated to these changes)
  • Visually verify text, generators, and heavily-blurred items at 100%/200%/500%/1000% zoom; pan blurred items near viewport edges; toggle blur radius repeatedly to confirm no hysteretic artifacts

🤖 Generated with Claude Code

mucow24 and others added 3 commits April 29, 2026 12:00
Pixi rasterizes Text once at the renderer resolution; zooming past 100%
magnified the cached texture and produced heavy blur. Tie the Text's
resolution to the current zoom so it re-rasterizes at the displayed size.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Generators rasterize to a Canvas2D bitmap at canvas dimensions; once the
viewport zooms past 100% that bitmap is magnified and the pattern blurs.
Render the buffer at a quantized pixel scale (1×/2×/4×) tied to zoom and
ctx.scale into it so vector ops stay in logical units. Cap at 4× to
bound VRAM.

Bands' ctx.filter blur and noise's putImageData both bypass ctx
transforms, so compensate explicitly: bands multiplies its blur radius
by the current scale, noise samples at physical canvas size. Image
adjustment filters get the same offscreen-FBO resolution treatment as
the blur/drop-shadow path so color-corrected sprites also stay sharp.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Three compounding bugs surface when blur radius or zoom is high:

1. Pixi's Gaussian BlurFilter samples raw UVs without clamping to the
   input frame. TexturePool reuses power-of-two textures across frames,
   so the area between the frame and po2 boundary keeps stale pixels
   from previous use. The blur kernel pulls those bright values in →
   zoom/blur-dependent edge artifacts that vary on text edits as the
   pool returns different textures (the hysteresis was the smoking gun).

2. FilterSystem clips the item's bounds to the viewport rect *before*
   adding padding. Panning a heavily-blurred item near a viewport edge
   crops the FBO on that side; the kernel hits clamp-to-edge there,
   producing a bright line that moves with screen position.

3. Auto-padding is `strength * 2`, but Pixi's optimized 4-pass kernel
   reaches ~5× strength. The Gaussian tail clips at the FBO boundary,
   leaving sharp cutoffs around the blur halo.

Fixes:
- New ClampingBlurFilter wraps Pixi's BlurFilter with shaders that
  clamp every sample to uInputClamp, so reads stay inside the active
  frame regardless of pool reuse.
- Set clipToViewport=false on blur/shadow filters to keep the FBO at
  full (item + padding) regardless of pan position.
- Bump padding to 6× strength (blur) and offset + blur*6 + 32 (shadow)
  so the falloff completes before the frame edge.

Image color-adjustment filter resolution is also capped at 2× to keep
the offscreen FBO within the GPU's max texture size at extreme zoom.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@mucow24 mucow24 merged commit 6d98290 into main Apr 29, 2026
1 check passed
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