Commit Graph
1189 Commits
Author SHA1 Message Date
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 48afb082d5 refactor(engine): move src/remote.rs tests to src/remote/tests.rs 2026-10-26 21:49:11 +00:00
aiongg fd2c828670 refactor(engine): move src/offload.rs tests to src/offload/tests.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
aiongg 887af7f2c6 refactor(engine): move src/commands/mod.rs to src/commands.rs 2026-10-26 21:49:10 +00:00
Dylan M. Taylor c618429252 Sonar: reduce cognitive complexity in footage reload, edit delete and text layout 2026-10-26 16:01:49 -04:00
vangel76andClaude Opus 5.5 236e8c87ae Merge main into rfx-text
Conflict in crates/text/src/layout.rs (paragraph direction at the top of
paragraph()), against the closure-to-method-path cleanup (4e9fa51f): kept this
branch's direction resolved once from BidiInfo.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-26 15:30:09 +01:00
Minher0 0539098887 Environment lights: review fixes — edit keeps Classic 3D, NaN sun guarded (#2436)
Three small fixes from the review of the shadow commit:

- light_settings switched a Classic 3D comp to Advanced 3D whenever the
  edited light was an Environment light (the resulting kind), so editing
  the intensity of one in a comp the user had switched back to Classic 3D
  dragged the renderer back. The switch now happens only on the
  non-Environment to Environment transition (the sources before and
  after), matching the docs; ordinary edits leave the renderer to the
  user.
- dominant_direction's thresholds let NaN through (every NaN comparison
  is false): a NaN or infinite texel produced a NaN sun direction and
  NaN shading with it. A non-finite weight or length now returns no
  direction — garbage casts no shadow.
- add_environment walked the full-resolution image for the dominant
  direction even when the light casts no shadows, where nothing reads
  it. Only a shadow-casting light pays for the pass now.

Tests: editing an existing Environment light in a Classic 3D comp keeps
the renderer and stays toast-silent; a NaN and an infinite environment
image yield no sun direction.
2026-10-26 13:40:53 +00:00
Minher0 863f0e49c1 Render the Environment light's shadow from its image (#2436)
The Casts Shadows option Environment lights got is only half a fix if
nothing shades for it: an image lights the scene from every direction,
and what occludes that light is the image itself — its dominant bright
region, the sun in a sky map.

- dominant_direction finds it: the radiance-weighted mean texel
  direction (solid-angle weighted, rotation applied). A uniform image
  cancels to zero — a flat default environment shines from everywhere
  at once and casts no shadow, which a uniform environment test pins.
- The shadow is one orthographic map over the scene from that
  direction, after the lights' maps, like a parallel light's: PCF
  widened by Shadow Diffusion, darkened by Shadow Darkness, cleared
  when nothing casts, the image is directionless, or the texel budget
  drops it.
- It darkens the environment's own diffuse and specular light on
  Accepts Shadows surfaces and counts in Cast Shadows Only. CPU and
  GPU (WGSL) do the same; Globals carries the environment's sun
  direction and shadow settings (40 → 44 floats, preflight updated).

A bright-disc environment turned to shine from behind the camera now
shadows a sphere onto the floor behind it, Cast Shadows off lights it
evenly again, and the GPU scene's sky gradient takes a shadow-casting
Environment light. Also: the renderer-switch toasts read "...renderer,
which draws 3D models", the dialog's Casts Shadows checkbox gets an
auto id (dialog.light.casts) the tests click, and the docs' Environment
notes cover the shadow.
2026-10-26 13:05:16 +00:00
ashokram-si c51a08ceb4 Export: Targa (.tga) sequence output, 24-bit RGB or 32-bit RGB + Alpha
After Effects lists Targa among its still-image output formats; EffectCraft
imported Targa (#745) but could not render to it.

- OutputFormat::TargaSequence ("Targa Sequence", `.tga`, numbered like the
  other sequences; `tga` / `targa` as a format name or output extension).
- Written by the `image` crate's Targa encoder (its `tga` feature, already
  enabled in effectcraft-media; no new crates, Cargo.lock unchanged), with
  run-length compression off: an 18-byte header, top-left origin, 24-bit BGR
  for RGB, 32-bit BGRA with 8 alpha bits in the image descriptor for
  RGB + Alpha (straight or premultiplied), 8-bit grey for Alpha.
- The render queue's size estimate counts the uncompressed bytes.
- CLI usage, the renderQueue command specs, README, architecture.md and
  file-format-parity.md name the new format.

