Commit Graph
43 Commits
Author SHA1 Message Date
Brandon Thomas 6caa67971b Merge pull request #851 from Ni-zav/fix/811-script-object-identity-20261011
fix(script): preserve item and layer wrapper identity

# Conflicts:
#	crates/script/src/tests.rs
2026-10-12 03:23:26 -04:00
Brandon Thomas 2599237ef5 Merge pull request #850 from Ni-zav/fix/838-script-importas-psd-20261011
fix(script): respect ImportOptions.importAs for layered PSD files

# Conflicts:
#	crates/script/src/tests.rs
2026-10-12 03:23:24 -04:00
Brandon Thomas b7e85034ab Merge pull request #849 from Ni-zav/fix/840-extendscript-substr-20261011
fix(script): implement ExtendScript String.substr compatibility

# Conflicts:
#	crates/script/src/tests.rs
2026-10-12 03:23:23 -04:00
Brandon Thomas 255d888236 Merge pull request #847 from Ni-zav/fix/816-script-transform-shortcuts-s20261011T141200Z-fd2e
fix(script): expose AVLayer transform property shortcuts

# Conflicts:
#	crates/script/src/tests.rs
2026-10-12 03:23:21 -04:00
Brandon Thomas 1c7935b8c2 Merge pull request #846 from Ni-zav/fix/808-script-comments-and-marker-params-s20261011T141200Z-fd2e
fix(script): persist layer comments and unnamed marker parameters

# Conflicts:
#	crates/script/src/tests.rs
2026-10-12 03:23:20 -04:00
Brandon Thomas 61f5b937dc Merge pull request #845 from Ni-zav/fix/814-batch-remove-keys-s20261011T141200Z-fd2e
feat(script): delete keyframe ranges in one undoable command

# Conflicts:
#	crates/script/src/tests.rs
2026-10-12 03:23:18 -04:00
Brandon Thomas 5237ebf596 Merge pull request #843 from Ni-zav/fix/812-stable-script-undo-id-s20261011T141200Z-fd2e
fix(script): keep Undo command ID 16 stable for scripts

# Conflicts:
#	crates/script/src/tests.rs
2026-10-12 03:23:14 -04:00
Brandon Thomas 80febbd418 Merge pull request #842 from Ni-zav/fix/817-script-binary-file-io-s20261011T141200Z-fd2e
fix(script): preserve raw bytes in BINARY File reads, writes, and copies
2026-10-12 03:23:13 -04:00
Brandon Thomas dfd6e9300f Merge pull request #772 from vangel76/script-760-evalfile-bridgetalk
#760: $.evalFile and a minimal BridgeTalk host identification

