Commit Graph
203 Commits
Author SHA1 Message Date
aiongg 2b4fcdd3db refactor(engine): move error, services, document state, event, fonts and Session methods out of lib.rs 2026-10-26 21:49:11 +00:00
aiongg eea1f50cd3 refactor(engine): move guard, logging, perf, sysinfo, storage to system/ 2026-10-26 21:49:11 +00:00
aiongg a7660a1e37 refactor(engine): move jobs, offload, remote to background/ 2026-10-26 21:49:11 +00:00
aiongg 85e26db57d refactor(engine): move learn, templates, demo, links to home/ 2026-10-26 21:49:11 +00:00
aiongg 1c565ba2df refactor(engine): move psd_import, vector, xml_project to interchange/ 2026-10-26 21:49:11 +00:00
aiongg d6b53650db refactor(engine): move doc_path, footage_check, footage_reload, sequence, media_browser, media_cache to footage/ 2026-10-26 21:49:11 +00:00
aiongg 9991466ff1 refactor(engine): move prefs, session_settings, config, shortcuts, autosave to settings/ 2026-10-26 21:49:11 +00:00
aiongg 3b5e19027e refactor(engine): move tracking, camera_track, mask_track, warp, roto, models to analysis/ 2026-10-26 21:49:11 +00:00
aiongg 35e66b17a6 refactor(engine): move tests_<topic>.rs files to src/tests/, tests.rs content to tests/session.rs 2026-10-26 21:49:11 +00:00
aiongg a3ea645fc6 refactor(engine): move commands/ to cmd/, keeping commands as an alias 2026-10-26 21:49:10 +00:00
skylar taylor-barrick 47bf08a15e M-egui037: document migration behavior and guard atomic batch rollback 2026-10-25 19:56:09 +01:00
skylar taylor-barrick dec327b98a egui037: Preserve text ownership across unrelated history changes 2026-10-25 13:03:14 +01:00
skylar taylor-barrick 18206c1014 Fix text ownership after composition removal and simplify playback helpers 2026-10-25 11:40:05 +01:00
skylar taylor-barrick 57220d4d6a Fix egui 0.37 text ownership and simplify UI lifecycle handlers 2026-10-25 10:18:26 +01:00
skylartaylor 9ee853715d M0.37: migrate EffectCraft to egui 0.37
Reconcile main 991904888a and preserve the reviewed lifecycle, IME, rendering and lockfile changes.

