Skip to content

perf: build a shape mask once per composition, and give Motion its own section - #9

Merged
simien merged 2 commits into
mainfrom
perf/mask-cache-motion-section
Sep 13, 2026
Merged

simien merged 2 commits into
mainfrom
perf/mask-cache-motion-section

Conversation

@simien

@simien simien commented Sep 13, 2026

Copy link
Copy Markdown
Owner

What does this change?

Two things that came out of today's audit follow-up.

The shape mask is built once per composition instead of once per frame. A layer's mask depends only on the shape, its direction, the grid size, and the layer's seed, so nothing in it changes with the animation phase. It was recomputed for every cell on every frame for both layers, and the radial shapes allocated a corner list and took four square roots per cell. On the default canvas a vignette doubled the frame time. The mask is now a cached keep/drop byte array, in the same shape of cache the flow field already uses, and a masked frame costs what an unmasked one does.

Motion gets its own section in the General tab, headed Animation, second after Settings, instead of being the last field under Settings. The heading is Animation rather than Motion so it does not repeat the field's own label directly beneath it; the field is still called Motion everywhere. It is what the site leads with, and it is one of the four controls that drive animation rather than a canvas setting. It sits second rather than first because size, colors, and mask come before how it moves, a still is the default, and the flash warning should not be the first line a new visitor reads. The guide's tab table now says where it lives.

generator.js moves to ?v=12 on the four pages that load it.

Related issue

None.

How was this tested?

  • Output is byte-for-byte unchanged. A Node harness loaded the previous generator.js and this one side by side and hashed both grids from 1,620 generate() calls: twelve mask and direction pairs, three sizes, three texture pairings, five motions, three phases. Zero mismatches. Old links and exported SVGs render exactly as before.
  • Timed in Chrome on the default 1200x630 canvas at block size 2, one animated frame:
Mask Before After
None 103 ms 53 ms
Circle 109 ms 50 ms
Stripes 126 ms 50 ms
Vignette 220 ms 50 ms
Corner vignette 222 ms 51 ms

The before and after columns are on different random compositions, so compare the spread within a column rather than across: before, a vignette cost more than double an unmasked frame; after, every mask costs the same as none.

  • Sidebar checked in the browser: the General tab's headings read Settings, Animation, Auto-randomize, Saved states, with the Motion select and its Speed slider under the new heading.
  • python3 .github/scripts/checks.py main passes, including the generator.js bump.

Checklist

  • No new build step, package manager, framework, or CDN dependency introduced
  • generator.js still has no dependency on the UI, if touched
  • Tested locally in at least one browser

🤖 Generated with Claude Code

…n section

A layer's mask is a pure function of the shape, its direction, the grid
size and the layer's seed; nothing in it moves with the phase. It was
recomputed for every cell on every frame, for both layers, and for the
radial shapes each cell allocated a corner list and took four square
roots. On the default canvas that doubled an animated frame, from 103ms
to 220ms with a vignette. The mask is now built once as a keep/drop byte
per cell and cached the way the field is, and a masked frame costs what
an unmasked one does.

The random stream is read in the same cell order as before, so the
output is unchanged: 1620 generate() calls across twelve mask and
direction pairs, three sizes, three texture pairings, five motions and
three phases hash identically against the previous generator.

Motion moves out from under Settings into its own section, second in
the General tab. It is what the site leads with, so it should be
findable as a heading, and it is one of the four controls that drive
animation rather than a canvas setting. Second rather than first because
size, colors and mask come before how it moves, a still is the default,
and the flash warning should not be the first line a new visitor reads.
The guide's tab table says where it sits.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Sep 13, 2026

Copy link
Copy Markdown

Deploying with  Cloudflare Workers  Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

Status Name Latest Commit Preview URL Updated (UTC)
✅ Deployment successful!
View logs
flield 68fd8e3 Commit Preview URL

Branch Preview URL
Sep 13 2026, 09:40 PM

The heading sat directly over a field labelled Motion. The section is
the topic and the field is the choice, the way Auto-randomize sits over
Reroll every, and the site already calls the thing animated backgrounds.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@simien
simien merged commit 955fcda into main Sep 13, 2026
2 checks passed
@simien
simien deleted the perf/mask-cache-motion-section branch September 13, 2026 22:11
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