Commit Graph
22 Commits
Author SHA1 Message Date
Brandon ThomasandClaude Opus 5.5 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 bb4972a886 Merge pull request #1160 from nanox333/fix/1063-levels-alpha-name
# Conflicts:
#	crates/script/src/tests.rs
2026-10-13 04:35:20 -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 0e4f3bfb8f Merge pull request #1043 from vbasky/fix/1000-sampleimage-footage
# Conflicts:
#	crates/script/src/tests.rs
2026-10-13 04:28:50 -04:00
Brandon Thomas ee682bbfd9 Merge pull request #1172 from redonion23/fix/815-stroke-dash-matchnames
# Conflicts:
#	crates/script/src/tests.rs
2026-10-13 04:28:45 -04:00
Brandon Thomas 092834b703 Merge pull request #1156 from redonion23/fix/814-removekey-linear 2026-10-13 04:28:44 -04:00
Brandon Thomas a55155bd7d Merge pull request #1191 from redonion23/fix/813-footage-proxy-scripting 2026-10-13 04:28:34 -04:00
Brandon Thomas 66be8857b5 Merge pull request #1162 from nanox333/fix/1063-light-casts-shadows
# Conflicts:
#	crates/script/src/tests.rs
2026-10-13 04:28:33 -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
redonion23andClaude Opus 5.5 004984d853 Scripting: footage proxies, replaceWithSequence and mainSource.conformFrameRate (#813)
FootageItem had no replaceWithSequence, setProxy, setProxyWithSequence or
setProxyToNone, useProxy and proxySource were fixed stubs, and mainSource
was a new object on every read with no conformFrameRate. They now run the
existing commands (file.replaceFootage, file.setProxy, file.useProxy,
file.setProxyNone, file.interpretFootage); the item info reports the proxy
and the conform/native frame rates, and mainSource is one live
FootageSource per FootageItem. replaceSource is not covered: it needs an
engine command that changes a layer's source.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 05:59:10 +02:00
redonion23andClaude Opus 5.5 f816cd5e38 Scripting: a stroke's Dashes use After Effects' match names (#815)
Dashes reported its children as `dash`, `gap`, `offset`, so
`property("ADBE Vector Stroke Dash 1")` was null and addProperty threw.
They now report ADBE Vector Stroke Dash 1-3 / Gap 1-3 / Offset.
addProperty with one of those names returns the existing property
(EffectCraft's Dashes always holds Dash 1, Gap 1 and Offset) or adds the
Dash/Gap 2 or 3 pair through shape.dashes.add. Lookups by the old ids
still work.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 03:04:12 +02:00
Kristian MyramandClaude Haiku 5.5 5530560fb8 #1063: find a light's Casts Shadows option by its After Effects name
A script asks a light's options for "ADBE Casts Shadows", which returned null. The light's option
is named "Casts Shadows" here, so the lookup never matched. The name is now an alias for the
castsShadows property, and a regression test checks the lookup returns the property.

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
2026-10-13 01:53:35 +02:00
Kristian MyramandClaude Haiku 5.5 5e97eaddba #1063: find a Levels alpha control on the effect by its name
Pro Levels2 keeps its Alpha controls one group down, under Alpha, and a script's
effect.property("Alpha Input White") only searched the effect's direct children, so it returned null.
The lookup now searches the groups nested below the direct children, up to three levels, after the
direct match fails. Direct children keep their priority. A regression test checks the name on the
effect and the same control through the Alpha group.

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
2026-10-13 01:41:22 +02:00
redonion23andClaude Opus 5.5 b2cf845624 Scripting: key calls fetch only the key they need, so removeKey stays fast (#814)
Every key call (removeKey, keyTime, keyValue, setInterpolationTypeAtKey…)
looked its key up through `__keys()`, which serialised the whole key list,
eases and tangents included, on each call. Removing keys one by one was
therefore quadratic: about 100 ms per removeKey on a 2,000-key property.
The `keys` query now takes an optional `index` and returns just that key
with the count; `__key` uses it. removeKey on 2,000 keys drops from
103.7 ms to 0.4 ms (release, Windows 11 aarch64).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 01:35:49 +02:00
Kristian MyramandClaude Haiku 5.5 2ef3d977a6 #808: sourcePointToComp and compPointToSource follow the layer's transform
Both returned their input unchanged. They now go through the layer's transform and its parents'
at comp time, and the inverse.

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
2026-10-12 19:19:13 +02:00
Vikram Bhaskaran de26297c36 Sample footage pixels in script expressions (#1000)
A script reading an expression that calls sampleImage on a footage layer got
[0,0,0,0]: the script evaluator built its EvalCtx with EvalCtx::new, which
has no footage source, so the renderer substituted transparent frames (solids
and shapes stayed correct because they are procedural). Pass the session's
footage source, as the app's renderer and diagnostics already do.
2026-10-13 01:34:58 +11:00
Claude 8d32d67f0e Color: Project Settings ▸ Working Gamma 2.2 / 2.4 with no working space, as in After Effects (#495)
After Effects' `app.project.workingGamma` (2.2 or 2.4, ignored with a working space) sets
the curve an unmanaged project uses: at 2.2 the piecewise sRGB curve, at 2.4 a pure 2.4
power curve. EffectCraft always used sRGB, so linear EXRs (Interpret As Linear Light) from
a 2.4 project came out darker in the shadows (0.18 → 0.461 instead of 0.490).

- `ProjectSettings::working_gamma` (default 2.2, serde default for old projects).
- The colour pipe's unmanaged curve is the Working Gamma's (sRGB, or Rec. 709's pure 2.4
  curve): Interpret As Linear Light encodes untagged footage with it and Blend Colors Using
  1.0 Gamma linearizes with it; it is part of the pipe's cache key. The GPU path takes the
  same conversions.
- `file.projectSettings {workingGamma: 2.2|2.4}` (other values are refused, as in AE),
  `app.project.workingGamma` in scripts and a Working gamma choice in Project Settings.

Test: render test with linear 0.051 / 0.18 / 0.5 footage (0.290 / 0.490 / 0.749 at 2.4,
0.250 / 0.461 / 0.735 at 2.2, the values measured in AE), linear blending at 2.4, a working
space ignoring the setting, and the cache key.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QiAJeFttZp83Fh7YuzAR5f
2026-10-10 19:54:17 +00:00
bflatasticandClaude Opus 5.5 da165724e9 Plug-ins: Ease Presets moves out of core into a bundled ScriptUI panel
The Ease Presets panel (#254) is modelled on a third-party panel, so,
as with third-party tools in After Effects, it isn't core any more: it
is `extensions/scriptui-panels/Ease Presets.jsx`, a ScriptUI panel
bundled as an optional extension (Window ▸ Ease Presets.jsx), written
only against the public scripting API. Clicking a preset eases every
pair of neighbouring selected keyframes in one undo step (per
dimension, along the motion path for spatial properties, the keys'
other sides as they play); the fields edit the working curve, which the
panel draws; From Keys, Save, Rename and Delete as before. The twelve
built-in curves are unchanged.

Scripting API fixes it needed (After Effects parity):
- `app.settings` lasts between runs (`script_settings.json` in the
  settings folder; `script.settings.get` / `script.settings.save`).
- Per-key methods (`setTemporalEaseAtKey`, `setInterpolationTypeAtKey`,
  `removeKey`, the continuous / auto-Bezier / roving setters) no longer
  change the user's key selection (they selected the key they edited).
- `keyInTemporalEase` / `keyOutTemporalEase` report linear and
  auto-Bezier sides as they play, `keyIn/OutSpatialTangent` the
  tangents the motion path plays.
- `selectedProperties` includes the properties of selected keyframes.
- `isInterpolationTypeValid` is false for Linear / Bezier on values that
  only hold.

Removed from core: Window ▸ Ease Presets, the `keys.easePreset.*`
commands, `engine::ease_presets` and the `ease_presets.json` store,
`keyframe::EaseCurve` (nothing else used it) and the egui panel. User
presets saved by the v0.6.0 panel move into the panel's app.settings
section the first time settings load (the old file is left as is).
Docs: plugins.md (bundled extensions), parity.md, gaps.md G8, agents.md.

Test: app_settings_last_between_runs,
per_key_methods_keep_the_key_selection_and_report_eases_as_they_play,
spatial_tangents_are_reported_as_the_path_plays (each fails before),
the_ease_presets_panel_eases_every_selected_pair_in_one_undo_step,
a_typed_curve_scales_to_each_dimension_and_follows_motion_paths,
user_presets_save_rename_delete_and_persist,
presets_saved_by_the_old_core_panel_carry_over (script, through the
panel's controls), ease_presets_panel_eases_the_selected_keys_from_its_list
(UI: the panel docks and a click on a preset eases the keys).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 21:03:12 +07:00
bflatasticandClaude Opus 5.5 0fe6db00e8 M4.9: Preserve frame rate when nested or in render queue, Preserve resolution when nested
Composition Settings ▸ Advanced has both options (they were missing from the model, the
renderer and the dialog):
- Preserve frame rate: nested in another comp, the comp shows only its own frames
  (`EvalCtx::nested_time` floors the precomp layer's source time to the nested comp's frame
  rate; used for the nested frame, its proxy, aux channels, collapsed transformations and the
  viewer's internal wireframes), and the Render Queue renders it at its own rate whatever the
  Frame Rate override (`RenderSettings::rate`).
- Preserve resolution: nested in a comp rendered at Half / Third / Quarter, it renders at full
  size and the buffer's scale places it.
- `comp.settings {preserveFrameRate, preserveResolution}`, `comp.info` reports them, scripts
  read and set `CompItem.preserveNestedFrameRate` / `preserveNestedResolution`, Pre-compose
  copies them, and the dialog registers `dialog.comp.preserveFrameRate` /
  `dialog.comp.preserveResolution`.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-05 01:33:14 +07:00
Brandon ThomasandClaude Opus 5.5 89c9b1b6ee M13.1: branching history, puppet pin recording, WebAssembly plug-in API, ScriptUI model and hosts, File ▸ Scripts, deterministic render test
- engine: History keeps undone lines as branches; edit.history.list/goto; History panel tree; MCP history tool
- puppet.recordPin / puppet.recordOptions; viewer Cmd-drag records; Record Options form
- effects::plugin (EffectPlugin trait, register_plugin, API v1); effectcraft-plugin (wasmi, sandboxed, fuel-limited); effect.plugins.load/list
- ScriptUI: engine scriptui model + layout + scriptui.* commands; script crate scriptui.js and script-host threads (dialogs block show())
- File ▸ Scripts: install script / ScriptUI panel, sample scripts, window.scriptPanel
- host test: bit-identical renders across runs and thread counts

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-03 04:07:20 -04:00
Brandon ThomasandClaude Opus 5.5 bbaee1fa0f M13.5: stroke taper/wave/multi-dashes, radial gradient highlight, variable-width mask feather, adaptive motion-blur samples
Shapes (SHP-2): Stroke Taper (pixels/percent start/end length, width, ease) and
Wave (amount, pixels/cycles, wavelength, phase) rendered as a variable-width
outline; Dash 2/Gap 2/Dash 3/Gap 3 (shape.dashes.add/remove, timeline +/-
buttons); radial gradient Highlight Length/Angle as a focal gradient.
Masks (MSK-1): mask feather points on the Mask Path (mask.featherPoint.*,
Mask Feather tool add/drag), per-point signed radius and tension, rendered
from the signed distance to the path; carried through vertex edits.
Motion blur (LYR-10): Adaptive Sample Limit comp setting; 2D layers take one
sample per pixel of shutter travel between Samples Per Frame and the limit.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-02 23:22:53 -04:00
Brandon ThomasandClaude Opus 5.5 78cd313d3c M14.4: scripting with an After Effects-style JavaScript object model
New crate effectcraft-script (L4): boa runtime with app/Project/CompItem/
Layer/PropertyGroup/Property/TextDocument/MarkerValue/RenderQueue/File
object model over engine commands (undoable, undo groups), AE match-name
table, file/network security gate. Entry points: script.run command,
File > Scripts > Run Script File (.jsx/.js), Window > Script Console,
effectcraft-cli script, MCP run_script. Engine: project.delete/duplicate,
prop.renameGroup/setGroupEnabled/removeGroup/duplicateGroup/moveGroup.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-02 22:13:09 -04:00