Tests: each Targa frame holds exactly the pixels of the PNG sequence of the
same job, with the expected header, numbering and size; the frames read back
through the Targa importer as the same picture (straight, and premultiplied
when interpreted so); the image-sequence round trip, the format parser and
the renderQueue commands cover it too.
2026-10-26 15:34:12 +05:30
Minher0 1599790ac9 Light Environment lights: default environment, Casts Shadows, Advanced 3D switch (#2436)
An Environment light had no visible effect, and its Light Settings dialog had
no Casts Shadows option — both halves of #2436.

No effect had two causes:

- Classic 3D (the default for new comps) skips Environment lights entirely,
  so creating one did nothing. Adding one (or changing a light's type to it)
  now switches the comp to Advanced 3D in the same undo step, with a toast,
  exactly as model and primitive layers already do; switching back to
  Classic 3D with an Environment light in the comp explains itself too.
- In Advanced 3D, a light with no Source and no Environment Layer produced no
  environment at all. It now falls back to a flat default environment of the
  light's colour × intensity, as After Effects does, so the light always
  lights the scene per its parameters.

Cast Shadows was missing because the dialog and the light's property groups
shared one gate (Falloff and Shadows together) that excluded Environment.
The two are now split: every light but Ambient gets Casts Shadows, Shadow
Darkness and Shadow Diffusion (stored, edited and carried over on type
changes), while Falloff stays on Parallel/Spot/Point only — an environment
light shines from every direction at once and has no use for a falloff.

Tests: the renderer lights a card from a sourceless Environment light (colour
and intensity drive it, zero intensity lights nothing), the engine switches
Classic comps to Advanced 3D on creation and type change (one undo step,
toast, and the Classic 3D switch-back toast), Environment lights take and
carry shadow options but no Falloff, and the dialog ticks Casts Shadows on
a new Environment light.
2026-10-26 09:43:47 +00:00
skylar taylor-barrick 69b9ce2bd1 M0.37: reconcile shared docking and qualify migration follow-up 2026-10-26 06:47:07 +01:00
dotCooCoo f23272f725 Merge #2352: Proxies: a composition proxy draws with Separate Fields, Invert Alpha, linear light and Frame Blending 2026-10-25 20:17:15 -07:00
dotCooCoo 4dd93bf065 Merge #2336: Animation presets: effects saved by an earlier version are upgraded on apply, as in a project 2026-10-25 20:17:14 -07:00
dotCooCoo b8f90cb9e5 Merge #2309: Interpret Footage: the params docs list every key the commands read 2026-10-25 20:17:13 -07:00
dotCooCoo 8ebacda419 Shapes: Wiggle Paths has Spatial Phase, which slides its wiggle along the path
Wiggle Paths had Size, Detail, Points, Wiggles/Second, Correlation,
Temporal Phase and Random Seed, but no Spatial Phase, which After
Effects lists among its properties (ADBE Vector Spatial Phase). Spatial
Phase now moves each point's own displacement along its subpath: 360
degrees is once around, and a fraction of a point is interpolated
between neighbors. At 0 degrees a path draws as before.

A project saved without the property gets it at 0 degrees, after
Temporal Phase, when it opens. Scripts can read and set every Wiggle
Paths property by its match name.
2026-10-25 16:06:28 -07:00
skylartaylor f842a58a4f M14: clarify text selection and footage playback contracts 2026-10-25 22:25:40 +01:00
Dylan M. Taylor e821feeec4 Merge pull request #2274 from storytold/sonar/rust-s4325-s1612
sonar: method paths instead of closures (rust:S1612)
2026-10-25 16:36:06 -04:00
skylar taylor-barrick 47bf08a15e M-egui037: document migration behavior and guard atomic batch rollback 2026-10-25 19:56:09 +01:00
tylerjenningsw 9b57090b00 Merge main into enhance/batch-parent-matte 2026-10-25 14:54:57 -04:00
tylerjenningsw 653a63c0b1 Merge main into enhance/pickwhip-index-refs 2026-10-25 14:26:30 -04:00
tylerjenningsw a2f3ac41b1 Merge main into enhance/avi-import 2026-10-25 14:26:28 -04:00
tylerjenningsw 86907e9a3a Merge main into enhance/keyframe-text-clipboard 2026-10-25 14:09:38 -04:00
Dylan M. Taylor e88feff569 engine.batch: drop the events a rolled-back atomic batch queued
A failing atomic batch restored the project, history and state but left the
events its steps had already published, so the UI could open the comp the
rollback had just undone. Snapshot the event count with the other snapshots and
truncate before the rollback bumps.

🤖 Generated with Codebuff
Co-Authored-By: Codebuff <noreply@codebuff.com>
2026-10-25 13:14:28 -04:00
Kushagra Kumar 59b564326e fix(engine): default transparent to true in queue_frame 2026-10-25 19:51:06 +05:30
Kushagra Kumar 5d25346547 fix(engine): propagate transparency setting to queued frame saves 2026-10-25 19:31:46 +05:30
Minher0 b50e74f295 layer.create: every instance3d copy in one undo step
The op ran Session::edit once per selected layer, so each copy was a history
step of its own: undoing removed them one at a time. Collect the eligible
models first and create all the copies in a single edit — one undo (or redo)
removes (or restores) them all, and each copy keeps a name of its own.
2026-10-25 13:22:14 +00:00
Minher0 601a15bc1f render: a 3D layer read outside its in/out range is transparent
solo_3d passed the layer to the 3D pipelines whatever the comp time, so an
instance (CC Composite referencing a model layer) rendered before the source
layer's in-point or after its out-point. Like any other layer reference, there
is nothing to read outside the range: return the transparent canvas.
2026-10-25 13:21:57 +00:00
Kushagra Kumar 77e2cf0554 fix(engine): expose transparent param in comp.saveFrameAs schema and test execute_checked 2026-10-25 18:44:35 +05:30
Minher0 82cebba68f layer.create: the instance3d op - a 2D copy of a 3D model layer (#2100)
Layer > Create > Create 3D Layer Instance, as After Effects (public docs):
3D model layers take no masks or effects, so the command puts a comp-sized
solid at the top of the layer stack with CC Composite referencing the
selected model, and switches the model off (back on to keep its shadow) -
a 2D copy of its render, through the comp's camera, that 2D effects can be
applied to.

- CC Composite (ec.channel.cccomposite) gains an optional Layer parameter:
  with a layer chosen it takes the original's place; In Front replaces the
  solid's pixels, alpha included, the other Composite Original modes blend
  with them. The GPU compositor runs such an instance on the CPU.
- FxHost serves a referenced model or primitive layer as After Effects
  does - the layer rendered on its own through the comp's camera
  (Renderer::solo_3d); the owner keeps no cache entry for it (it moves with
  the camera and lights, without a trace in its own properties).
- layer.create {op: instance3d} skips layers that are not 3D model or
  primitive layers (the ones that take no effects); one undo step, the copy
  selected, the model's video off.

Tests: tests_instance3d.rs (behaviour, pixels, undo/redo, serde, 2D effects
on the copy), a CC Composite layer-parameter unit test; docs/effects.md
regenerated (3033 parameters).
2026-10-25 12:46:58 +00: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
dotCooCoo d466e428b2 Scripts: File ▸ Scripts entries take keyboard shortcuts
Edit ▸ Keyboard Shortcuts now lists the scripts File ▸ Scripts lists, under
File ▸ Scripts, and a key given to one runs it as its menu entry does. The
key is bound to the script's file name (file.runScript {"name": ...}) and is
saved with the preset. File ▸ Scripts and the macOS menu show it.

The shortcut table lists the Scripts folder again when a script is installed
or uninstalled, when the editor opens and when shortcuts.list runs.
shortcuts.set and shortcuts.reset look a script up in File ▸ Scripts' list
as it is now, and a script it doesn't list is an error instead of a key for
Run Script File....
2026-10-24 21:06:00 -07:00
dotCooCoo 62cd2364d5 Shapes: add the Wiggle Transform path operation, which wiggles paths and each Repeater copy
A shape layer's Contents > Add menu had every After Effects path operation
except Wiggle Transform. It is now a shape item (layer.addShapeItem kind
wiggler, "ADBE Vector Filter - Wiggler" for scripts) with Wiggles/Second,
Correlation, Temporal Phase, Spatial Phase, Random Seed and a Transform
group whose Anchor Point, Position, Scale and Rotation set how far each
transformation wiggles.

The values come from the Wiggly selector's noise, with each Repeater copy
as one unit: the copies of a Repeater above the operation, in its group or
a nested one, wiggle independently as far as Correlation allows, and the
copies of a Repeater below it wiggle the same way. A paint above it whose
paths all move by one matrix moves its gradient and stroke scale with them.
The layer cache keys a layer with a Wiggle Transform by time.
2026-10-24 18:11:29 -07: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
Kristian Myram 39137fbd78 #1743: report refused queue items to CLI callers 2026-10-24 23:28:42 +00:00
Kristian Myram 9d33c200d5 #1743: protect render sources and refresh proxies safely 2026-10-24 23:00:46 +00:00
dotCooCoo d8e756dec5 Proxies: a composition proxy draws with Separate Fields, Invert Alpha, linear light and Frame Blending
For a precomp layer whose composition had a proxy, the renderer
decoded the proxy file with frame_with and drew it as decoded.
Interpret Footage > Proxy's Invert Alpha, Interpret As Linear Light
and Separate Fields had no effect on the render, and neither did the
layer's Frame Blending. A footage item's proxy already goes through
footage_frame and gets all of them.

The composition proxy now goes through footage_frame too, so it is
decoded the way a footage proxy is.
2026-10-24 15:20:57 -07:00
vangel76 3f41f5c026 Reuse the validated Warp Stabilizer plan on first render
Prepare the default plan through the effects cache after analysis instead of discarding it. Plan from the serialized analysis so the first rendered frame retains identical floating-point inputs and output. Test bitwise render equality and cache reuse.

Part of #2322
2026-10-25 00:14:57 +02:00
dotCooCoo 0cb05a601b Animation presets: effects saved by an earlier version are upgraded on apply, as in a project
Opening a project runs migrate::upgrade_instance on every effect, so an
instance saved before a parameter was renamed, moved into a twirl-down
group, added or had its popup reordered takes the current shape.
Apply Animation Preset added a preset's effects as saved, without that
upgrade. A Change to Color saved with its single Tolerance applied
with that old property and without the Tolerance group, so the effect
did not read the saved tolerance.

apply_preset now upgrades each preset effect before adding it, sized by
the target layer's effect bounds as upgrade_effects does. A lone effect
property saved at a renamed or moved parameter id
(effects/ec.color.changetocolor/tolerance) is rewritten to the current
id through migrate::current_param_id, so it is applied instead of being
listed in skipped.
2026-10-24 13:46:12 -07:00
dotCooCoo 7efbe7d85c Interpret Footage: the Footage panel, thumbnails and tracking show Cineon Settings
The Footage panel, the Project panel thumbnail and the native-size source
frames that tracking, mask tracking, scene detection and auto-trace read took
DPX and Cineon frames straight from the file, so they showed the log code
values while a composition showed the converted ones. Each now applies the
footage's Cineon Settings, as the composition renderer does.
2026-10-24 11:48:41 -07:00
vangel76andClaude Opus 5.5 c8dc0fca8c Merge upstream/main into gap-behaviors-presets
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-24 20:11:09 +02:00
vangel76andClaude Opus 5.5 5289b2e853 Merge upstream/main into fix-1083-beat-marker-audio-pause
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-24 20:02:37 +02:00
dotCooCoo 557c13b9cd Interpret Footage: the params docs list every key the commands read
execute_checked refuses any key a command's params doc does not list, so
MCP, the CLI and the control channel could not pass preserveRgb,
overrideStart, startTimecode or guessAlpha to file.interpretProxy. The
command reads all four, and the shared Interpret Footage form sends
preserveRgb for every proxy, and overrideStart and startTimecode for a
movie or sequence proxy. file.interpretProxy's doc now lists them. The
docs of file.interpretProxy and file.interpretFootage list premulColor
beside matteColor, which both commands read as the matte color. The
docs of file.interpretFootage, file.applyInterpretation and
file.reloadFootage list `item` beside `items`, which the three commands
already read.
2026-10-24 10:01:40 -07:00
dotCooCoo 9de2c5ee8a Interpret Footage: Cineon Settings convert DPX and Cineon log scans
DPX and Cineon footage showed its log code values as stored, with no
way to convert them. Interpret Footage now has the Cineon Settings that
After Effects' help page describes: Logarithmic Conversion, the
Converted Black and White Points, the 10 Bit Black and White Points,
Current Gamma, Highlight Rolloff and Units. With Logarithmic
Conversion on, the code values of each decoded frame are converted
from printing density to the Current Gamma between the converted
points, before Separate Fields, Frame Blending, Interpret As Linear
Light and the working space use them. With it off (the default), the
values stay as stored.

file.interpretFootage and file.interpretProxy take the settings as
parameters and report them. They return an error for out-of-range
values, and for Cineon parameters when none of the items is a DPX or
Cineon file. Apply Interpretation copies the settings between DPX and
Cineon files.
2026-10-24 08:37:15 -07:00
onlykshitijandClaude Opus 5.5 6e7cc34c9e Scripts: window.scriptPanel opens only ScriptUI panels
It fell back to any script, so a script outside the ScriptUI Panels folder opened as a panel and
was remembered, then reported missing and forgotten at the next launch (restore looks only for
panels). Review feedback from CodeRabbit on #2289.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-24 20:45:29 +05:30
dotCooCoo c2011fb11d Scripts: Recent Script Files keeps a script's full path, and same-named entries show their paths
A script run from a relative path is stored with its absolute path, so
choosing it again runs the same file after the working directory changes.
The web build keeps its file keys as they are (Services::full_path).

Two recent scripts, projects, footage files or presets with the same file
name are listed with their paths instead of the name alone.
2026-10-24 08:03:16 -07:00