Commit Graph

569 Commits

Author SHA1 Message Date
Brandon Thomas 549e9d8251 Footage: the missing-footage toast names the real menu item, Relink Missing Footage… (#1106)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 05:34:22 -04:00
Brandon Thomas 7a9213611e Merge pull request #1106 from eliasx45/upstream/relink-moved-footage
# Conflicts:
#	docs/footage.md
2026-10-13 05:34:14 -04:00
Brandon Thomas 3ac283eee4 Review fixes for the landed batch
- Cryptomatte (#1183): planes shorter than the image read as empty instead of panicking.
- layer.addMarker (#1180): a comp marker no longer replaces one at the same time.
- Desktop (#1005): ignore macOS's -psn_ argument instead of refusing to launch.
- Doc comments put back on their own items (#1153, #1037).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 04:47:52 -04:00
Brandon Thomas eb2b734059 PSD: take the integration branch's adapted non-finite test and psd_import formatting (#1149)
The six PSD PRs merged one by one leave #1131's test calling samples()/to_rgb(), which #1139
replaced; vangel76's integration draft #1149 has the adapted version.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 04:47:27 -04:00
Brandon Thomas acb77a8c85 Merge pull request #1210 from arnav-hiwarkar/feat/copy-presets-folder-path 2026-10-13 04:35:21 -04:00
Brandon Thomas 66c08de572 Merge pull request #1039 from moecr7/codex/fix-989-effect-paste-timing
# Conflicts:
#	contributors/people.toml
#	docs/gaps.md
2026-10-13 04:35:19 -04:00
Brandon Thomas 286a521598 Merge pull request #1037 from vbasky/fix/1001-selection-persist
# Conflicts:
#	crates/engine/src/lib.rs
2026-10-13 04:34:34 -04:00
Brandon Thomas 4ffd605296 Merge pull request #1180 from maxaeexe/feat/comp-marker-fallback 2026-10-13 04:33:46 -04:00
Jannik Wappler 1765dc53df Tint: Swap Colors (#963) (#1060)
Squash of #1060 by @RavoxX, without the docs/images screenshots (kept out of the repo).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 04:33:43 -04:00
Brandon Thomas f9d6457f6a Merge pull request #1021 from pravdomil/claude/uu-effect-params
# Conflicts:
#	crates/ui-egui/src/panels/timeline.rs
2026-10-13 04:32:16 -04:00
Brandon Thomas 430c968e52 Merge pull request #933 from Themolx/replace-with-precomp
# Conflicts:
#	crates/engine/src/tests_project_items.rs
2026-10-13 04:31:42 -04:00
Brandon Thomas 4574fb62bc Merge pull request #792 from vangel76/gap-object-matte
# Conflicts:
#	crates/ui-egui/src/i18n/ui.rs
#	docs/gaps.md
#	docs/target-app-parity.md
2026-10-13 04:30:49 -04:00
Brandon Thomas 287c35dae7 Merge pull request #1109 from eliasx45/upstream/azerty-graph-zoom
# Conflicts:
#	crates/engine/src/commands/time.rs
#	crates/ui-egui/src/panels/timeline.rs
2026-10-13 04:29:47 -04:00
Brandon Thomas 3aac824976 Merge pull request #1175 from storybored379/fix/roto-trim-span
# Conflicts:
#	ROADMAP.md
2026-10-13 04:29:08 -04:00
Brandon Thomas 12e21b5938 Merge pull request #1159 from nanox333/fix/1010-gimbal-precision 2026-10-13 04:29:07 -04:00
Brandon Thomas fa5ce34012 Merge pull request #1119 from marcoarnulfo/fix/ges-jsx-keyframes
# Conflicts:
#	crates/script/src/tests.rs
2026-10-13 04:29:06 -04:00
Brandon Thomas a985dfb36b Merge pull request #1098 from vangel76/feat-gap21-percent-guides-effect-labels
# Conflicts:
#	crates/engine/src/tests_menu_cmds.rs
#	docs/effects-parity.md
#	docs/gaps.md
#	docs/ui-parity.md
2026-10-13 04:29:06 -04:00
Brandon Thomas a43cf2002a Merge pull request #1075 from vangel76/fix-1061-rename 2026-10-13 04:29:04 -04:00
Brandon Thomas 767f1f6265 Merge pull request #1057 from pravdomil/claude/shortcut-toggles 2026-10-13 04:29:03 -04:00
Brandon Thomas 37b681ac12 Merge pull request #1104 from eliasx45/upstream/import-project 2026-10-13 04:28:59 -04:00
Brandon Thomas 1d8fe7a8a0 Merge pull request #1158 from nanox333/fix/551-shift-space-every-frame
# Conflicts:
#	docs/ui-parity.md
2026-10-13 04:28:55 -04:00
Brandon Thomas f0fa92ceef Merge pull request #1146 from redonion23/fix/1078-reset-keeps-keyframes 2026-10-13 04:28:54 -04:00
Brandon Thomas dc3131b339 Merge pull request #1054 from pravdomil/claude/shortcuts-keyboard-commands
# Conflicts:
#	crates/engine/src/commands/time.rs
#	crates/ui-egui/src/menus.rs
2026-10-13 04:28:51 -04:00
Brandon Thomas 4f57d5d73d Merge pull request #1144 from tylerjenningsw/enhance/quick-offset
# Conflicts:
#	crates/ui-egui/src/i18n/ui.rs
2026-10-13 04:28:43 -04:00
Brandon Thomas fc54b5debc Merge pull request #1139 from vangel76/fix-psd-decode-memory-budget
# Conflicts:
#	crates/psd/src/lib.rs
#	crates/psd/src/placed.rs
2026-10-13 04:28:42 -04:00
Brandon Thomas b438cdd702 Merge pull request #1135 from vangel76/fix-psd-lenient-layer-section
# Conflicts:
#	crates/engine/src/psd_import.rs
#	crates/engine/src/tests_vector_import.rs
#	crates/psd/src/tests.rs
2026-10-13 04:28:40 -04:00
Brandon Thomas 15d2030d73 Merge pull request #1051 from marcoarnulfo/fix/interpret-loop-video-duration 2026-10-13 04:28:37 -04:00
Brandon Thomas c5d2a54507 Merge pull request #1013 from Themolx/unique-new-comp-names 2026-10-13 04:28:36 -04:00
Brandon Thomas e02c60c08a Merge pull request #1131 from vangel76/fix-psd-nonfinite-and-panic-paths
# Conflicts:
#	crates/psd/src/tests.rs
2026-10-13 04:28:31 -04:00
Brandon Thomas 7da7358504 Merge pull request #1102 from vangel76/feat-gap7-presets-backgrounds
# Conflicts:
#	crates/ui-egui/tests/ui_panels.rs
#	docs/gaps.md
#	docs/target-app-parity.md
2026-10-13 04:28:30 -04:00
Brandon Thomas 2a1a98006c Merge pull request #1086 from vangel76/fix-1070-stale-footage-cache 2026-10-13 04:28:27 -04:00
Brandon Thomas 0e424b45f1 Merge pull request #1050 from pravdomil/claude/bind-existing-shortcuts 2026-10-13 04:28:25 -04:00
Brandon Thomas 61a6d95e51 Merge pull request #1030 from vbasky/fix/990-u-reveal-timeremap 2026-10-13 04:28:24 -04:00
Brandon Thomas 96a29bb2f0 Merge pull request #1129 from vangel76/fix-psd-nested-group-depth 2026-10-13 04:27:30 -04:00
Brandon Thomas 69f416e3b0 Merge pull request #1038 from vbasky/fix/1010-camera-parent 2026-10-13 04:27:25 -04:00
arnav-hiwarkar c7692aa697 #971: copy the presets folder path in Effects & Presets 2026-10-13 13:27:09 +05:30
Vikram Bhaskaran c46f80faa2 Store each comp's layer selection on its own.
A single selected_layers list kept ids from every comp, so the active comp looked selected whenever another comp was. Opening a comp and running a script against a different comp now park and restore that selection.
2026-10-13 17:46:02 +11:00
Vikram Bhaskaran 8c986a1bec Keep closed comps' layer selections across scripts (#1001)
sanitize_state dropped every selected layer not in the active comp at the
end of each script run, so a layer selected by script in a comp that was not
open was gone by the next script call. Every comp keeps its own selection as
in After Effects; only ids gone from every comp are dropped now. UI and
engine lookups resolve selections per comp and tolerate foreign ids.
2026-10-13 17:39:16 +11:00
maxaeexe af1133a1f3 layer.addMarker: add composition marker when no layers are selected 2026-10-13 04:43:53 +03:00
Kristian Myram be99fecfdc #1010: recover a static Orientation's Y angle without losing precision near gimbal lock
uniform_parent_pose took the Y angle from asin, which loses precision within about 1e-6 degrees of
+-90. The Y angle now comes from atan2 on cos(Y), as the X and Z angles already do. The gimbal
branch and the principal-range output are unchanged.

A new test parents a static Orientation with Y 1e-6 degrees off gimbal lock under a uniform
parent. Its largest corner displacement was 3.3e-8 px before this change and 1.5e-14 px after.

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
2026-10-13 01:33:51 +02:00
tylerjenningsw e1c9c33fb1 Keyframes: a refused key drag step doesn't count towards the drag (#1012)
keys.quickOffset and keys.move stored the drag's new total before the
edit ran. When the edit refused the step (keys.quickOffset with a key
landing past the end of time), the project stayed as it was but the
total kept the refused delta, and with incremental steps (merge without
fromStart) the next step moved by it too.

The drag state is now stored only after the edit applies.

Test: a_refused_step_does_not_count_towards_the_drag (+1 s, a refused
step, -1 s: the keys end where they started; fails before: the last key
ends near the end of time).
2026-10-12 18:49:48 -04:00
tylerjenningsw f72b8993ef Keyframes: moving keys keeps subframe spacing (#1012)
keys.move and the nudges snapped each key's destination to the nearest
frame, so moving keys a Quick Offset had staggered onto subframes put
them back on frames: four keys at 0, 1/3, 2/3 and 1 frame, moved one
frame, came out at 1, 1, 2 and 2. Layer bars kept theirs, because
layer.timing snaps the move, not the times.

The move is now rounded to whole frames and every key translated by it.
layer_shift turns a comp-time move into a layer-time move through the
layer's start and stretch (reversed too) without a round trip through
comp time; keys.quickOffset uses it as well.

Test: moving_staggered_keys_keeps_their_subframe_spacing (Quick Offset,
then keys.move and keys.nudgeForward; fails before: 1/3 frame lands on
a frame).
2026-10-12 18:49:34 -04:00
redonion23 a69c7d7cd2 Timeline: Reset keeps an animated property's keyframes and keys the default (#1078)
prop.reset cleared every keyframe before setting the default value. As in
After Effects (and as effect.reset already does for effect parameters), an
animated property now keeps its keyframes and gets the default as a key at
the current time; a static property just takes the default. The expression
is still removed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 23:52:44 +02:00
storybored379 5d9bab268d M6.7: reject Roto Brush span edits past trimmed strokes
Validate saved stroke frames against the current layer limits before clamping a span edit. Keep project and undo state intact when trimming has left strokes outside the layer.

Co-Authored-By: OpenAI Codex <noreply@openai.com>
2026-10-12 14:40:10 -07:00
tylerjenningsw 28e9e5229e Quick Offset: layer.quickOffset and keys.quickOffset commands (#1012)
After Effects 25.4's Quick Offset staggers selected layers, or each
layer's selected keyframes, in the order they were selected: the first
stays, the last moves by the drag and the ones between by equal steps,
landing on subframes.

layer.quickOffset {delta, layers?} moves each layer's start, in and out
point by total * i / (n - 1), worked out once in ticks with integer
arithmetic, so 1 frame over 4 layers gives 0, 1/3, 2/3 and 1 frame
exactly. keys.quickOffset {delta} does the same per layer for the
selected keys, the layers in the order their first key was selected;
every selected key of a layer, across its properties, moves by that
layer's comp-time offset through its start and stretch (reversed too),
keeping values, interpolation, easing and labels. Locked layers are
skipped and at least two layers are needed. With merge and fromStart,
delta is the whole drag and each step starts again from before it, so
the drag is one undo step and a key passed over survives. A delta or a
destination out of the range of times is an error, not a clamped move.

Docs: agents.md; architecture.md notes Quick Offset as the exception to
times snapping to frames.
2026-10-12 17:37:31 -04:00
tylerjenningsw 7643f803e0 Keyframes: moving keys keeps the selection order
keys.move (and nudging) rebuilt the key selection in layer and property
order, so the order the keys were selected in was lost after a move. A
Quick Offset that follows staggers layers in that order (#1012).

The move now goes through move_key_refs, which maps each selected key to
its new time and returns the selection in its original order, with the
same collisions (a key landing on another replaces it), roving retiming
and locked-layer handling as before. key_gesture is the drag-step logic
(start again from the keys and project as they were before the drag)
split out of shift_keys so other key drags can share it.

Test: moving_keys_keeps_the_selection_order (fails before: the keys come
back sorted by layer).
2026-10-12 17:37:29 -04:00
vangel76 4a08f8fdf4 PSD: a memory budget for one decode and a capped smart-object bake (#1138)
The 2^28 pixel limit applied per image; one composite or layer decode kept
the ZIP output, a Vec<f32> per channel and the result alive together, and the
bake size came from the file's quad. A decode now charges every buffer
against a byte budget (4 GiB, 1 GiB on 32-bit), checks its whole expected peak
before allocating, writes channels straight into the result and returns an
error when over budget. Bakes are at most 4x the document across and 2^24
pixels.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-12 23:06:55 +02:00
vangel76 6259bf0b57 #1132: a damaged PSD layer section keeps the merged image instead of failing the document
Psd::parse drops the layers, records Psd::warnings and keeps the header and
merged image; the importer then imports the flattened image as one layer and
reports 'Layers could not be read'. Header damage and a missing merged image
stay hard errors.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-12 23:00:40 +02:00
vangel76 130bcb2385 PSD: drop non-finite values from descriptors, EngineData and 32-bit samples; no panic in Warp::apply or Rect::new (#1130)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-12 22:57:27 +02:00
vangel76 4f9a04fcf5 PSD import: bound group nesting at 64 so thousands of nested groups cannot overflow the stack (#1128)
Psd::tree flattens groups nested deeper than MAX_GROUP_DEPTH into their depth-64 parent, keeping every layer, so the importer recursion and the tree's Drop/Clone/PartialEq are bounded. The import result reports how many groups were flattened.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-12 22:56:56 +02:00