With the shutter open the textured squares fell back to the particle
colour. Both branches now draw through the same sprite closure, and the
sharp frame goes through plan.post like the trails.
Resolve the two conflicts the panel catalogs and the Composition Settings
rewrite left:
- i18n/ui.rs: keep both sides' rows in the Simplified and Traditional Chinese
catalogs, which grew at the same anchor (the PR's 301 panel/dialog rows, then
main's 43 tool and Preview-panel rows). The tables are grouped by feature, not
sorted by key, so the two blocks sit one after the other. Both sides also added
"Frame Rate" once: keep one row per catalog, main's 影格速率 in Traditional
(matching the table's existing 影格速率:) and 帧速率 in Simplified.
- comp_settings.rs: take main's rewritten tab_body (it returns () and matches on
the tab, and show() measures the tabs) and re-apply the wrapping the old layout
had: the three tab labels go through tr(), as Basic, Advanced and 3D Renderer
already have rows. The old horizontal layout and its out accumulator are gone.
cargo test -p effectcraft-ui-egui --lib: 336 passed, 0 failed, 3 ignored.
The renderer applies every ancestor's transform, so a scaled null above a
camera already carries the camera's children. A Scale key with one shared
ease gets a separate Z ease before its speed is scaled.
Position speeds stretch with the path's direction at each key and Scale's Z
speed with the factor, so the ease keeps its shape. A 3D layer under a 2D
parent scales its own Z only when no 3D ancestor's Scale already carries it.
A 2D parent's Scale carries no depth, so its 3D children scale their own Z.
Percentage guides keep their percent exactly instead of drifting by rounding.
Tests now check the specific errors and cover a layer parented to a camera.
Like After Effects' File > Scripts > Scale Composition.jsx: a factor, or a new
width or height that keeps the aspect ratio, in one undo step. Layers whose
parent has a Scale follow that parent; nested precomps and expressions are
left as they are. No dialog yet.
Refs #2208
file.runScript and script.run moved from REFUSED to RUNS_SCRIPTS, which
check_command refuses too; the audit test now looks there as well.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Calculate frame_size from the original rendered dimensions and effective
render scale before cropping, so locked-aspect resize does not apply the
crop margins a second time in its dimension calculation.
Add dimension and decoded-PNG regressions for crop, resize, padding, scaled
ROI, both interpolation qualities, and zero or extreme requested sizes.
AI assistance: OpenAI Codex (GPT-6).
The job reports its times when a frame finishes, so with slow frames the
Current Render strip held the same Est. Remain long enough to look
stalled, then jumped. Between reports both times now count on from the
last one, as a clock does (remaining never below zero, a finished job
stands still), and the panel repaints twice a second while rendering.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
With the compositor built on a worker thread, the parity test's first
frame could be composited on the CPU while the build ran. Frame keys
don't name the compositor (by design: the disk cache serves frames from
either), so after the hand-over the viewer could keep showing that CPU
frame, and the GPU-vs-CPU comparison would pass comparing the CPU with
itself. The test now waits for the compositor, then opens the project
and sets the time, so every frame it compares was requested with the
compositor attached.
(`viewer_on_gpu()` can't tell here: on the desktop GPU frames are read
back into CPU images, and only the browser draws them from their texture.)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The status line is the toast that clears itself after 5 s, so the
preparing notice went blank while the viewer was still on the CPU for the
rest of a cold-cache build (tens of seconds), though `init_gpu` says the
status bar tells the user so. draw_toast now leaves that one status up
while `gpu_initializing()`; `finish_gpu_build` clears it when the
compositor lands, and the worker's repaint brings that frame, so the
toast doesn't tick meanwhile. A click still dismisses it; every other
status clears as before.
Test: with the build held on its gate, 30 more steps (7.5 s) leave the
status as it was; before this change it was empty by then.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Since #2107, Replace Footage keeps an item's kind by default, so
replace() on a sequence item brought the new file's whole numbered run.
In After Effects, replace() swaps in the one file and replaceWithSequence()
brings a run; replace() now asks for exactly that.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The reader reports a track's media duration (mdhd). For H.264 with
B-frames that runs past the last shown frame by the encoder delay the
edit list trims, so a 75-frame 25 fps clip imported as 76 frames / 3.04 s.
The footage's duration now follows the video track's edit list when it
is shorter (never longer; a delayed start keeps the reader's duration),
as the frame rate is already corrected from the header.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The menu only carried Mute, so unmuting meant the timeline's context menu.
Add the second row bound to `keys.setMuted {"muted":false}`, its translation
in the ten catalogs, and a test that runs both rows through Session::execute
with undo and redo.
Add a muted flag to Keyframe. Muted keys stay in the Timeline and Graph Editor (dimmed, selectable and movable) but evaluation skips them, so the active neighbours interpolate as if they were not there; auto-Bezier and eases use the active neighbours. When every key is muted the property falls back to its static value.\n\nkeys.setMuted {muted} mutes or unmutes the selected keys in one undo step. The Timeline context menu offers Mute/Unmute Keyframes and the Animation menu has Mute Keyframes. Muted keys have no Bezier handles and motion-path points are dimmed.\n\nLottie export omits muted keys (with a warning) because Lottie has no mute state; scripting keeps seeing them in numKeys/key().\n\nTests: keyframe evaluation (linear, auto-Bezier spatial, all muted), serialization and value replacement, engine command + undo, Lottie export.