Commit Graph
1739 Commits
Author SHA1 Message Date
Dylan M. Taylor cbddc9d284 Fix Flatpak updates and bump to 0.24.1 (#3516)
* fix(flatpak): allow release checks and self-update helpers

* test: keep Flatpak permission parsing within strict Clippy rules

* chore: bump version to 0.24.1 for the Flatpak update fix
2026-11-11 15:25:13 -05:00
Dylan M. Taylor 20ed10da5f Shortcuts: list each binding once and cap the conflict list (#2997)
* fix(shortcuts): list each binding once and cap the conflict list

* address review: compute the shortcut bindings once per keyboard draw
2026-11-11 14:37:29 -05:00
Dylan M. Taylor eece065426 UI: ScriptUI images decoded within a size limit; effect detection answers each comp once (#3005)
* UI: ScriptUI images decoded within a size limit; effect detection answers each comp once

ScriptUI decoded any image and converted it to full RGBA without a size
check; images are decoded through image's limits (4096 px per side and a
matching allocation cap). comp_has_effects walked a nested comp again for
every layer using it; each comp is now answered once.

* address review: effect detection by breadth-first search so depth cannot hide a comp
2026-11-11 14:36:58 -05:00
arnav-hiwarkar f6b4da0aeb Merge remote-tracking branch 'upstream/main' into fix/3365-aep-loss-report
# Conflicts:
#	crates/aep/tests/it/import/synthetic.rs
2026-11-11 17:19:01 +05:30
ash 367ef1f031 Merge pull request #3445 from arnav-hiwarkar/fix/negative-start-time-entry
Time entry: a negative displayed timecode goes to the frame it shows (#3373)
2026-11-11 17:15:14 +05:30
arnav-hiwarkarandClaude Opus 5.5 6b7731d05a #3365: the losses prompt shows every detail line and how many have none
The prompt showed 3 detail lines per category under a bare count, which read
as the project's total. The headline now says how many occurrences are left
out or changed, every line the report keeps shows, and "… and N more" counts
the rest. The import report records that number as `unlisted` (an unmapped
effect's line covers all its instances); unmapped effects are listed most
used first.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-11 16:45:55 +05:30
FredAppsandClaude Opus 5.5 47fc00f85d test(ui-egui): split the crypto-pick viewer matrix into one test per window size
picks_what_the_viewer_shows_across_sizes_scales_zoom_pan_resolution_and_proxies looped over four
independent window-size and display-scale cases, each with its own session. As one test it took
~90 s in the gate and ~590 s under coverage, where it alone set the slowest SonarCloud shard.

Each case is now its own test, running the same checks, so nextest runs them in parallel and
partitions them across shards. The "more than 100 hovers checked" floor becomes more than 25 per
case, which still adds up to more than 100.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-11 11:58:07 +01:00
arnav-hiwarkarandClaude Opus 5.5 5922dabd3a Time entry: a negative displayed timecode goes to the frame it shows (#3373)
In a comp whose Start Timecode is negative, the current-time display shows
the first frames as `-0:00:00:12`, but typing that back (the Go to Time
dialog opens with it since #3419, and the Timeline's time field takes it)
read the leading `-` as "move back", so OK on an unedited dialog jumped to
another frame. There, a `-` before a full timecode is now the time's sign,
as it already is before Feet + Frames; a bare `-n` still steps back, and
comps that start at 0 or later are unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-11 16:19:46 +05:30
ash 6aca5e473c Merge pull request #3419 from nanox333/fix/3373-viewer-time-click
Viewer: clicking the current-time display opens Go to Time (#3373)
2026-11-11 16:01:30 +05:30
nazar-gavrylyk abdf4c369a Settings: move the playhead onto layers the tools fit to the work area
With Fit New Layers to Work Area on and the playhead outside the work
area, the Type tool, shape tools and Pen now move the playhead to the
work area start so the new layer and its controls show. Layer timing is
unchanged; Layer ▸ New commands leave the playhead.
2026-11-11 08:34:05 +01:00
FredApps f85f18e0b4 Merge pull request #3401 from nazar-gavrylyk/fix/first-playback-lag
Preview: smoother first playback of uncached comps
2026-11-10 18:36:23 +01:00
FredApps 9eb9ac003b Preview: end the small-RAM-preview pacing test with a newline (cargo fmt) 2026-11-10 17:56:26 +01:00
FredApps 114fbaed63 Preview: the pace measures its lead over no more frames than the RAM preview holds
The pace counted cached frames among the next ahead x 2, but the prefetch never requests more than the RAM preview holds (offsets 0..fit-1 from the current frame). With room for only a few frames the lead could never fill, so a preview that rendered every frame at once was slowed to a fraction of its frame rate, with Lower Resolution When Playback Can't Keep Up off (the default). The lead is now counted over at most the frames the prefetch keeps after the current one, and with none of those (room for at most two frames) the clock runs in real time as before pacing.
2026-11-10 17:22:44 +01:00
Claude ddb8c958a0 Go to Time: show and take the time as the project displays it (#3373)
The dialog's Frame field held the engine's zero-based frame, so with frames shown
from 1 the viewer's 00013 opened as 12, and typing 13 went to the frame displayed
00014. It now holds the time in the project's display style (timecode, frames from
Start Numbering Frames At, or feet + frames), which time.set already reads that
way. The now-unused 'Frame' translation rows go.
2026-11-10 15:49:40 +00:00
nazar-gavrylyk e356e4adf5 Preview: a stall after playing at full rate still steps down a resolution
The step-down was skipped while the achieved frame rate read as keeping up, and that rate comes from the frames shown in the last second they were shown: through a stall it kept the rate from before it, so a preview that played a cached stretch and then stalled never stepped down. A rate whose last frame is more than a second old no longer counts.
2026-11-10 15:58:42 +01:00
Claude 22b04320a4 Viewer: clicking the current-time display opens Go to Time (#3373)
The time display in the Composition panel's bottom bar only reacted to
Ctrl/Cmd+click, which switches timecode and frames. A plain click now opens the
Go to Time dialog (View > Go to Time), as in After Effects. The Ctrl/Cmd+click
test follows: its plain click now opens the dialog, which it closes.
2026-11-10 14:48:14 +00:00
ash b23bbf927f Merge pull request #3412 from arnav-hiwarkar/fix/1828-timeline-layer-snapping
Timeline: Shift-dragging a layer bar snaps to layer ends, the current time, markers and keys (#1828)
2026-11-10 20:10:39 +05:30
FredApps 9143393ce5 #945: play preview audio at the selected frame rate (#3416) 2026-11-10 15:26:21 +01:00
nazar-gavrylyk 513d5eaea7 Preview: Lower Resolution When Playback Can't Keep Up is off by default
It never steps back up during a play, so a looping preview kept playing at a quarter of its resolution after its first loop. Without it the paced first loop caches the viewer's resolution and the next loops play in real time, as in After Effects. The setting stays for whoever prefers a lower first pass.
2026-11-10 15:10:24 +01:00
nazar-gavrylyk b18bf9186a Preview: GPU admission's reasoning holds for lanes four threads wide
Only a lane's drain thread waits for a GPU slot. A lane runs one drain at a time (it is idle, and started again, only once its drain found no job), and its other threads only help with that frame's parallel work, as Rayon helpers that never wait. The comments said lanes had one thread; the test now runs on a lane LANE_WIDTH wide and checks that its other threads decline while the drain thread waits.
2026-11-10 15:09:40 +01:00
nazar-gavrylyk db21c733b4 Auto: a frame's ticket ends it on every exit
AutoPick::ticket chooses a side and reports the frame's time once; dropped without one it ends the frame unmeasured. The viewer's frames, the renderer's top-level frames and frames rendered in passes use it, so an Auto CPU frame turned away by GPU admission (#3028), a cancelled export frame or any later exit no longer leaves its frame counted as running. The frame server keeps its choice across calls and still ends a replaced frame itself.
2026-11-10 15:07:57 +01:00
nazar-gavrylyk bbc5f9889d Preview: a cached end of a preview that doesn't loop plays in real time
The paced clock counted the cached lead out of twice the prefetch depth even when fewer frames were left before the end, so a fully cached preview that doesn't loop slowed down over its last frames, and one shorter than that depth played slow throughout (and could step down). The lead now counts out of the frames left.
2026-11-10 15:04:01 +01:00
nazar-gavrylyk 396495dfa0 Auto: frames that end without a time stop counting as running
A GPU frame that failed or failed its health check, and a remote frame replaced before it finished, stayed counted as running on its side, so every later frame there was timed as one of several side by side and that side looked cheaper. AutoPick::abandoned releases them.
2026-11-10 15:04:01 +01:00
nazar-gavrylyk b3000aac70 Preview: playback runs at the pace frames arrive when it can't keep up 2026-11-10 15:03:10 +01:00
nazar-gavrylyk 3709cccedf Preview: frame lanes are four threads wide, and cache_bench measures the cadence 2026-11-10 15:03:10 +01:00
nazar-gavrylyk 893d9a0b04 Preview: playback steps down a resolution when it can't keep up
Settings > Previews > Lower Resolution When Playback Can't Keep Up (on by
default): a preview at Resolution Auto that stalls on uncached frames and
shows under 80 % of its frame rate for two seconds plays on at half the
scale, and two seconds later at a quarter if still slow, no lower than the
Adaptive Resolution Limit. Stopping goes back to the viewer's resolution
and Cache Frames When Idle fills it in. An explicit Resolution, the comp's
or the Preview panel's, is kept as set.

First playback of a 1080p comp with a blur (cache_bench --play): 9.0 to
22.1 frames/s on the CPU (about 27 once at Half), 4.1 to 16.1 with Mercury
Auto on an integrated GPU; plain clips that keep up stay at Full.
2026-11-10 15:03:10 +01:00
nazar-gavrylyk cc4f834a94 cache_bench: --play measures a first playback in the app
--play SECS runs the app headless (egui_kittest) on the bench comp, with
the viewer at 100 %, Resolution Auto, nothing cached and Cache Frames When
Idle off, presses play and steps it for SECS seconds of wall time. It
prints the frames shown per second, the time the clock stalled on uncached
frames, the frame reached and the share of passes at each viewer scale.
--gpu composites on the GPU (Mercury Auto) as the desktop app does;
--res N sets the comp's Resolution to every N-th pixel.
2026-11-10 15:03:10 +01:00
nazar-gavrylyk 6bb52b1cb1 cache_bench: --gpu measures the GPU compositor
--gpu renders on a headless GPU of its own and reads the frames back, as the
desktop viewer does; --backend cpu|gpu|auto picks the compositor (default
auto, the viewer's Mercury GPU Acceleration). With auto the bench prints
Auto's per-comp timing history: how many frames each side rendered and how
long they took.
2026-11-10 15:03:10 +01:00
nazar-gavrylyk 87bfaa8f1c Preview: Cache Frames When Idle is on by default, as in After Effects
A comp left alone for a second fills its RAM preview from the current time,
so the first playback is cached instead of rendering frame by frame. Saved
settings keep their value. Two UI tests that assumed the old default set it
explicitly.
2026-11-10 15:03:10 +01:00
nazar-gavrylyk 38dffd4aea Disk cache: frames and layer buffers are compressed on the writer thread
A render thread handed each frame to the disk cache already copied pixel by
pixel and LZ4-compressed (~9 ms per 1080p frame) before it could start the
next one, and layer buffers were encoded even when the queue then dropped
them. The queue now holds raw RGBA (one memcpy via ColorImage::as_raw) and
Arc<Buf>s; the writer thread encodes them. Every frame of a 120-frame bench
run now reaches disk (113–119 before). cache_bench prints the flush time.
2026-11-10 15:03:10 +01:00
arnav-hiwarkarandClaude Opus 5.5 d0eb89904c Timeline: note that a snapped bar edge off the frame grid lands within half a frame (#1828)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-10 19:26:51 +05:30
arnav-hiwarkarandClaude Opus 5.5 3c6abe3606 Timeline: a Shift-drag on an unselected bar moves the whole selection (#1828)
A Shift-press on an unselected bar adds it to the selection, so the drag now moves that
selection and its layers are no snap targets. Tests cover the selection drag and that a
moved layer's own marker is no target.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-10 18:44:24 +05:30
FredApps f88e7980ae Merge pull request #2162 from MarekSpodBiedry/issue-2104
Make the audio preview follow mute changes made during playback (#2104)
2026-11-10 14:10:00 +01:00
FredApps 8b9f9e6943 Capture observed process and GPU failure evidence (#3409)
* #3357: retain process, memory and typed GPU failure evidence

* #3357: tighten reporter protocol regression cases
2026-11-10 14:05:57 +01:00
FredApps d047d89b9a #2104: document audio comparison and regression contracts 2026-11-10 13:36:17 +01:00
arnav-hiwarkarandClaude Opus 5.5 3f3031d941 Timeline: Shift-dragging a layer bar snaps to layer ends, the current time, markers and keys (#1828)
Moving a layer bar or dragging its In / Out end with Shift held snaps the moved edge, within
8 px of the pointer, to the current time, comp and layer markers, visible keys, the work area,
the comp's start and end, and other layers' In / Out points, as in After Effects. The edited
layers' own ends are no targets (nor, when moving, their markers and keys). Targets are
gathered once per drag; snapping is measured from the pointer, so dragging on lets go.
Without Shift a drag moves by the whole frames the pointer covered, as before.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-10 17:54:46 +05:30
FredApps 31da676415 #2104: bound audio comparisons across reused precomps 2026-11-10 13:10:10 +01:00
FredApps 9d504f6722 #2104: synchronize live audio edits and restore silent previews
Merge current main while preserving continuous audio and prefetch behavior. Fix sibling method visibility, audio-only unmute, queue/cursor handoff, end-of-span replay, and expression-driven audio invalidation. Add mixer and preview-output regression coverage. Formatting checked; builds and tests run in hosted CI.
2026-11-10 13:07:43 +01:00
ashandClaude Opus 5.5 d9fde92d83 Viewer: a click selects the topmost layer over a selected one (#3389) (#3405)
* #3389: a viewer click selects the topmost layer over a selected one

Clicks in the viewer went through pick(), which prefers a selected layer
under the pointer so a covered layer can be dragged (#230). A large
selected layer lower in the stack therefore captured every click inside
its bounds, and the layers in front of it could not be selected there
(#1535, #3389).

Add click_pick(), the same hit test without that preference: the
topmost layer, keeping the selection when it is already selected. The
left click (Selection and fallback tools, Roto Brush), the double-click
and the right-click menu use it; drag starts keep pick(), so dragging a
covered selected layer works as before.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* #3389: rustfmt the viewer's shapes imports

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* #3389: test the right-click where both layers cover the pointer

The right-click check ran after the drag had moved the layer behind out
from under the pointer, so the old pick() passed it too. It now runs
before the drag with the layer behind selected, then closes the menu.
pick()'s doc names the Puppet tool's pin placement as a click that uses it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* #3389: a click on a covered path of the selected layer keeps that layer

With clicks going to the topmost layer, a click on a mask or shape path
of the selected layer where a layer in front covers it selected the
layer in front. Its paths went away, so a double-click there could no
longer free-transform the path. A plain click on a shown path now stays
on its layer, as pick() did; Shift-click still toggles the topmost one.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* #3389: a right-click on a covered path of the selected layer keeps it

The context menu picked as a left click did before the path fix, so a
right-click on the selected layer's path, under a layer in front,
selected the layer in front. It now keeps the path's layer like a left
click. pick() and click_pick() docs describe the Puppet and path
exceptions exactly.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-10 17:31:34 +05:30
ash bb908a6ae3 Merge pull request #3393 from arnav-hiwarkar/fix/keyframe-marquee-scroll
Timeline: keep marquee selection anchored while scrolling
2026-11-10 11:53:07 +05:30
arnav-hiwarkarandClaude Opus 5.5 58a1f3df17 #2859: test the real marquee selection path
The unit test re-implemented Marquee::selection's box/outline split, so it
only covered `targets`. Move the anchor math into `Anchor::press` /
`Anchor::selection` over a plain `View`, call it from the test, and add a
scrolled-drag case that fails with a screen-fixed anchor.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-10 11:01:42 +05:30
arnav-hiwarkar 384184a12b #2859: document marquee gesture contracts and regression cases 2026-11-10 09:40:22 +05:30
arnav-hiwarkar eec3c51296 #3103: doc comments for the touched import and prompt functions 2026-11-10 09:35:56 +05:30
arnav-hiwarkar 51ef332c05 #2859: keep timeline marquee anchored while scrolling 2026-11-10 09:23:04 +05:30
arnav-hiwarkar 9e58108288 #3103: import dropped and picked After Effects projects; name the project imports alike
Dropping an .aep or .aepx on the window, or picking one in File > Import > File...
or Multiple Files... (also from the Home screen and the Project panel), imports it
as File > Import > Adobe After Effects Project... does, instead of failing as
unsupported footage: the losses prompt first when parts cannot come over, its
items in a folder named after the file, its first composition open.

- Several projects are asked about one at a time: the others wait in the
  prompt's queue, and Cancel skips only the one it asks about. A prompt another
  dialog replaced (Save changes?) strands nothing: its projects are tried with
  the next import or queued behind the next prompt.
- The other files of a drop or pick import as footage, into the Project panel
  only when a project is in the drop. While the prompt shows, a Photoshop file
  or image sequence imports with its defaults instead of replacing the prompt,
  an Interpret Footage question leaves a note instead, and a dropped .ecproj is
  skipped with a note. While Save changes? waits for a dropped .ecproj, the rest
  of the drop is skipped with a note instead of landing in the replaced project.
- Errors of every picked project reach the status line on both the blocking and
  the non-blocking file dialog.
- The Import File dialogs list .aep, .aepx, .ecproj and .ecprojx; Replace
  Footage offers footage only.
- For scripts and agents, file.import hands After Effects projects to
  file.importAep; a refusal (new EngineError::Refused) names the menu entry and
  `file.importAep` with `allowLosses`.
- File > Import / Export name the entry Adobe After Effects Project..., as
  Adobe Premiere Pro Project...; File > Import keeps After Effects' order with
  the project imports together and the formats only EffectCraft imports after a
  separator. All 13 menu catalogs and the losses dialog title are updated.
- Docs: aep-import, aep-export, footage, file-format-parity, agents.

Supersedes #3312.
2026-11-10 08:49:26 +05:30
FredApps 59c41fee0a #3028: keep dedicated preview lanes waiting on GPU admission 2026-11-09 20:21:23 +01:00
FredApps 989b37b1d1 #3028: reconcile GPU admission with current preview workers 2026-11-09 19:42:59 +01:00
FredApps 1197414255 Merge pull request #3363 from FredApps/fix/3357-gpu-fallback-exit
#3357: release retired GPU resources before CPU fallback
2026-11-09 19:10:21 +01:00
FredApps 5207194f30 Merge pull request #3336 from vangel76/rq-readback-3335
GPU render speed: footage uploaded once per frame, single-copy readback, Render Queue picks the faster renderer (2.6× on a 1080p EXR job)
2026-11-09 19:00:20 +01:00
FredApps e8634b1f4b #3357: release retired GPU resources before CPU fallback 2026-11-09 18:41:39 +01:00