# Conflicts:
#	crates/script/src/runtime.rs
#	docs/scripting-parity.md
2026-10-12 03:20:49 -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
Nigel Ihza Firdausy 40e9e7786b fix(script): route usedIn composition references through identity cache 2026-10-11 21:45:20 +07:00
Nigel Ihza Firdausy d347afb2cb fix(script): preserve item and layer wrapper identity (#811) 2026-10-11 21:44:02 +07:00
Nigel Ihza Firdausy 8b25dc713f fix(script): forward ImportOptions.importAs for layered PSD imports (#838) 2026-10-11 21:42:43 +07:00
Nigel Ihza Firdausy 3cdc7af9ff fix(script): implement ExtendScript String.substr compatibility (#840) 2026-10-11 21:41:21 +07:00
Nigel Ihza Firdausy 74b842cc45 fix(script): expose AVLayer transform property shortcuts (#816) 2026-10-11 21:30:18 +07:00
Nigel Ihza Firdausy 47972e95a8 fix(script): persist layer comments and unnamed marker parameters (#808) 2026-10-11 21:29:04 +07:00
Nigel Ihza Firdausy be2c73ece9 feat(script): remove a range of keyframes in one command (#814) 2026-10-11 21:25:13 +07:00
Nigel Ihza Firdausy a7249ad1a4 fix(script): keep After Effects Undo command ID 16 stable (#812) 2026-10-11 21:19:59 +07:00
Nigel Ihza Firdausy d88bfe9f7c fix(script): preserve binary File bytes when reading, writing and copying (#817) 2026-10-11 21:17:46 +07:00
vangel76andClaude Opus 5.5 7085816c98 #773: run repeating app.scheduleTask tasks until cancelTask
Problem: app.scheduleTask(code, delay, true) queued the task and then
skipped it (eval_with_tasks: `if repeat { continue; }`), so repeating
tasks - what ScriptUI panels use for polling and refreshing - never ran.
One-shot tasks scheduled by handlers or in the Script Console never ran
either.

Fix: tasks live per script context (crates/script/src/tasks.rs) with a
due time. Frontends run the due ones every frame through the new
ScriptUi::run_tasks hook (the egui app does; agents and headless hosts
use the `script.runTasks` command). Script-host threads get a Tick
message, inline hosts (Script Console, web) run in their kept context.
A repeating task runs every `delay` ms until app.cancelTask, until it
throws (reported once, then cancelled), or until its owner goes: the
script's last window closing, or - for scripts without windows and the
console - the project being closed or replaced (ScriptUi::project_epoch).
Bounds: at least 50 ms between runs, at most 64 pending tasks per
script, one run per pass (no catch-up bursts), task code nested too
deeply is refused, the engine's loop and recursion limits apply. Ticks
only reach the hosts of the session that scheduled them.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 12:56:09 +02:00
vangel76andClaude Opus 5.5 88278ea871 #760: $.evalFile and a minimal BridgeTalk host identification
Problem: `$.evalFile` always threw, and `typeof BridgeTalk` was
`undefined`, so frameworks such as DuAEF failed during initialisation
when they load their modules or ask which application they run in.

Fix: `$.evalFile(file[, timeout])` evaluates a script file in the global
scope and returns its last value. Relative paths resolve against the
folder of the file being evaluated (the running script's for the
outermost call, else the project's); reads follow the same file gate,
16 MiB size cap and 32-deep nesting limit as `#include` (#759, shared
`scriptfile.rs`), and the bracket-depth check runs before parsing.
`BridgeTalk` names the host honestly (`appName` "effectcraft", its
version, `appSpecifier`, `isRunning` / `getSpecifier` / `getStatus` /
`getTargets` for ourselves only); `send()` throws a clear "not
supported" error instead of messaging other applications.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 12:37:22 +02:00
vangel76andClaude Opus 5.5 bfe384e400 #758: layers, property groups and properties are callable
Problem: After Effects scripts call layers and property groups as a
shorthand for .property(nameOrIndex) (layer("ADBE Effect Parade"),
fxGroup(1), effect("Slider Control")("Slider")); Duik and many other
scripts use it throughout. EffectCraft's objects were Proxies around
plain objects, so each such call failed with "TypeError: not a callable
function".

Fix: Layer, PropertyGroup, MaskPropertyGroup and Property objects are
now Proxies around an arrow function carrying the object's state and
prototype (own name/length removed so the object's getters show). The
apply trap returns self.property(arg), so a call matches .property():
null when absent, Property returns null, and a missing name is the same
script error. instanceof, attribute access and script results are
unchanged; new on these objects stays a TypeError.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 12:22:03 +02: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
Claude adeccc02e0 Merge pull request #479 from MarekSpodBiedry/issue-475
# Conflicts:
#	crates/script/src/tests.rs
2026-10-10 12:51:16 +00:00
Claude 45897f0aaf Merge pull request #566 from Ni-zav/fix/548-property-selected-false-s20261010T084400Z-a6e9
# Conflicts:
#	crates/script/src/tests.rs
2026-10-10 12:49:18 +00:00
Claude c7b75a04d7 Merge pull request #555 from LloydNicholson/fix/addsolid-pixel-aspect
# Conflicts:
#	crates/script/src/tests.rs
2026-10-10 12:49:11 +00:00
Claude ead13d81d4 Merge pull request #559 from Ni-zav/fix/544-project-item-deselect-s20261010T084400Z-a6e9
# Conflicts:
#	crates/script/src/tests.rs
2026-10-10 12:49:11 +00:00
Nigel Ihza Firdausy 4bc619b010 fix(script): deselect individual properties via Property.selected=false (#548) 2026-10-10 15:58:22 +07:00
Nigel Ihza Firdausy 4f6256c486 fix(script): keep pending TextDocument baseline reads in sync (#549) 2026-10-10 15:49:32 +07:00
Nigel Ihza Firdausy d0489021b5 fix(script): make Item.selected=false deselect only that item (#544) 2026-10-10 15:47:58 +07:00
lloydandClaude Opus 5.5 6843510a25 Scripting: layers.addSolid keeps the requested pixel aspect (#543)
LayerCollection.addSolid dropped its fifth argument, so layer.newSolid
fell back to the composition's pixel aspect. The wrapper now passes
pixelAspect through; layer.newSolid already validates it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 09:42:07 +02:00
MarekSpodBiedry bca027de6a Scripting: importFile(ImportOptions) imports one file unless sequence is set (#475) 2026-10-09 21:12:22 +02: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
BFlat 9e79271893 Merge pull request #10 from storybored379/pr/spatial-tangent-getter-names
Scripting: Property.keyInSpatialTangent / keyOutSpatialTangent under their AE names
2026-10-05 12:11:18 +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
storybored379andClaude Opus 5.5 0a8cdfc67e Scripting: Property.keyInSpatialTangent / keyOutSpatialTangent under their AE names
The getters were registered as keySpatialInTangent / keySpatialOutTangent,
so scripts using the documented After Effects names failed with
"TypeError: not a callable function" (setSpatialTangentsAtKey and the
other keySpatial* methods already use AE's names).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-04 01:17:34 -07:00
Brandon ThomasandClaude Opus 5.5 dc132bc219 Merge main into M13.11 (bokeh kernel_spans/blur_levels, Essential Graphics as_type controls with mirrors and links)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-03 09:54:37 -04:00
Brandon ThomasandClaude Opus 5.5 d774d11231 M13.11: essential graphics mirrored and linked properties
Adding a property already in the Essential Graphics panel adds a mirror
(EgKind::Mirror: own name and place, one value in the comp and in every
instance; editing, reverting or pushing either acts on both). A property
control can also drive further properties of the comp (links follow the
main property both ways and take instance values). essential.addMirror,
essential.linkProperty, essential.unlinkProperty; panel badges and menu;
ExtendScript addToMotionGraphicsTemplate(As), canAddToMotionGraphicsTemplate,
motionGraphicsTemplateName, controller count/name and
exportAsMotionGraphicsTemplate.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-03 09:38:19 -04:00
Brandon ThomasandClaude Opus 5.5 558de71720 M13.7: Essential Graphics scripting hooks, Font and uniform Scale controls, Open in Essential Graphics
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-03 07:23:22 -04:00
Brandon ThomasandClaude Opus 5.5 5aae82b05c M13.7: ScriptUI resource strings, onDraw graphics, live onChanging, Socket
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-03 05:49:05 -04:00
Brandon ThomasandClaude Opus 5.5 f855a4b55b M14.5: wire the remaining settings; keyframe assistants and labels; AE menu entries
Settings: 56 of 59 not-yet-wired settings now change behaviour (nested-comp switches,
constant vertex count, related-item time sync, match-name pick whip, split-layer order,
Home on open, motion path span, internal wireframes, zoom quality, label-coloured tabs,
mask colour cycling, gradients, grid/guide styles, text engine, font preview/recent/native
names, missing frames, unlabeled alpha, drag import, default output folder, segmenting,
bit depth names, preview sample rate, disk/media/conformed-audio caches, RAM reserve and
low-memory reduction, Video Preview window, 3D reference axes/extended viewer/draft
shadows, script file gate + File.execute warning, expression editor options and error
banner). Three stay display-only and are documented.

Features: Convert Audio to Keyframes, RPF Camera Import (JSON/CSV camera data),
keyframe colour labels + Select Keyframe Label Group, Recent Animation Presets.
Menus: Edit > History, File > Import Recent Footage, Replace Footage > With Layered
Comp, Save a Copy As XML (.ecprojx, opens again), Composition > VR (Create VR
Environment, Extract Cubemap), Assign Shortcut to 3D view / workspace, Window viewer
labels + open viewers, Help > System Compatibility Report / Enable Logging / Reveal
Logging File. Dynamic menu nodes (@dynamic:…) shared by the egui and native menus.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-03 02:45:44 -04:00
Brandon ThomasandClaude Opus 5.5 d880746fec M14.4: scripting tests for layer/comp settings, import + save, console snapshot; Project.saveAs
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-02 22:18:11 -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