The comp-end label was clipped to a stray "1" against the marker bin.
(cherry picked from commit f62afa0364f1bf38f0b0b5eda5ccc07f33174790)
(cherry picked from commit 2e3d08dad7d73a14688bf6d8bfb1712ab51443a2)
(cherry picked from commit 773471c3a39bef51f4763d21d007534cfd95c0b1)
(cherry picked from commit 176508a82145eb7063c776f6cd44ba925a8edd99)
(cherry picked from commit 9fd5b1e5618a6ad19638494b480460e9527debde)
(cherry picked from commit 812e34fd7834e828bebd3f79440f831d188a1a99)
(cherry picked from commit 283adb1a30e6b51ab6603488e57b9997a0ca83f0)
(cherry picked from commit cb2e659baad5e4fe853c124dafe32491335b8232)
(cherry picked from commit 0acb03da5f0d09d726047013e931e5eeff5504ce)
(cherry picked from commit 66427c0149c5f2fd46931945a4f11a9530c12269)
(cherry picked from commit d5fadffc1ac9f072a985a918cd6a62e9763bc2bf)
(cherry picked from commit adec1c33542c2566183c6698cb0b1ad8e8afa0e0)
(cherry picked from commit 9d6352faea454ebcd1a575056c4d5f0bafcc80ea)
(cherry picked from commit d6110a23e9c459eb4c677b439d811b7438b1a999)
(cherry picked from commit f46595d119d253c9298eb045ad521420a155b422)
(cherry picked from commit fff43e6f6edc00bf60aa031643f3356b9e7ccfad)
The In/Out trim zones were 6 pt strips inside the bar only: at or just outside an end the pointer got the default cursor, and on footage/precomp layers just outside the end it hit the slip zone, which shows the same arrow but slips the source instead of trimming. Zones now reach 4 pt outside and up to 5 pt inside each end (short bars keep their middle third as body), registered after the slip zones so trimming wins there. The trim zones show the system resize cursor (upstream port: the fork also offers an owner-local cursor, left out here). Test: ui_timeline_trim.
(cherry picked from commit e2490f801067365addc03858bd555731cb188ad1)
(cherry picked from commit b704fc52c4fdb43816721e95d13f132a11062aa1)
(cherry picked from commit 17faf9cebf9e347534ceab37386e79979da8f786)
(cherry picked from commit 9b9d21aacc4d025e36e13a05e4416a49f448bdf1)
Co-Authored-By: Claude <noreply@anthropic.com>
(cherry picked from commit 562bfa51bd6ee86d1f8f5558b1ad466c7e4b4517)
(cherry picked from commit 0779d6944ede8afdff6ab49ea5d2caad19dfbfa3)
(cherry picked from commit 38e224f5c5037b7c79a283ab058582a3ad200339)
(cherry picked from commit 5e7b68be23ace400d92672ebf41c59124d29b101)
Co-Authored-By: Claude <noreply@anthropic.com>
(cherry picked from commit 6277a98f3ff6207bd215213af514c5f6fb481532)
(cherry picked from commit 646f4055b180d98ccc6ac6898b64ba97f9e2ad7d)
(cherry picked from commit b21932ed7058cec68da01d337ba46521501ebc49)
(cherry picked from commit 0d6b93962e123b2e0179622f2abd472cfa9015ac)
Opening the Graph Editor (header button, menu, Shift+F3, control channel)
frames the graphs on its first frame: Fit Selection to View when keys are
selected, else Fit All Graphs to View. Switching value/speed graph refits
too (different units). A selected key now shows its property's graph even
when its layer isn't selected, and Fit Selection on a lone key also frames
its neighbouring keys.
Co-Authored-By: Claude <noreply@anthropic.com>
(cherry picked from commit a3c95f601e78e7a12f62aba94ee3515b2ade1670)
(cherry picked from commit d6309ffad79b91676d6409d1845de508e485873d)
(cherry picked from commit 78f557433742e443c9b7db34c1dac67e6a2b8e18)
(cherry picked from commit 7a4e160434b7bf1289cbf5900a86715814d1c791)
The Timeline footer's zoom-out / zoom-in mountain icons were painted but not
interactive, and the zoom slider only reacted to drags (a click on the track did
nothing) and set the zoom without the whole-comp clamp. The icons are now buttons
(timeline.zoomOutButton / timeline.zoomInButton, one = / - step), the slider
jumps on click, and both go through set_zoom, centred on the CTI.
The layer bars and the Graph Editor share one time zoom (TimelineState start /
pps, as in After Effects); regression tests drive = / -, the buttons, the slider
and the navigator over the control channel in both views and check switching
views keeps the zoom.
Co-Authored-By: Claude <noreply@anthropic.com>
(cherry picked from commit 2ee0fb656ff6bd16eed6857be10495d9f30e3a64)
(cherry picked from commit f1997d32d4c51b58467a04944889131fd741a22a)
(cherry picked from commit 1c25aeb51d37357b4b37857858db4dbea246b13a)
(cherry picked from commit 81d7fcccfc91f76f7b9640cbb7d3f75dcea56e30)
Split out of 7782ab01 (shapes: Reverse Path Direction …; work area keys) for upstream, where it
belongs with the commands it binds.
(cherry picked from commit 7782ab015a01613c1685cb6dda48d48c3b1db67b)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01F2dXDtF1ivCLP4tQwFveQ4
(cherry picked from commit b58cfb7434e147535e66582718b8856bd3ce1230)
(cherry picked from commit ff4876054f3cbf9388954602e8fe7288d136c255)
(cherry picked from commit 79d083a8c2a0bfa4663445257149a0d0ce491987)
Shortcut presets accept Physical+<key> (egui US-position names) so layouts that report the
same logical key for two physical keys (AZERTY's - and )) can bind them separately; physical
bindings win for that press, and a focused panel's binding wins over an application command on
the same chord. ui.key accepts the same notation. Adds time.workAreaStart / time.workAreaEnd.
(cherry picked from commit 209543e9e0ba32f809f9ff333abb8b8ec4125cea)
(cherry picked from commit f8301a9e3e0b60e200e8a233455398741658481e)
(cherry picked from commit 4d002fabf992934e1bb73a0c32bc9f3fd3ae5447)
(cherry picked from commit 5d466c5955ee934d5347c194ec7d15fb5f58bba4)
File > Import > EffectCraft Project (and .ecproj/.ecprojx given to File > Import)
merges the project into a folder named after the file, with every id shifted past
the open project's, in one undo step. Relative footage resolves next to the file;
the result lists comps, root comps, primaryComp and missing media.
offset_ids now shifts tracker Motion Targets and saturates instead of overflowing;
fix_next_id saturates too, so a damaged file can't overflow on open or import.
Menu entry translated in all ten menu catalogues.
Rebased onto current upstream main for the split of #858 (test module list in
engine lib.rs; es/pt-br/ru/fr/de/cs menu translations).
(cherry picked from commit 19c653fccc95133fb35e978a7f7f20a18c0e8c89)
(cherry picked from commit 4e751ad2)
(cherry picked from commit ceed706cc3b5f3755769738a1ddb3d965a94ab6b)
3eb3b99 makes the particles replace their layer as in AE, so their 112 pinned
CPU hashes change intentionally; no other effect changed.
(cherry picked from commit 9900eae773e1cad43a6d1bdcacbadc45a84b063a)
(cherry picked from commit 7aa27c0dd7c24b9f24591bb144a95951dc0ec510)
(cherry picked from commit 73377e8eca5c639715e5f3f623ed53ff329638a0)
(cherry picked from commit f07497dfee)
Echo, Posterize Time and the other Time effects read the layer at other times with none of
its effects. After Effects renders them with the effects before them: SceneYard "Task
Preparation UI" applies Echo after CC Particle Systems II on black solids, and AE shows the
echoed fireworks over a white page where we echoed the black solids and blacked it out
(Posterize Time after Turbulent Displace, the usual stop-motion setup, depends on the same).
The host already bounds the count to the effects before the one rendering.
Mean abs error vs AE: Task Preparation UI 0.1855 -> 0.0071, Lightbulb Idea 0.0126 -> 0.0102;
the 15 other corpus projects with a Time effect after another effect are pixel-identical.
(cherry picked from commit 46870452db2656c72406f63245e8b1609ceb04d4)
(cherry picked from commit 334d102582e5a64db32e2f3e55836d55ac96bdaa)
(cherry picked from commit 734da3e35dc57c01b73823458bdd87611ac1bf99)
(cherry picked from commit 87a733e076)
The particles were composited with the original layer by the Transfer Mode, so the solid an
artist applies them to stayed visible. After Effects 2026 frames show no trace of it:
SceneYard "Burnout matchstick" (a red rectangle around the flame), "Documentary Man Falling"
(a black block over the light), "Task Preparation UI" (black solids under fireworks). The
Transfer Mode now only sets how the particles meet each other.
Mean abs error vs AE: Burnout matchstick 0.0191 -> 0.0130, Documentary Man Falling
0.1177 -> 0.0937 (Task Preparation also needs the next commit).
(cherry picked from commit 3eb3b9958f9cd929dcf060865e604d42cc0f9337)
(cherry picked from commit 729638710e63f4da10711fc5e6a1f7ddc42c37aa)
(cherry picked from commit 083332116c936f1b4863f0bb390d0647f2b567a1)
(cherry picked from commit 338421de36)
With --compare, exits 1 when a matched run got more than PCT % worse in CPU time, peak memory, max RSS
or instructions retired (wall time follows the load and is never gated).
Checks: xtask fail_over test (1 passed).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TEytG1Qum4TJrMTLKjgwDa
(cherry picked from commit c34be4d12f3a61f4e386256ae54d75c6bc7f875d)
(cherry picked from commit 6e3eab96493726c551ec1e66174ac08b5591e4c2)
(cherry picked from commit 2e066f4073b300d8bace04419a7d4af3f3242b2e)
(cherry picked from commit 351a4b96c0)
(cherry picked from commit 40b232d02069925e9c72677f52ee6f356495a736)
(cherry picked from commit a2d89bda11b7217c83c98ab681b8f9b4a334786d)
(cherry picked from commit 63951595222207b6bfd0ecde72f991628c6f12d9)
(cherry picked from commit 20c2bb0dcb)
footage.relink {item, path} relinks one item and every other missing item that moved with it (one undo
step); Replace Footage on a missing item does the same, as in After Effects. File > Dependencies >
Relink Missing Footage in Folder... (footage.relinkFolder) finds missing files by name in a folder;
footage.missing lists them. The footage check after open finds files that moved along with the
project's folder, without marking the project modified. Paths compare by parts, so Windows and macOS
projects relink either way.
Checks: engine relink:: / footage_check:: (13 passed with replay::), host relink:: (1 passed),
clippy -D warnings (engine, host, ui-egui, script, cli, xtask). Not run: ui-egui i18n tests.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TEytG1Qum4TJrMTLKjgwDa
Upstream port: the folder search (footage.relinkFolder) is left out, since upstream's file.relinkFootage already scans a folder; the module is relink_moved.rs next to upstream's relink.rs.
(cherry picked from commit ea7923535fb81693ed95aa0fe768b850b347b2a9)
(cherry picked from commit d15e853a720304c1032e21974d84e1501c6edfc3)
(cherry picked from commit 0b8a328dda1fb727488e912a13f94a2ef4147d03)
(cherry picked from commit 9d85bfde72)
Both returned their input unchanged. They now go through the layer's transform and its parents'
at comp time, and the inverse.
Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
layer.source was undefined in expressions, and a layer from a Layer Control had no transform.
Both now work.
Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Shift+Spacebar set Skip to 1, so it played every other frame out of the box. It now plays every
frame, like Spacebar. Skip still works when it is set.
Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
The menus have been complete in Japanese since the menu catalog landed, but the panel
catalog below the menu bar stopped at 410 of the 506 source strings the Chinese catalogs
define. Settings, the Home screen, the viewer tools and the Fast Previews and channel
popups therefore still drew in English for a Japanese interface.
This adds the 96 missing rows. Existing rows are untouched and keep their order; the new
ones follow the canonical (Simplified Chinese) order, which the catalog tests require, and
no row changes the number of `{}` values its English source carries.
Terms follow the Japanese already in the catalog and, wherever a control exists in both,
the wording After Effects 2026 (26.5) itself shows in Japanese: 平面 (Solid), 関心領域
(Region of Interest), フル画質 / 1/2 画質 / 1/3 画質 / 1/4 画質 (viewer resolution),
ドラフト 3D (Fast Previews), 透明グリッド (Transparency Grid), マスクとシェイプのパスを表示
(Toggle Mask and Shape Path Visibility), チャンネルとカラーマネジメント設定を表示 (Show
Channel and Color Management Settings).
The crate's `i18n` unit tests pass (10/10) and rustfmt is clean.
First in the menu, as in After Effects, and for the right-clicked comp rather than the one in the viewer: the dialog keeps the comp it edits and OK passes it to comp.settings. comp.settings with only {"comp": id} opens the dialog on that comp.
The shared release workflow installs trunk, but EffectCraft's web build
runs the wasm-bindgen CLI directly (cargo xtask web), so the Web job
fails with "wasm-bindgen CLI not found". In CI, package.sh now installs
the CLI at xtask's WASM_BINDGEN version, as the per-app release.yml did
before the move to craft-common-actions.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Zoom to Fit Comp remembers the span it left and goes back to it when pressed
again from the whole comp.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Alt+1 after Alt+Shift+1 shows the red channel in grayscale instead of going back
to RGB (and the other way round). The same key again is still RGB.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
layer.sampling takes `toggle`: layers that all have the sampling already get the
other one. The Bilinear and Bicubic menu entries, which carry the keys, pass it.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
F2 Deselect All, Cmd+Shift+T Effect Controls, Cmd+Alt+Left / Right Go to Start /
End, Cmd+Shift+/ Add to Render Queue.
Effect Controls is a menu entry with bound parameters, which could hold one key:
a menu line can now give further default keys after a comma
(F3, Cmd+Shift+T); the menus show the first. MenuEntry gains alt_shortcuts.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
arc added 2π to its sweep in a loop until the sweep was no longer
negative, and arcn subtracted 2π the same way. For an angle of 10^18
degrees the loop took about 3e15 passes, and from 2^56 radians (about
4.1e18 degrees) up, adding 2π left the sweep unchanged and the loop
never ended. A sweep that needed no loop, as in 0 10^18 arc, was passed
unchanged to kurbo, which divides it into more than 1e16 curves (about
four per turn at a radius of 10), and arc appended each curve to the
path. Importing an EPS file probes it with effectcraft_pdf::parse,
which has no time limit, so importing such a file did not finish.
As in storytold/vectorcraft#1062, every arc now starts at the first
angle's remainder after whole turns, and when the second angle is below
the first (arc) or above it (arcn), the sweep is worked out from the
two angles' remainders. A sweep of up to 1,024 turns is drawn whole.
For a longer one, the import records a skip note
("arc (too many turns)") and leaves out whole pairs of turns, so that
between 1,022 and 1,024 turns remain. The arc still ends at the second
angle, and an even-odd fill covers the same area as the full sweep.
Arcs of up to 1,024 turns whose angles are within about 10^6 degrees
are unchanged apart from rounding, except some whose angles are a whole
number of turns apart or within rounding of that. For larger angles,
the old conversion to radians lost precision: at 10^15 degrees, a
quarter-turn arc swept 1.5723 radians instead of 1.5708.
When raising (arc) or lowering (arcn) the second angle by whole turns
makes it equal to the first, as in 7 -353 arc or 2 362 arcn, rounding
sometimes made the old loop add a turn and draw a full circle. Those
arcs are now empty, as the PostScript Language Reference defines them.
When the raised or lowered angle falls just short of the first
instead, the reference defines a full circle, and each version leaves
some of these arcs empty: the old code drew nothing for
125.00000000000001 125 arc, which the new code draws as a full circle,
and the new code draws nothing for 1.0000000000000002 -719 arc, which
the old code drew as a full circle.
arcs_with_huge_angles_end_at_their_second_angle parses each program on
a thread of its own and fails when no result arrives within 20 seconds.
Both were a single command taking the mode as a parameter, with no menu entry,
so nothing could carry a default key. Each mode is now its own command:
view.fastPreviews.off / adaptive / draft / fastDraft / wireframe (Cmd+Alt+1-5)
and view.channel.red / green / blue / alpha (Alt+1-4), redColorized /
greenColorized / blueColorized (Alt+Shift+1-3) and rgbStraight (Alt+Shift+4).
A channel's key again returns to RGB.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The previous release build failed in craft-common-actions, not in this
repo: riscv64 packaging got --formats deb,rpm,tar (fixed in
craft-common-actions#3), Linux jobs lacked the ALSA headers
(craft-common-actions#5), and Windows signing needed the AZURE_* secrets
listed in the caller.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Cmd-click (or Alt-click) a twirl arrow now takes the whole tree with it in
three more places: Audio's Waveform row in the Timeline, an effect or effect
group in Effect Controls, and a folder in the Project panel.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- The cap applied whenever an accelerator was attached, so Software Only
projects (which render on the CPU) rendered one frame at a time. It
now needs the project's GPU acceleration too, as #898 gates it.
- Only the render is capped: each window of max(cap, threads) frames
renders in chunks of the cap, then encodes in parallel, holding at
most one window of images.
- An invalid EFFECTCRAFT_GPU_INFLIGHT (0, negative, not a number, too
large) logs a warning before using the default.
- The default stays one frame: the GPU backend reports no free or total
device memory portably, so it is not sized from VRAM.
setInterpolationTypeAtKey and setTemporalEaseAtKey act on effect parameters
(a Slider Control's slider and a 3D Point Control), not just transform
properties. Verified on current main; lock it in with a script regression
test driving the per-key methods through the property object.
The engine's layer.create has shapesFromText and masksFromText, but the
timeline and Composition context menus only offered Create Shapes from Vector
Layer, so text could not be converted to editable outlines from the UI. Gate
the two text conversions on a text layer (LayerMenuCaps replaces the lone
vector flag), beside the vector one.
Cmd-click (or Alt-click) the arrow of Effects, Contents, Masks or any other
group in the Timeline twirls every group under it open, or closed, with it,
as the layer's own arrow already did.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A script reading an expression that calls sampleImage on a footage layer got
[0,0,0,0]: the script evaluator built its EvalCtx with EvalCtx::new, which
has no footage source, so the renderer substituted transparent frames (solids
and shapes stayed correct because they are procedural). Pass the session's
footage source, as the app's renderer and diagnostics already do.
Drop the 6 px added to expression editor rows (and the matching offset in
the drag-to-resize maths), so the row is a whole number of row heights.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Three frames at once still filled an 8 GB card on the #879 project at
1080p (7.9 GB, the same as no cap); one frame peaked at 6.3 GB and two at
7.0 to 7.8 GB. One matches how the export scheduler in #898 renders image
sequences (one GPU worker, synchronous readback). EFFECTCRAFT_GPU_INFLIGHT
still raises it.
Rows stripe by their index among the non-expression rows, so adding or
removing an expression leaves every other row's stripe unchanged.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
setParent re-expressed Position for 3D layers but skipped cameras and lights
entirely, so parenting a camera to a (default) null moved its eye by the
null's world transform and the framing jumped. Cameras and lights now get the
same parent-space Position fix, plus Point of Interest for two-node rigs
(values, keys, spatial tangents and ease speeds). They have no Scale, so
Orientation stays as authored.