Commit Graph
4432 Commits
Author SHA1 Message Date
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
13470ca161 Add affected CI and replayable crash repros (#1224)
* AG4: xtask ci --affected

cargo xtask ci --affected [--base REV] [--dry-run] runs fmt, clippy, tests (nextest + doctests when available), layers, assets (only on asset changes) and wasm (only for affected L0-L4/web crates) for the packages a change can affect: changed files map to the owning package and to packages whose sources read them via ../ paths, expanded to reverse dependents. Workspace-wide inputs (root Cargo.toml, Cargo.lock, .cargo/, xtask/, toolchain, clippy.toml) fall back to full CI. Documented in docs/testing.md, AGENTS.md and CLAUDE.md.

(cherry picked from commit f3ca84fc2ee3948582cbc94e4c99ee510e829540)

(cherry picked from commit 8a2cdcadf447eafa57ab14016beae4420f002af0)
(cherry picked from commit d8a4301bc1)

(cherry picked from commit 36402c61ac2f7e29ecd76a6cfc89365cc2572e0a)

* AO1: fast CI profile, looser timing tests

- [profile.ci] (release without LTO, 16 codegen units); `xtask ci` runs clippy
  and tests with --profile ci instead of --release.
- Wall-clock asserts in engine memory_tick, gpu OpenGL decline and script
  socket tests keep their intent with bounds that survive a loaded machine.
- docs/testing.md and CONTRIBUTING.md mention the profile.

(cherry picked from commit b45c8a379351ebdfda0d7076ad4b740baf6f2087)

(cherry picked from commit fa1ea6a107c4c1936cde89b518a05adc73f2b4b0)
(cherry picked from commit e5d5ed80e9)

(cherry picked from commit d2c67660c70764f9c56880a642ad7f0d004a7f92)

* AG6: journal replay repros

Bug reports become replay scripts and crash regression tests become data files:
- engine::replay: a JSON-lines repro format (start line, command steps with
  expect_error, expect queries with JSON pointer + equals, expect_no_error),
  a never-panicking runner that reports per-step ok/error and the first failure,
  and journal export (from the last project open; saves left out; size-capped).
- journal.export {path?} and help.exportRepro {path?} (not journaled).
- Crash capture: when the last-resort guard catches a panic in the outermost
  command, the journal plus that command is saved to Repros/crash-*.jsonl in the
  settings store (newest 20 kept) and the error names the file.
- Commands run by a journaled command (script steps) are no longer journaled twice.
- effectcraft-cli replay SCRIPT.jsonl [--json] [--keep-going]: exits 1 on a failed
  step, unmet expectation or panic.
- crates/host/tests/repros.rs replays every tests/repros/*.jsonl; three samples
  from past crash fixes (zero frame rate, Layer Settings with no selection,
  New Comp from Selection with hostile overlap).
- Docs: docs/agents.md "Repro scripts"; AGENTS.md: crash fix regression test =
  a .jsonl in tests/repros.

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

(cherry picked from commit c38509d7dafe507856c48c78db65e00b94b0cebc)

(cherry picked from commit e55b56dbf76716adfcbfe4cc773df19a74edc419)
(cherry picked from commit 96a63855a9)

(cherry picked from commit c59351ab3bd697f0868e41230dd883960d94a540)

* xtask: ci and ci --affected run cargo test and nextest with --no-fail-fast

One run now lists every failing crate instead of stopping at the first.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019qXL3GPNnY9BSFF2XoU2Yu

(cherry picked from commit e46c7debe738eca62b35bf7392ab77637f6a33ae)

* Agents: confinement write-checks journal.export, help.exportRepro and file.exportTimeline

Review on #859 (split into this PR): their output paths were only read-checked (relative ones
not at all). Test: confinement_covers_every_command_that_writes_a_file.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014d65YdNxQmjRkbXRtP2NwH

* #1224: handle bin-only CI targets and BOM repros without weakening timing tests

* #1224: run the full gate when nextest policy changes

---------

Co-authored-by: Elias <hakifx91@gmail.com>
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: FredApps <FredApps@users.noreply.github.com>
Co-authored-by: FredApps <153173854+FredApps@users.noreply.github.com>
2026-11-10 14:57:32 +01:00
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
FredAppsandFredApps 47e804f86f Fix launch guard ownership during concurrent startup (#1459)
* docs: track startup adapter recovery investigation (#477)

* Fix launch guard ownership during concurrent startup

* Launch guard (#477): fold the ownership tests into the tests module

Review cleanup, no behaviour change:
- Drop docs/issue-477-startup-recovery.md (investigation notes, not docs).
- Move the investigation_477 and root_patch_477_tests cases into the existing
  tests module under behaviour names, without println! output; every
  assertion is kept.
- Rewrap the module doc comment.

* #477: preserve inaccessible launch markers on Windows

---------

Co-authored-by: FredApps <FredApps@users.noreply.github.com>
2026-11-10 13:21:16 +01:00
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
nnaannoo 87000339ed Build: drop the unused egui patches and fail CI on [[patch.unused]] (#3404)
Removes the unused egui_demo_lib, egui_inspection and egui_system_font_provider patches and adds cargo xtask lock-patches to cargo xtask ci. Fixes #3403.
2026-11-10 15:13:16 +05:30
nnaannoo f31463abfe Build: take craft-libs at e11f9d9a so its workspace loads with current Cargo (#3351)
Moves the six craft-libs 92d392c pins to e11f9d9a so cargo vendor (and the Nix flake) can load the craft-libs workspace. Refs #3291.
2026-11-10 15:12:55 +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
ash 6a105aa285 Merge pull request #3392 from arnav-hiwarkar/feat/aep-drag-drop
File ▸ Import: drop or pick After Effects projects to import them; name the project imports alike (#3103)
2026-11-10 10:16:48 +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 93b69a8cf9 Merge pull request #3384 from storytold/release-0.23.1-version
Release: EffectCraft v0.23.1
2026-11-10 00:08:31 +01:00
FredApps 360e21f539 Release: EffectCraft v0.23.1 2026-11-09 23:36:18 +01:00
FredApps 308a906043 Merge pull request #3047 from MarekSpodBiedry/issue-3028
Preview: render at most two frames on the GPU at once so video memory stays flat (#3028)
2026-11-09 23:22:54 +01:00
FredApps 3c2a6d54f7 Merge pull request #1956 from ded-achtung/g5-near-camera-1388
#1388: 3D text and shapes rasterise only the part the frame shows
2026-11-09 23:21:49 +01:00
FredApps 5909f9cf76 Merge remote-tracking branch 'origin/main' into maintainer/1956-raster-20261109 2026-11-09 22:54:41 +01:00
FredApps 2d6d08f29f #1388: retain whole text raster for animator blur 2026-11-09 22:54:40 +01:00
FredApps 4ed549588e Merge pull request #3377 from FredApps/fix/3357-crash-diagnostics
Report unexpected desktop exits with local diagnostics
2026-11-09 22:28:13 +01:00
FredApps 8d9d9c446b #3357: preserve concurrent session log identity 2026-11-09 22:04:08 +01:00
FredApps 47c9b4a99b #3357: finish crash reporter after accepted macOS teardown 2026-11-09 20:58:45 +01:00
FredApps 59c41fee0a #3028: keep dedicated preview lanes waiting on GPU admission 2026-11-09 20:21:23 +01:00
FredApps fc4bcd21d4 #3357: report unexpected desktop exits with local diagnostics 2026-11-09 20:15:19 +01:00
FredApps 989b37b1d1 #3028: reconcile GPU admission with current preview workers 2026-11-09 19:42:59 +01:00
FredApps 636dc1578c #1388: synchronize current main and retain raster regression modules 2026-11-09 19:14:30 +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 d643e7f8f0 #1388: distinguish fine raster clips and update layer test fixtures 2026-11-09 18:55:46 +01:00
FredApps e8634b1f4b #3357: release retired GPU resources before CPU fallback 2026-11-09 18:41:39 +01:00
FredApps 9ce936d197 Merge pull request #3360 from FredApps/fix/3357-drop-shadow-cover
#3357: avoid whole-layer cover for Drop Shadow
2026-11-09 18:31:49 +01:00
FredApps 38e7b5e16b #1388: integrate raster clipping and preserve whole-layer consumers 2026-11-09 18:17:25 +01:00
FredApps 45e81e603e #3335: isolate proxy caches and settle small render batches 2026-11-09 18:16:57 +01:00
FredApps 43e82587fd #3357: avoid whole-layer cover for Drop Shadow 2026-11-09 18:10:06 +01:00
FredApps d07aed85c3 Merge pull request #3355 from arnav-hiwarkar/fix/3345-gpu-preview-lanes
Preview: the window stays smooth while lanes render on the GPU (#3345)
2026-11-09 16:49:13 +01:00
vangel76 d77d978973 Merge remote-tracking branch 'upstream/main' into rq-readback-3335
# Conflicts:
#	crates/render/src/lib.rs
2026-11-09 16:06:16 +01:00
arnav-hiwarkar 9a0a198ff1 Preview: the window stays smooth while lanes render on the GPU (#3345)
Since #595 (v0.19.0) a playing preview and Cache Frames When Idle render one frame per
lane, a lane per core, each recording, submitting and reading back a whole frame on the
GPU the window draws with. On a GPU that can't keep up, the window froze for hundreds of
milliseconds to seconds and the playhead jumped ahead when it came back.

Lanes now take a GPU frame only while fewer than a limit of them composite. The limit
starts at one lane and adapts to the window's frame gaps while a preview plays: a stall
(>100 ms) with lanes compositing halves it, half a second of smooth frames (<50 ms) with
every allowed lane busy adds one, up to every lane; a limit that stalled is tried again
only after 10 s. Frames on the CPU (Software Only, no or retired GPU, GPU memory
pressure) and disk-cache hits use every lane; the pool and the viewer's frame are not
limited, and frames ahead of the playhead still start first.
2026-11-09 19:58:51 +05:30
just_anshhandjustanshh 544eebf904 WebAssembly ABI 2: neighbouring frames for effect plug-ins (#2773) (#3329)
* WebAssembly ABI 2: neighbouring frames for effect plug-ins (#2773)

A wasm plug-in can export ec_api_version 2 and ec_render2 to receive the layer's previous and next frames, their layer times and validity flags. Neighbours come from PluginHost::input_at, are resampled onto the current grid, and are zeroed when absent. ABI 1 modules (ec_render) load and render unchanged; the manifest api stays independent. A layer with an ABI 2 plug-in keys the render cache on layer time; the Plug-in Library accepts ABI 1-2 releases. Docs, help text and tests updated.

* Fix ABI 2 neighbour times on NTSC frame boundaries

	ime * fps is often a few ulps off an integer at rates such as 24000/1001. The old boundary test then took the bracket branch and passed the current frame back as prev (or
ext). Treat a near-integer as a frame boundary within 1e-6 frames, and test 2400 frames at 24000/1001: every boundary must get the frames either side. Also document the loader helpers for the docstring coverage check.

---------

Co-authored-by: justanshh <294019246+justanshh@users.noreply.github.com>
2026-11-09 10:49:53 +01:00
Dylan M. Taylor 81a12ffffc Merge pull request #3340 from dotCooCoo/chore/craft-update-1b34eba41
Updates: take craft-update from craft-libs main at 1b34eba41
2026-11-08 23:25:07 -05:00
dotCooCoo 91f35c73e1 Updates: restart from the update result dialog 2026-11-08 20:01:20 -08:00
Valentin Klein 7c62272305 .aep import: placed .ai/PDF footage framed by its ArtBox, Null anchors at the corner (#3099) (#3311)
* #3099: placed .ai pages fill the size After Effects stored; null anchors default to the corner

Footage of an .aep keeps the size After Effects stored for a placed PDF / Illustrator / EPS
file (the ArtBox, rounded up), and masks and anchors are measured against it. The page was
drawn as a PDF viewer frames it (CropBox, /Rotate) at its own size, scaled by the width ratio
at full resolution and stretched to the stored aspect below 3/4: masks too large, art off
centre, squeezed at half resolution.

- effectcraft-pdf: Framing::Placed / parse_page_framed (ArtBox clipped to the CropBox,
  /Rotate ignored); boxes with a non-finite corner or span are not used
- Footage::placed_page (set by the .aep importer, serialized only when true): the page is
  framed so and filled into the stored size (effectcraft_render::vector_fit), decoded,
  continuously rasterised and in Create Shapes from Vector Layer; Reload keeps the size;
  the frame cache keys it by size and framing
- .aep import/export: a null's absent Anchor Point is [0, 0], as After Effects reads it
- fixture ai-mask-3099.aep (own synthetic files, scrubbed, profiles stubbed) and tests
  against After Effects 2026's read-back

* #3099: placed-page framing only for .ai and .pdf, EPS as before; doc comments

After Effects' sizing was measured with PDFs named .ai only; an EPS from an .aep keeps its
bounding box at its own size (listed as not measured in docs/gaps.md and docs/aep-import.md).
Doc comments on the touched functions.

* #3099: shapes from a placed page keep its frame (track matte)

Create Shapes from Vector Layer converted every path of a placed page, so bleed, art past the
artboard or the page's background showed where the footage's raster hides them. The layers it
makes from a placed page now take a hidden "<layer> Frame" shape layer (the footage's
width x height) as their Alpha track matte: drawn at the comp's resolution, its edge is the
raster's on shape and image layers alike. The command returns the frame layer's id too.
2026-11-08 21:52:32 -06:00
FredApps 9893eb0d8d Naming: descriptive names for the CC effects, Lumetri, Mocha, Keylight and Mercury (#3327)
Related to #1365. Display labels only; effect, command, parameter, panel and serialized ids and the AEP/script match-name tables are unchanged.

- 69 Cycore CC effects, Key Light, Mocha shape, Lumetri Color/Scopes and the Mercury renderer labels get descriptive names; the old names stay case-insensitive lookup and search aliases.
- Backend::parse accepts the new renderer labels, so reported settings round-trip.
- Display names are unique per language in every effect catalog (new test).
- Warp Stabilizer and Roto Brush keep their names until RFC-0029 settles.
- Mapping in docs/feature-naming.md.
2026-11-09 04:51:10 +01:00
dotCooCoo 9253b5bdc6 Updates: take craft-update from craft-libs main at 1b34eba41 2026-11-08 19:47:28 -08:00
vangel76 74ac5a2f26 #3335: choose the GPU frames in flight from measured GPU memory, with a Memory & CPU setting 2026-11-09 02:04:15 +01:00
vangel76 e0154351f3 #3335: time the CPU on up to eight frames in parallel when choosing the renderer 2026-11-09 01:18:49 +01:00