Merge remote-tracking branch 'upstream/main' into aep-import-thirdparty

This commit is contained in:
vangel76 committed 2026-11-07 19:42:21 +01:00
commit 2e738606f3
45 files changed
+2550 -317

No files matched your search

+26 -2
View File
@@ -261,6 +261,30 @@ build real projects through these interfaces; they are worked examples of everyt
`layer.centerAnchor` skip them and fail when every target is locked ("… is locked"); Select
All and `layer.selectNext` / `selectPrevious` step over them. Unlock with
`layer.setSwitch {"layers": [...], "switch": "lock", "value": false}` or `layer.unlockAll`.
* **Un-precompose**: `layer.unprecompose {layer?, force?, dryRun?}` (Layer ▸ Un-precompose) expands the
selected pre-comp layer into copies of its composition's layers at its place (order, keyframes,
effects, masks, parenting, mattes, markers kept; timing moved by the layer's Start and trimmed to
what it showed; Position minus Anchor Point added to the unparented ones). One undo step; the
nested comp stays in the project; the nested comp's frame no longer clips what its layers draw
outside it. Only a **locked** pre-comp layer is refused (with or without `force`), changing
nothing. Everything that would change the picture or drop something is a warning: the pre-comp
layer has a parent or matte, effects, masks, layer styles, a non-default Scale / Rotation /
Opacity, an animated transform, time remap or stretch, a blending mode, Video or Audio off, Solo
or Guide on, the 3D / collapse / adjustment switch or Preserve Transparency, or is used by another
layer (parent, matte or a layer property), or an expression of another layer names it (by name in
quotes or as `layer(<index>)`; listed per property, the expression is left as written and will
no longer find it); or the nested comp holds a camera, light, adjustment,
3D, collapsing or soloed layer, or a layer with a blending mode or Preserve Transparency, preserves
a frame rate other than the comp's, has a motion-blur shutter other than the comp's (with motion
blur layers), or has an unparented layer with a Position expression while the pre-comp layer's
Position differs from its Anchor Point (the move is added to stored values only). Without
`force` such a call is an error listing every reason and nothing changes; `dryRun: true` returns
`{dryRun, warnings}` without changing anything. With `force: true` it unpacks anyway and returns
`{layers, warnings}`: what the pre-comp layer itself carried (effects, masks, styles, transform
beyond Position, time remap, blending mode, switches, its parent and matte) is dropped, and other
layers' parent, track matte and layer-property links to it are removed. The menu shows the
reasons and asks (Unpack Anyway / Cancel, `dialog.unprecompose.force` /
`dialog.unprecompose.cancel`); a layer without reasons unpacks without asking.
* **Quick Set Anchor**: `layer.quickSetAnchor {point: topLeft|top|topRight|left|center|right|bottomLeft|bottom|bottomRight, layers?}`
(Layer ▸ Transform ▸ Quick Set Anchor) moves the Anchor Point of 2D layers to that point of their
content and shifts Position and its keys so the layers don't move, in one undo step. 3D and
@@ -302,8 +326,8 @@ build real projects through these interfaces; they are worked examples of everyt
file's whole numbered run as one item (several picked frames: that range; a folder: each run in
it, also without `sequence`). Without `"sequence": true` a picked or dropped numbered file imports
as one still, as in After Effects; `"alphabetical": true`: Force Alphabetical Order, the files
play one after another) at `frameRate` or 30 fps (Settings ▸ Import). Missing frames show
colour bars, as in After Effects. `file.interpretFootage {"items":[id], "frameRate":12,
play one after another) at `frameRate` or 30 fps (Settings ▸ Import). A gap in the numbering holds
the previous frame, as in After Effects. `file.interpretFootage {"items":[id], "frameRate":12,
"startTimecode":1001}` conforms them and sets Override Start (the item and layers that ran to its end get the new
length). See [footage.md](footage.md).
* **Colour of footage**: `file.interpretFootage {"items":[id], "preserveRgb":true}` is Interpret
+2 -1
View File
@@ -44,7 +44,7 @@ corpus compares renders, each effect is assumed to differ somewhere, and users k
| Simulation | 18 | 18 | Particle Playground lacks Particle Exploder, text particles, ephemeral mapper; CC Particle World camera fixed (#397) |
| Stylize | 25 | 25 | Glow's halo (coverage of a dim layer's edge) and blur width match After Effects 2026 renders; glows above the threshold match too (each channel 8 × (value − threshold + 0.061), measured at three thresholds and two radii); Composite Original's labels are swapped against After Effects (EffectCraft's On Top adds the glow over the original, which After Effects calls Behind); Motion Tile output size (#369) |
| Text | 2 | 2 | — |
| Time | 8 | 8 | #535 (Pixel Motion Blur, Vector Detail) is closed |
| Time | 8 | 8 | Timewarp retimes the layer's source and masks without the effects above it, as After Effects 2026; #535 (Pixel Motion Blur, Vector Detail) is closed |
| Transition | 17 | 17 | Venetian Blinds matches After Effects 2026 renders (band phase from the layer centre, Gaussian feather on both edges) except within ~6 px of the layer edge (up to 48/255); Radial Wipe's Feather matches After Effects 2026 (a Gaussian of σ = 0.4 × Feather pixels on both edges of the wedge) |
| Utility | 9 | 7 | — |
@@ -71,6 +71,7 @@ the GPU is performance, not parity.
| 2026-10-19 | minor | Radial Wipe: Feather is in pixels on both edges of the wiped wedge (was degrees on the moving edge only), measured against After Effects 2026 (CPU and GPU) |
| 2026-10-19 | minor | Fractal / Turbulent Noise: lattice cell = Scale × 2/3 px (Block noise every 66.7 px at Scale 100, as After Effects 2026), CPU and GPU |
| 2026-10-19 | minor | Transform: After Effects' skew order and output beyond the layer bounds, measured against After Effects 2026 renders of three cases (CPU and GPU) |
| 2026-10-19 | minor | Timewarp ignores the effects above it (source and masks only), measured against After Effects 2026 |
| 2026-10-19 | minor | Tritone uses Rec. 601 luminance, measured against After Effects 2026 renders of a red solid and a grey ramp (CPU and GPU) |
| 2026-10-19 | minor | Black & White's Tint keeps the gray's luminosity (Color blend), measured against After Effects 2026 renders (CPU and GPU) |
| 2026-10-19 | minor | Levels: "Off for 32 bpc Color" no longer clips in 32 bpc projects, unclipped values extrapolate below Output Black; Levels (Individual Controls) applies the channel controls before the RGB ones, measured against After Effects 2026 (CPU and GPU) |
+12
View File
@@ -71,6 +71,18 @@ After the fix, all ten tangents equal AE's to the printed 0.001 px, and the two
test `spatial_auto_bezier_tangents_follow_after_effects` checks the rule on other original keys,
including a timing change. AE's output stays local; only the script and these scores are tracked.
## Linear side next to an eased side
Measured on 19 October 2026 with After Effects 2026 (26.2) through a time-remapped precomposition
(a square moving at 455 px per second of source time, read off rendered frames to the pixel): a
segment from a Bezier out side (speed 0, influence 50 %) at 2 s, value 3.5, into a linear key at
4 s, value 0.5, plays 3.290 at 2.5 s and 2.657 at 3 s. EffectCraft gave the linear side the
segment's average speed at 33.3 % influence (3.308 and 2.629, 8 and 13 px off); AE uses the average
speed at 16.67 %, the influence its Keyframe Velocity dialog shows for linear keys. Now the same
square positions to the pixel. `LINEAR_SIDE_INFLUENCE` holds the value for evaluation, the Graph
Editor / velocity dialog sides and the Lottie export; segments that are linear on both sides stay
straight. Regression test: `a_linear_side_next_to_an_eased_side_matches_after_effects`.
## Justify All with the every-line composer
Measured on 19 October 2026 with After Effects 2026 (26.2) on box text (EXPORTER read-back t6):
+2 -2
View File
@@ -47,8 +47,8 @@ Stills of any format EffectCraft reads can form a sequence: PNG, JPEG, TIFF, Ope
WebP. Layered and vector documents (PSD, SVG, PDF) import one by one.
**Missing frames.** Where the numbering skips a number (`shot_0003.png` is missing between
`0002` and `0004`), the sequence shows a placeholder of colour bars for that frame, as After
Effects does, so every other frame stays at its number. Render or copy the missing files into the
`0002` and `0004`), the sequence holds the previous frame (`0002`) there, as After Effects 2026
does, so every other frame stays at its number. Render or copy the missing files into the
folder and choose File ▸ Reload Footage to fill the gaps.
Agents: `file.import {"paths": ["/shots/shot_0001.png"], "sequence": true, "frameRate": 24}`.