chore: sync upstream (43 Commits) #23

Merged
alf merged 43 commits from chore/sync-upstream-20261109 into main 2026-11-09 11:10:34 +00:00
Owner

Upstream-Sync von upstream/main (43 Commits). Fast-Forward.

  • 544eebf9 WebAssembly ABI 2: neighbouring frames for effect plug-ins (#2773) (#3329)
  • 81a12fff Merge pull request #3340 from dotCooCoo/chore/craft-update-1b34eba41
  • 91f35c73 Updates: restart from the update result dialog
  • 7c622723 .aep import: placed .ai/PDF footage framed by its ArtBox, Null anchors at the corner (#3099) (#3311)
  • 9893eb0d Naming: descriptive names for the CC effects, Lumetri, Mocha, Keylight and Mercury (#3327)
  • 9253b5bd Updates: take craft-update from craft-libs main at 1b34eba41
  • a41ff501 Merge pull request #3129 from vangel76/aep-import-lumetri
  • 86c08aa0 Keep native control renders responsive (#3306)
  • 5f2d88ea Merge remote-tracking branch 'upstream/main' into aep-import-lumetri
  • 07be19d4 Merge pull request #3255 from vangel76/aep-import-puppet-3093
  • 7ca249d0 Merge pull request #3120 from vangel76/aep-import-thirdparty
  • 5832219d Merge pull request #3248 from vangel76/text-layer-name-follow-3233
  • 362b3903 Merge pull request #3256 from vangel76/clamp-time-stretch-3247
  • c8ccf807 #3233: AEP import names an unnamed text layer as a following name is cut, so export and import agree
  • e41d6d9d Merge remote-tracking branch 'upstream/main' into text-layer-name-follow-3233
Upstream-Sync von `upstream/main` (43 Commits). Fast-Forward. - 544eebf9 WebAssembly ABI 2: neighbouring frames for effect plug-ins (#2773) (#3329) - 81a12fff Merge pull request #3340 from dotCooCoo/chore/craft-update-1b34eba41 - 91f35c73 Updates: restart from the update result dialog - 7c622723 .aep import: placed .ai/PDF footage framed by its ArtBox, Null anchors at the corner (#3099) (#3311) - 9893eb0d Naming: descriptive names for the CC effects, Lumetri, Mocha, Keylight and Mercury (#3327) - 9253b5bd Updates: take craft-update from craft-libs main at 1b34eba41 - a41ff501 Merge pull request #3129 from vangel76/aep-import-lumetri - 86c08aa0 Keep native control renders responsive (#3306) - 5f2d88ea Merge remote-tracking branch 'upstream/main' into aep-import-lumetri - 07be19d4 Merge pull request #3255 from vangel76/aep-import-puppet-3093 - 7ca249d0 Merge pull request #3120 from vangel76/aep-import-thirdparty - 5832219d Merge pull request #3248 from vangel76/text-layer-name-follow-3233 - 362b3903 Merge pull request #3256 from vangel76/clamp-time-stretch-3247 - c8ccf807 #3233: AEP import names an unnamed text layer as a following name is cut, so export and import agree - e41d6d9d Merge remote-tracking branch 'upstream/main' into text-layer-name-follow-3233
alf added 43 commits 2026-11-09 11:10:33 +00:00
The importer reported these five effects as lost. They now become
EffectCraft's effects of the same name with every parameter After Effects
stores (ranges, defaults and popup items from our own After Effects 2026
project, documented in docs/aep-format.md 3.7):

- ADBE HDR ToneMap -> ec.utility.hdrcompression (Amount)
- ADBE Echo -> ec.time.echo (Echo Time, Number Of Echoes, Starting
  Intensity, Decay, Echo Operator by item name)
- ADBE Linear Wipe -> ec.transition.linearwipe
- ADBE Offset -> ec.distort.offset (Blend With Original is a stored 0..1
  fraction, a percentage here)
- ADBE Deflicker -> ec.color.colorstabilizer (fresh Stabilize default
  Levels, points, Sample Size)

A table row can name the range EffectCraft's effect works in
(ParamMap::limit): Echo values or keys beyond 255 echoes or a Decay of 1
are imported as stored and reported.

Tests build each effect into the committed synthetic.aep (fx_inject.rs,
which also checks its pard layout reads back). On the sample project the
effect losses go from 75 to 3 (the out-of-range Echo values).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The importer reported these three plug-ins as lost effects. They now
become EffectCraft's effects of the same name (parameter lists and data
layouts from our own After Effects 2026 project, docs/aep-format.md 3.7):

- CS Color Neutralizer -> ec.color.cccolorneutralizer: Pinning and Blend
  w. Original. After Effects' correction is the per-range Red / Green /
  Blue sliders (the Unbalance colours are pickers that keep no record),
  plus View and Black / White Point; EffectCraft's effect has none of
  them, so each is reported when stored.
- EXtractoR -> ec.3d.extractor: Black / White Point, UnMult, and the
  default Channel Info (R, G, B, (copy)) as EffectCraft's R, G, B, A
  (ExtractorChannels). Other channels are reported: only the default
  layout is sampled.
- IDentifier -> ec.3d.identifier: Display by item name, ID. Its Channel
  Info names only the channel type (Object ID, identifier_channel_type),
  not the channel After Effects reads; After Effects left the sampled EXR
  unchanged where EffectCraft draws the footage's object ID channel, so
  every instance is reported.

On the sample project no effect is lost any more (29 before); the
parameters above are reported instead.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The importer now converts After Effects' Lumetri Color. Its parameters are
found by match-name suffix, not by parT index: After Effects inserted
-0127 ... -0130 mid-list and five tone sliders share one valid range.

- Values are read from every value record, also those in the default
  state (tdsb 3), where Lumetri keeps High Dynamic Range, HDR Specular and
  the second Look popup (EffectParam::recorded_value; stored_value is
  unchanged).
- A switched-off section, and HSL Secondary without a picked key colour,
  draws nothing in After Effects: its set values are reported in one line
  and not imported.
- The HSL key data is decoded into hue / saturation / lightness ranges.
- LUTs and Looks (by name), controls without a counterpart, eyedropper
  colours and undecoded curves, wheels and Split Toning are reported.
- EffectCraft's Lumetri sliders take After Effects' valid ranges.
- import_param is split into lookup plus import_mapped for reuse.

Evidence: 1200 samples (After Effects 2026). The 62 read-backs of mapped
controls in sections that act equal the imported values. The other 61
lie in sections that do nothing and are reported. Renders of identity
grades are within 1/255.

Part of #3111

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Presets of our own (blocks 1300 and 1310) show what the Channel Info stores for a chosen
channel.

- EXtractoR: each record is a kind in byte 0 and the channel name. Named channels are
  imported by name (Z, Z, Z renders equal to After Effects) and `(copy)` as the input's
  own channel. The kind is byte 0 only: one definition default has `02 00 00 32`.
- IDentifier: byte 19 holds the chosen channel's name, `Object ID` when none is chosen.
  After Effects lists only UINT channels and leaves the layer unchanged without one, which
  the loss now says. A chosen `ObjectID` / `MaterialID` channel (any case) is the one
  EffectCraft reads itself, so it imports without a loss; other names are reported.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
After Effects 2026 presets made by hand (1200 lumetri-58 ... -62) decode
the data the scripted samples could not set.

- RGB curve (-0039): the first of the four curves is the master curve
  and arrives as curves/rgbCurves/master. A moved red, green or blue
  curve is reported: no sample tells which slot is which channel.
- Hue vs Sat (-0042): y is the offset from neutral, 1 doubling the
  saturation (in linear light), so EffectCraft's y is 0.5 + y / 2. The
  other four hue / saturation curves stay reported when moved.
- Color Wheels (-0047): four triples of hue (degrees), brightness slider
  (0.5 neutral) and distance. Shadows, Midtones and Highlights become
  EffectCraft's wheel colours (HSL of that hue, saturation = distance,
  lightness 0.5); the brightness sliders and the fourth wheel are
  reported.
- Damaged curve or wheel data is reported as damaged.
- Legacy Tone And Saturation is reported when a record says on: its pard
  default turns from off to on when the project is saved again (the
  25.x / 24.x / 26 copies of 1200), so comparing with it missed it.
- The Input LUT and Look presets confirm -0095 / -0096 hold the names;
  the LUT files are After Effects' own and are not embedded.

Evidence: the 62 read-backs still equal the imported values in the new
63-composition 1200 file. The version copies store the same Lumetri
definitions, ranges and values and give the same report. Renders: master
curve within 0.024 (After Effects uses a natural spline, EffectCraft's
Lumetri a monotone one), Hue vs Sat mean 0.008, wheels mean 0.042.

Part of #3111

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The EffectCraft value for the Shadows wheel's blue lift at black was read at input 0.05; at input 0 it is 0.17 (After Effects 0.13).

Part of #3111

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Take recorded_value from #3134 for ordinary effects in import_mapped; the ValueRecord switch is gone (stored_value now reads default-state records too).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
# Conflicts:
#	docs/file-format-parity.md
Conflicts with the Cryptomatte import (#3109), the quick wins (#3119) and
the version report: Extra keeps both Lumetri and Cryptomatte (the exporter
reports both, writes neither), the Lumetri mapping gets ParamMap's new
limit (None), the effect table counts 64, the docs keep both sections.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
#3119 (the base of this branch) is merged. Conflicts with the Cryptomatte
import (#3109) and the version report: Extra keeps Extractor, Identifier
and Cryptomatte, arbitrary.rs keeps ExtractorChannels /
identifier_channel_type next to CryptomatteData, the effect table counts
66, the docs keep both sides. The exporter from #2594 gets the Extractor
and Identifier arms: like Lumetri they have no prototype, so CC Color
Neutralizer, EXtractoR and IDentifier are reported, not written (new
test imported_plug_in_effects_are_reported_not_written).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A text layer's name followed its Source Text whenever the name started with "Text", so a user's
"Text Title" was replaced by the next text edit. The layer now records whether its name follows
the text (`name_follows_text`, optional in the project file). A new text layer named after its
text follows it; a name given at creation or by Rename (Enter, layer.rename, a script's
layer.name, Layer Settings' name) is the user's and stays; renaming to an empty name shows the
text again and follows it; committing the unchanged name changes nothing; copies keep the state.
On-canvas typing and layer.setText share the rule. The name is the text's first paragraph, which
ends at a line feed or a bare carriage return (After Effects' paragraph break).

Projects saved without the state keep the old rule for the names that followed: a name that is
empty, the text's own, or "Text"/"Text 2"... follows; any other name stays. AEP import records a
stored layer name as the user's and no name as following, and names an empty text layer without
a name "Text" instead of "Layer"; export writes no name for a following layer and keeps the name
the user gave, even when it equals the text.

Fixes #3233
After Effects' Puppet was dropped with a one-line "has the effect" loss. It now
arrives as EffectCraft's Puppet (ec.distort.puppet) in its place in the stack,
with its name and fx switch, and the report lists per mesh Triangles, Expansion
and per pin group (Deform, Overlap, Stiffness) the pins, keyed pins and atom
match names; entries outside the known tree are named once, and long lists stop
at ten with "and N more".

No pins are created: a pin's rest place is a vertex of the hidden mesh data and
the unit of its Position is unknown, and no corpus file holds a Puppet. The tree
(docs/aep-format.md 3.7) comes from an external scripting listing, not the
corpus; the sample that settles it is described there. The fx_inject test
helpers can now inject any effect instance, which the new tests use.

Refs #3093
A project file, an .aep, a timeline document or a Lottie file could give a
layer a time stretch of 1e-300 %, 0 or 1e300 %. Layer and comp time divide
by it and the audio mix read about usize::MAX source samples for one block,
which overflowed or tried a huge allocation and aborted the app.

- limits::stretch brings a stretch within After Effects' range (±1 % to
  ±9900 %, Layer.stretch in the scripting guide), sign kept; 0 and NaN are
  100 %. Opening a project file corrects each layer and says so; a stretch
  written as null (NaN in an auto-save) now opens instead of failing.
- .aep import and Lottie import clamp and report the stretch; timeline
  import clamps the clip speed and warns.
- layer.timeStretch refuses a non-number and more than 9900 %; the Time
  Stretch dialog's ranges match.
- Layer::layer_time / comp_time and the audio mix use the clamped stretch,
  so a value set in memory can't divide by zero or read without bound.

Fixes #3247
After Effects' Channel Info kind 2 "(copy)" was imported as R, G, B or A.
EffectCraft's EXtractoR resolves those names through the footage's aux planes
first, and an OpenEXR keeps its own R/G/B/A planes, so "(copy)" read the
original file plane and dropped what an earlier effect did to the channel.

"(copy)" is now a reserved EXtractoR channel name (EXTRACTOR_COPY) that the
CPU and GPU renderers never look up in the aux planes: it is the input's own
channel of the same position. The importer writes it for kind 2.

Render regression: a modified input buffer with same-named R/G/B/A aux planes
of other values; GPU parity case with (copy) on an aux scene with R/G/B.
import_extra returned as soon as the arbitrary data was missing, so an
EXtractoR or IDentifier value record whose aRbs/aRbp payload is gone was
silently imported with the default channels; the payload may have chosen
other ones (Z). As for Lumetri's data parameters, a stored record without its
payload now adds a DamagedData loss; a parameter with no record stays the
silent default. The test now asserts the report.
# Conflicts:
#	crates/aep/src/import/effects.rs
# Conflicts:
#	docs/aep-format.md
Time stretch: hold a loaded or imported stretch to ±1 % to ±9900 %
Text layers: the name follows the text until the user renames the layer
.aep import: map CC Color Neutralizer, EXtractoR and IDentifier
AEP import: Puppet arrives as EffectCraft's Puppet, its meshes and pins are reported
# Conflicts:
#	crates/aep/src/container/effect_map.rs
#	crates/aep/src/export/effects.rs
#	crates/aep/src/import/effects.rs
#	crates/aep/tests/it/export/effects.rs
#	crates/aep/tests/it/import/effects.rs
#	docs/aep-import.md
* Keep native control renders responsive

* Refresh replies for immediately completed render jobs

* #3289: Bind waiting replies to their native render
.aep import: map Lumetri Color
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.
* #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.
Updates: take craft-update from craft-libs main at 1b34eba41
WebAssembly ABI 2: neighbouring frames for effect plug-ins (#2773) (#3329)
Some checks failed
nix.yml / WebAssembly ABI 2: neighbouring frames for effect plug-ins (#2773) (#3329) (pull_request) Failing after 0s
sonarcloud.yml / WebAssembly ABI 2: neighbouring frames for effect plug-ins (#2773) (#3329) (pull_request) Failing after 0s
ci-macos.yml / WebAssembly ABI 2: neighbouring frames for effect plug-ins (#2773) (#3329) (push) Failing after 0s
ci.yml / WebAssembly ABI 2: neighbouring frames for effect plug-ins (#2773) (#3329) (push) Failing after 0s
nix.yml / WebAssembly ABI 2: neighbouring frames for effect plug-ins (#2773) (#3329) (push) Failing after 0s
sonarcloud.yml / WebAssembly ABI 2: neighbouring frames for effect plug-ins (#2773) (#3329) (push) Failing after 0s
ci.yml / WebAssembly ABI 2: neighbouring frames for effect plug-ins (#2773) (#3329) (pull_request) Failing after 0s
544eebf904
* 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>
alf merged commit 544eebf904 into main 2026-11-09 11:10:34 +00:00
alf deleted branch chore/sync-upstream-20261109 2026-11-09 11:10:34 +00:00
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
iris/effectcraft!23
No description provided.