* Mask feather: bound the variable feather's distance pass
Every flattened segment scanned its box grown by the largest feather radius,
so a path with many vertices and a radius spanning the mask revisited every
pixel once per segment. The pixel visits are now counted first; past a
budget of 2^31 the flattened polyline is thinned (every other point, arc
lengths kept) until it fits, and only a degenerate case falls back to the
hard mask.
* clippy manual_is_multiple_of
Winding numbers were dense vectors up to each segment's path index, and the
topology keeps one per segment, so memory grew with the square of the path
count. They now store only the nonzero (path, winding) pairs.
tidy_segments re-checked the whole run on every merge attempt, so a long
chain of collinear pieces cost quadratic time. A run now merges at most 64
pieces; longer runs leave a few extra joints on the same line or curve.
Add 308 Traditional Chinese effect names and 21 category labels, written from the English source with Taiwan creative-software terms. Update the completeness tests to require the zh-hant table and recount the localization docs.
Unselected layers parented to, or track-matted by, a layer that moved into the
new composition kept ids that no longer exist in the outer comp. The command's
default name was always "Pre-comp 1"; it now picks the lowest unused number.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RDvxCS8xcR28VArjzn1x7U
The panel catalog said 作業領域 for Work Area while the four menu rows say ワークエリア. The installed After Effects 2026 settles it: Edit > Preferences > Previews reads キャッシュ範囲: ワークエリアと現在の時間.
The row draws the Content-Aware Fill panel range menu and the Time Span form, so a reader met both words for
one thing depending on where they looked. One row, no other change.
Co-Authored-By: DeepSeek V4.1 Flash <noreply@deepseek.com>
The "while reading" sections of the waiting-click, in-order and undo/redo
tests now hold the build with the Held wrapper until their asserts are
done, instead of relying on a 4K plate being slow to read.
The undo tests use the shared helpers from ui_crypto_pick.rs, so they now
go through crypto_exr with k = 1 rather than a copy without it.
clicks_queued_while_reading_are_one_step_each_and_undo_in_order relied on
a blurred 4K plate being slow to read, and failed when the IDs were read
while the clicks were still being pressed. The probe's ID read is now held
(the Held footage from ui_crypto_pick) until the clicks are checked, and
the test asserts that the build reached that read and that nothing was
made while it was held.
The Esc that closed New Solid or Composition Settings also disarmed the
eyedropper. An open dialog now takes Esc like a focused text field or an
open popup, so that Esc only closes the dialog and the next one disarms.
long_sequence asserts both instead of logging a finding.
A solve with unsolved frames drew the same block as a full one, so it
looked complete. It now gets one more line in the warning colour,
"Partial solve: N of M frames solved", under the status line, and the
editor grows by that line only then. The line is an automation element,
so agents can read it too.
An eyedropper next to the Cryptomatte effect's Selection arms the viewer pick, and the status
line says how to use it. It stays armed until Esc or the button (Esc in a text field or a menu
only ends that); disarming, New, Open and Revert end it and let go of the session's probe.
The app runs the pick's bookkeeping at the start and end of each pass, the viewer hands the
pointer to the pick while it is armed and opens its context menu for a right-click the pick
forwarded, and a Selection cut off by a narrow Effect Controls panel shows whole on hover.
UI tests: ui_crypto_pick (arming, hover, clicks, modifiers, drags, waiting clicks, status,
highlight) and ui_crypto_pick_undo (one undo step per pick, the probe kept over undo).
panels::crypto_pick is the eyedropper's viewer side; it is wired in by the next commit. Armed,
the hover names the ID under the cursor and highlights its coverage, a click replaces the
Selection with it, Shift adds, Alt or Ctrl (Option or Cmd on a Mac) removes. Each pick is one
undo step, "Pick Cryptomatte".
The probe the hover needs is built off the UI thread, one at a time for the app
(EffectcraftApp::crypto_probe_busy, re-arming included), not while playing and not until a
scrub has settled for 100 ms; meanwhile the chip says so. Session::crypto_probe_ready asks for
readiness without changing anything; a job is asked for only when it starts.
Clicks made meanwhile are queued, own the build and are made in order at the end of the pass,
after its keys and edits. A click is the frame, point, resolution and project revision its
press saw. If any of them changed before it is made (an edit, Ctrl+Z, a nudge, a frame step),
it and every click waiting with it are dropped and the status says "Pick not made". A pick's
own change of the revision doesn't count as an edit for a click still held. Losing the window
focus drops a held press. A click that takes the focus from the Selection field waits for the
field to commit and is made on top of it.
The overlay takes drags too: a click that drifts picks at its press, and one dragged further
than 24 points picks nothing ("Drag cancelled the pick"). Presses and releases are read from
the pass's events in order rather than from egui's end-of-pass click state, since a slow pass
can hold a whole click. Space, the Hand and the Zoom tool keep their clicks, the middle button
pans, and a right-click is passed on under viewer::FORWARDED_SECONDARY for the viewer to open
its context menu (the viewer side is in the next commit). Errors show in the chip in red,
without the command's prefix, wrapped to the viewer's width.
The hovered ID's coverage (Session::crypto_coverage) is drawn as a texture through the layer's
effect-space transform, rebuilt only when the hovered ID, frame or revision changes, and
exposed to the test harness as viewer.cryptoPick.highlight.
Supporting changes:
- EffectcraftApp::say sets the status line and restarts its 5 s; each status message now gets
its own 5 s, also when the same text is shown again.
- Points snap to the centre of the shown frame's pixel at the exact 1/n scale the viewer
renders (frames::render_scale; the frame key keeps 0.333 for Third, which named the next
row's ID). Cache Frames When Idle renders at that exact scale too, so idle-cached frames are
on the grid the pick reads.
Session::crypto_coverage returns the coverage of one Cryptomatte ID over the layer, read from
the probe Session::crypto_probe_job keeps: at most max_side samples on the long side, each at
the centre of its cell, or None until the probe is built. It is what the Cryptomatte
eyedropper's hover highlight will draw.
Tests cover the coverage of an ID from the kept probe and the cost of a highlight with six
ranks.