Repository navigation
fix(background): wrap heropattern scroll on its per-axis period - #248
Merged
LeadcodeDev merged 1 commit intoSep 22, 2026
Merged
Conversation
53 tasks
LeadcodeDev
force-pushed
the
fix/heropattern-scroll-period
branch
2 times, most recently
from
September 22, 2026 08:35
f067906 to
67be435
Compare
tile_spacing returns one scalar that line 830 applies to both axes, and the
Heropattern arm never reads d.height. The function's own doc comment states
the invariant it relies on — "since every tiled pattern is exactly periodic
on spacing, translating by any offset congruent mod spacing produces byte-
identical pixels" — which is false for any non-square pattern. I counted the
table programmatically: 41 of the 87 entries in crates/rustmotion-
core/src/engine/heropatterns.rs have width != height (architect 100x199,
aztec 32x64, bamboo 16x32, bank_note 100x20, death_star 80x105, yyy
60x96...). Concrete case: {"animated-background":{"preset":"heropattern","he
ropattern":{"pattern":"aztec"},"direction":"down","speed":60}}. The shader
tiles vertically on 64px but the offset wraps at 32px, so every 32px of
travel the pattern snaps by half a period — a periodic jolt through the
whole scene. The .max(20.0) clamp breaks it a second way for the 8 patterns
narrower than 20px: bamboo (16 wide) wraps at 20, so even horizontal scroll
jumps 4px per wrap. draw_world_bg_with_parallax reuses the same tile_spacing
for the camera-pan modulo (line 89), so world views inherit it.
Fix: Make tile_spacing return a (f32, f32) period and have the Heropattern
arm emit (d.width * cfg.scale, d.height * cfg.scale); wrap raw_x on the x
period and raw_y on the y period at line 830, and do the same for the camera
modulo at line 89. Drop the .max(20.0) floor or replace it with a multiple-
of-period ceiling (period * (20.0 / period).ceil()) so the clamp preserves
periodicity.
Refs #220
LeadcodeDev
force-pushed
the
fix/heropattern-scroll-period
branch
from
September 22, 2026 08:44
67be435 to
5a7f871
Compare
LeadcodeDev
added a commit
that referenced
this pull request
Sep 22, 2026
tile_spacing returns one scalar that line 830 applies to both axes, and the
Heropattern arm never reads d.height. The function's own doc comment states
the invariant it relies on — "since every tiled pattern is exactly periodic
on spacing, translating by any offset congruent mod spacing produces byte-
identical pixels" — which is false for any non-square pattern. I counted the
table programmatically: 41 of the 87 entries in crates/rustmotion-
core/src/engine/heropatterns.rs have width != height (architect 100x199,
aztec 32x64, bamboo 16x32, bank_note 100x20, death_star 80x105, yyy
60x96...). Concrete case: {"animated-background":{"preset":"heropattern","he
ropattern":{"pattern":"aztec"},"direction":"down","speed":60}}. The shader
tiles vertically on 64px but the offset wraps at 32px, so every 32px of
travel the pattern snaps by half a period — a periodic jolt through the
whole scene. The .max(20.0) clamp breaks it a second way for the 8 patterns
narrower than 20px: bamboo (16 wide) wraps at 20, so even horizontal scroll
jumps 4px per wrap. draw_world_bg_with_parallax reuses the same tile_spacing
for the camera-pan modulo (line 89), so world views inherit it.
Fix: Make tile_spacing return a (f32, f32) period and have the Heropattern
arm emit (d.width * cfg.scale, d.height * cfg.scale); wrap raw_x on the x
period and raw_y on the y period at line 830, and do the same for the camera
modulo at line 89. Drop the .max(20.0) floor or replace it with a multiple-
of-period ceiling (period * (20.0 / period).ceil()) so the clamp preserves
periodicity.
Refs #220
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.
Severity Medium, category correctness. Location:
crates/rustmotion/src/engine/render/background.rs:806Impact
tile_spacingreturns one scalar that line 830 applies to both axes, and the Heropattern arm never readsd.height. The function's own doc comment states the invariant it relies on — "since every tiled pattern is exactly periodic onspacing, translating by any offset congruent modspacingproduces byte-identical pixels" — which is false for any non-square pattern. I counted the table programmatically: 41 of the 87 entries in crates/rustmotion-core/src/engine/heropatterns.rs have width != height (architect 100x199, aztec 32x64, bamboo 16x32, bank_note 100x20, death_star 80x105, yyy 60x96...). Concrete case:{"animated-background":{"preset":"heropattern","heropattern":{"pattern":"aztec"},"direction":"down","speed":60}}. The shader tiles vertically on 64px but the offset wraps at 32px, so every 32px of travel the pattern snaps by half a period — a periodic jolt through the whole scene. The.max(20.0)clamp breaks it a second way for the 8 patterns narrower than 20px:bamboo(16 wide) wraps at 20, so even horizontal scroll jumps 4px per wrap.draw_world_bg_with_parallaxreuses the sametile_spacingfor the camera-pan modulo (line 89), so world views inherit it.Fix
Make
tile_spacingreturn a(f32, f32)period and have the Heropattern arm emit(d.width * cfg.scale, d.height * cfg.scale); wrapraw_xon the x period andraw_yon the y period at line 830, and do the same for the camera modulo at line 89. Drop the.max(20.0)floor or replace it with a multiple-of-period ceiling (period * (20.0 / period).ceil()) so the clamp preserves periodicity.Evidence the audit read
Part of the September 2026 audit remediation chantier. Refs #220 (RM-19).