Keep zoomed-in canvas sharp; fix blur edge artifacts#86
Merged
Conversation
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>
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.
Summary
Three rendering fixes that all surface as "everything goes blurry past 100% zoom":
resolution = zoom × dprtopixiTextso glyphs re-rasterize on zoom-in.ctx.scaleinto it so vector ops stay in logical units. Bands'ctx.filterblur and noise'sputImageDatabypassctx.scaleand need explicit physical-pixel handling.ClampingBlurFilterthat clamps sample UVs touInputClamp, setclipToViewport: 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
🤖 Generated with Claude Code