Formatting, strict lint, layers, assets and WASM passed. Full CI retained 3,961 passes, 14 baseline-matching GPU failures and 31 ignored executions. The local review commit has explicit approval to retain these documented failures; native/browser acceptance and paired app performance remain open.
2026-10-25 02:01:16 +01:00
aiongg cce71f69fc Merge #1946: #1926: an edit no longer stamps every image-sequence frame for the disk cache (@ded-achtung) 2026-10-24 01:10:55 +00:00
aiongg bae27ebbe7 Merge #1841: Cryptomatte: pick the ID under a point into the Selection (effect.pickCryptomatte) (@MatejKozlovsky) 2026-10-23 23:33:10 +00:00
dedandClaude Opus 5.5 49ec37ec3f Disk cache: an edit that leaves the footage alone keeps its salt (#1926)
Session::bump took the disk cache's footage salt at every edit, which reads the size and time of
every footage file, each frame of an image sequence included. With three 5000-frame sequences a
caret move or a typed character in a text field took ~0.6 s on the UI thread (9 ms with the disk
cache off). The salt is now taken again only when the footage items changed, or when a project
is opened, footage is reloaded or the disk cache attached.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 16:40:24 +03:00
Camille Moine 8d887fd6da Layer: replace a layer's source with Alt-drag and Ctrl+Alt+/ (#991, #813)
Alt/Option-drag a Project item onto a Timeline layer, or press Ctrl+Alt+/ (Cmd+Opt+/) with layers and an item selected, to swap the layer's source. The layer keeps its name, timing, transforms, keyframes, expressions, effects, masks, switches, parenting and track matte; a source with audio adds Audio properties when missing. Precompositions can't be nested inside themselves.

AVLayer.replaceSource now runs the same engine command and closes the replaceSource part of #813.
2026-10-20 12:18:46 +02:00
Matej Kozlovský 76098665b0 Cryptomatte: effect.pickCryptomatte picks the ID under a point into the Selection (#473)
Engine part of viewer picking: replace / add / remove the top-coverage ID at a
layer-space point in one undo step, at the time the Selection was read. The
aux channels come from the render's own path (Renderer::layer_aux, shared with
the effect host; footage at its source time, 3D precomps) through a renderer
set up like Session::render (expressions, render prefs, layer cache). An
optional scale snaps the point to the pixel a preview at that resolution
samples. New effects::crypto_select quotes names and falls back to <hex> for
unnamed, wildcard-looking or ambiguous names. effect.cryptomatteAt is the
read-only hover query.
2026-10-19 06:10:27 +02:00
Brandon Thomas d9e3c56404 Merge pull request #1721 2026-10-18 09:35:35 -04:00
Brandon Thomas 972a2d21d2 Merge pull request #1659 2026-10-18 09:35:34 -04:00
arnav-hiwarkarandClaude Opus 5.5 ea67c46880 #1714: doc comments name the saved current times
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-17 14:40:44 +05:30
arnav-hiwarkarandClaude Opus 5.5 b9172fec2f #1714: reopen each comp at its saved current time
Layer times were already saved and read back as exact ticks; the values in
the issue are 34f, 315f and 3033f at 59.94 fps. The viewer was black because
the playhead wasn't saved: a reopened comp started at 0, before its layers.
The project file's view (`activeComp`, `openComps`) now also records each
comp's current time (`compTimes`), restored on open within the comp's frames.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-17 14:32:14 +05:30
aiongg 816ca95800 Footage: follow stored footage paths only on this computer or the project's share
Footage paths stored in a project are resolved through craft-docpath against
the project file when it is opened or imported: relative paths are taken from
the project's folder, and an item whose path is on another computer, names a
device or is a non-file URL is marked missing without being looked at. The
footage check, the changed-on-disk scan, Reload Footage, Relink, Edit Original
and Reveal in Finder resolve the path again before touching the file, and the
Project panel, Metadata panel and waveforms read no file details of missing
footage.

Lottie image assets are resolved against the Lottie file; one on another
computer is skipped with a warning. Files a 3D model names are read only when
local or on the model's own share.

Reveal in Finder refuses a folder that would open as an app or other bundle.

Files imported or relinked in this session are opened as given.
2026-10-16 17:43:58 +00:00
detthandClaude Sonnet 5.5 2823abc40c fix(engine): report the keys keys.delete removed, not the keys selected
keys.delete returned the number of selected keys even when some of them
no longer existed, so a delete that removed nothing still reported success.
It now returns the number of keys actually removed, and a key that is gone
or listed twice is not counted.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JaA7tHy731qtvscjulrcfz
2026-10-16 13:55:29 +00:00
DWAA1660andClaude Opus 5.5 2c08f675c2 fix(engine): preserve edits when applying background analyses
Merge each offloaded property-group result against the snapshot the job started from. Preserve disjoint live edits, group identity and child changes; refuse conflicting results without changing the document or undo/redo history.

Record an apply rejection on its originating job so completion logs and waiting control commands report failure. Keep concurrent jobs' outcomes separate and retain the correct completion position when the bounded log rolls over.

Add actual-worker regressions for conflicts, disjoint edits, concurrent analyses and undo/redo, plus control completion/error regressions.

Fixes #1249

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 21:15:40 -06: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 37b681ac12 Merge pull request #1104 from eliasx45/upstream/import-project 2026-10-13 04:28:59 -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
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
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
pravdomilandClaude Opus 5.5 d444eceb90 Shortcuts: work area from the selection, most recent comp
comp.workAreaToSelection (Cmd+Alt+B) spans the selected layers, or the
whole composition with none selected. comp.activateRecent (Shift+Esc)
goes back to the composition that was active most recently within the
active one's nesting hierarchy; EditorState keeps recent_comps for it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 20:57:21 +02:00
pravdomilandClaude Opus 5.5 a644bb07c9 Shortcuts: go to the work area ends and to In / Out points
time.workAreaStart / time.workAreaEnd (Shift+Home / End) and
time.previousInOut / time.nextInOut (Cmd+Alt+Shift+Left / Right): the In
and Out points of the selected layers, of every layer with none selected.
time.go takes nextInOut and prevInOut.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 20:53:49 +02:00
vangel76andClaude Sonnet 5.5 8e5605d0e6 #1070: a fresh import or opened project reads footage files again
The media layer keys decoded frames by path, and nothing dropped them when a
new project (or a new import) named a file that another app had overwritten
since, so a same-size overwrite showed the old pixels. Importing footage and
replacing the project now make the media layer and the layer cache let go of
the files involved.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-12 20:22:48 +02:00
Elias 376f5757fc file.importProject: import an EffectCraft project into the open project
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)
2026-10-12 19:19:21 +01:00
Moein Saharkhiz 55ef2d05db #989: align pasted effect keyframes with the playhead 2026-10-12 10:26:35 -04:00
Brandon Thomas b2d05582e0 Merge pull request #462 from storytold/fix/417-viewer-resolution
Viewer: each composition keeps its Resolution in the project, as in After Effects (#417)

# Conflicts:
#	crates/ui-egui/src/control.rs
#	crates/ui-egui/src/menus.rs
#	crates/ui-egui/src/panels/viewer_tools.rs
2026-10-12 04:21:14 -04:00
Brandon Thomas 3f8af1a3b6 Merge pull request #863 from itrycodinganditsbad/fix-748
Save the active comp and open comp tabs in project files (#748)
2026-10-12 04:20:33 -04:00
Brandon Thomas 58b09391bd Merge pull request #789 from vangel76/gap-project-size-limits
#788: hold opened projects and size commands to the 30,000 px limits

# Conflicts:
#	crates/engine/src/commands/layer.rs
2026-10-12 03:22:54 -04:00
Brandon Thomas 909572dffd Merge pull request #785 from vangel76/gap-fuzz-project-open
#779: fuzz File > Open; refuse deeply nested XML projects
2026-10-12 03:22:51 -04:00
Brandon Thomas d9dddb90b7 Merge pull request #781 from vangel76/script-773-repeating-tasks
#773: run repeating app.scheduleTask tasks until cancelTask
2026-10-12 03:03:45 -04:00
Brandon Thomas bcb9ee1fa5 Merge pull request #764 from vangel76/gap-transition-presets
#757: Transitions animation presets in Effects & Presets
2026-10-12 03:03:31 -04:00
Brandon Thomas c72e47b7dc Merge pull request #761 from vangel76/gap-variable-font-filter
#741: font menu filters to variable fonts
2026-10-12 03:03:28 -04:00
Fabio LussiandClaude Opus 5.5 b0c0c61aa0 Save the active comp and open comp tabs in project files
Project files now record activeComp and openComps next to savedBy, and
file.open restores them, so a project reopens on the comp it was saved
on (desktop app, CLI and MCP all open through file.open). Older files
and ids that no longer name a comp fall back to the first comp; older
versions ignore the new keys.

Fixes #748

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 17:27:01 +02:00
vangel76andClaude Opus 5.5 765ba157be #788: hold opened projects and size commands to the 30,000 px limits
Problem: comp.new/comp.settings clamp sizes to 30,000 px, frame rates to
0.001-1000 fps and motion-blur samples to 2-64, but reading a project
(.ecproj and .ecprojx, templates, recovery, offload) accepted any value:
a 4-billion-px comp, solid or footage frame, a 0 or 10^18 fps rate
(zero-length frames), a negative duration or 4 billion blur samples all
reached the renderer. New Solid, Layer Settings, Import Solid/Placeholder,
Crop Comp and PSD import set sizes without the upper bound, and comp
sizes past 2^32 wrapped.

Fix: one set of limits in effectcraft_project::limits. Project::from_json
brings every item (and proxy) within them; from_json_repaired also says
what it changed, which file.open returns as `repaired` and shows in a
toast, so the project still opens. Project::add_item applies the same
limits to every new item, and the size-setting commands clamp with the
shared helpers.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 13:22:59 +02:00
vangel76andClaude Opus 5.5 b747ffc986 #779: fuzz File > Open; refuse deeply nested XML projects
Problem: nothing fuzzed project files. The hand-written .ecprojx XML reader
recursed once per nested <arr>/<obj> with no limit, so a deeply nested file
overflowed the stack and aborted the app instead of failing to open.

Fix: a dependency-free, deterministic, seeded mutation fuzzer for File > Open
(JSON and XML seeds from the demo, byte and JSON-structure mutations, the real
file.open path, first queries and a thumbnail render; each input under
catch_unwind with a deadline; bounded for cargo test, longer runs via env
vars). The XML reader now stops at the JSON reader's 128-level limit, with a
regression test.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 13:02:40 +02:00