After Effects measures the blinds' phase from the layer's centre and softens
both edges of the transparent band with a Gaussian of sigma = Feather / 2; the
band runs from the origin's phase to Completion x Width. EffectCraft measured
from the buffer corner and ramped only one edge linearly over Feather (a hard
edge on the other side). Fitted to AE 2026 renders of Completion 40,
Direction 30, Width 50, Feather 5 on a 960 x 540 and a 480 x 270 layer (the
origin is the centre + 0.6 px): case 715 was 499 of 5184 grid points off
(max 91/255, 7.1 % of pixels > 8), now 28 (0.056 %), all within ~6 px of the
layer edge where AE differs (up to 48/255, not modelled); away from it within
6/255 (test: one AE row of the 480 x 270 render). CPU and GPU (new erf-based
kernel, same term count). Completion 0 / 100 are unchanged, so the
Transitions presets keep their start and end frames.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
After Effects' Radial Blur keeps a layer's edges: Zoom 20 on a flat grey 960x540
solid over red (case 713) stays flat and opaque to its edge, and a zoomed
full-frame ramp (case 829) keeps the frame opaque (2/255 at x = 2, 253/255 at
x = 1917 on row 540). EffectCraft sampled transparency outside the layer, so its
edges faded and the red below showed through (713: 3.9 % of the frame off, max
64/255). Now 713 is identical to AE (max 0/255), CPU and GPU. CC Radial Blur
(already matching AE) is unchanged.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
With Glow Colors = Original Colors, After Effects thresholds each channel of
the straight colour separately and the glow is 8 x (value - threshold +
0.061) per channel (times Intensity), nothing below: fitted to AE 2026
renders of grey 0.65 / 0.8 / 0.9 / 1, orange (1, 0.5, 0) and (0.2, 0.6, 1)
solids at Threshold 40 / 60 / 80 % and Radius 10 / 30 (36 channel values,
exact to the 8-bit capture; an orange solid glows red only). EffectCraft
scaled the colour by a luminance threshold (k = (L - thr) / (1 - thr)), about
3.7 x too dim on white. Cases 806 / 810 / 811 (32 bpc): outside the layer
now within 3/255 of AE (806 white at Intensity 1: 119 = AE, was 32); grid
0 points off for 806-810. The glow's alpha (the blurred layer alpha) and the
Arbitrary Map / A & B colours and alpha-based glows are unchanged.
Stacked on fix-glow-halo (same lines). Not changed: Composite Original's
semantics are swapped against AE's names (EffectCraft's "On Top" adds the
glow over the original, which AE calls "Behind"; AE's "On Top" keeps the
original over the glow), so imported AE Glows at the default Behind show
no glow inside the layer (811 interior 204 vs AE 255).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
With Glow Based On Color Channels, After Effects gives the glow the layer's whole
alpha (blurred), not the thresholded part, and Intensity scales only its colour:
a layer below the threshold darkens what lies under its edge. Fitted to AE 2026
renders of a grey solid over red (cases 524, 807-809): the halo is the same at
Intensity 1 and 3 and with Composite Original Behind or On Top, and its edge is
an erfc step of sigma = 0.384 x Glow Radius at radius 10 and 30 (was radius / 2).
524 (Glow defaults on a 50 % grey solid): EffectCraft had no halo (max 116/255
off at the edge); now red 248/234/208/165/140 at 7.5/5.5/3.5/1.5/0.5 px outside
vs AE 249/235/206/164/140, max 2/255 over the frame, CPU and GPU. The blur
width applies to every glow; alpha-based glows keep their coverage rule
(thresholded alpha, scaled by Intensity). Not matched yet: the brightness of glows above the
threshold (AE about 3.7 x brighter for a white solid, cases 806, 810, 811).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Menus 628 rows (every menu catalog), panels 886 (695 shared with the Chinese
catalogs plus 191 Georgian-only), effect names 307 + 21 categories; gaps.md
and localization-parity.md now agree.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YMTAbGNRxnMEzRvYnQGphF
Without a Fill Mask, After Effects turns the layer into the fill colour and
applies Opacity to its alpha; nothing of the original shows through. AE 2026
renders Fill (0, 0.5, 1) at Opacity 50 % on a Gradient Ramp over a red solid
as premultiplied (0, 0.251, 0.502) at alpha 0.502 at every pixel; EffectCraft
mixed the fill with the ramp (mean difference 95.5/255), now within 1/255,
CPU and GPU. Invert fills the transparent part the same way. With a Fill
Mask the mix with the original is unchanged (not measured). Lottie's fill
effect (colour, alpha x opacity) now plays the same in EffectCraft.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
After Effects weighs each of the four points by its inverse squared
distance softened by Blend squared, 1 / (d^2 + Blend^2) in pixels: fitted to
AE 2026 renders of the default gradient at Blend 10, 100 and 300 and case
904 E16 at Blend 50 (power 2.00 at every Blend, softening 0 / 2367 / 9817 /
90127 = about Blend^2; mean error 0.27/255, max 0.9). EffectCraft used
1 / (d^2 / (100 Blend))^1.5, in which Blend cancels out: E16 was 34/255 off
on 99 % of the grid, now 0 grid points off, max 1/255, CPU and GPU.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
After Effects 2026 keys Luma Key and Extract (Channel Luminance) on Rec. 601
weights of the working-space values: Key Out Darker / Extract Black Point at
65, 166 and 24 on pure red, green and blue keep red (601: 76, 709: 54) and
blue (29 / 18) and key out green (150 / 182) - Rec. 709, which EffectCraft
used, decides all three the other way. Case 904 E18 (Extract 30 / 220 /
softness 10 on grey and colour steps): 513 of 5184 grid points off (pure blue
kept at 231 in AE, keyed out in EC), now 0, max 0. CPU and GPU.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
After Effects' Luma Key removes everything darker (or brighter) than Threshold
and ignores Tolerance for those two key types; Tolerance only sets the band of
Key Out Similar / Dissimilar. EffectCraft ramped the matte over Tolerance, so
case 719 (a 50 % grey, Key Out Darker, Threshold 140, Tolerance 20) kept about
80 % of the layer where AE keys it out completely.
Measured in AE 2026 on a vertical grey ramp (cases 812-814): Darker keys up to
level 139.9 and keeps 140.1 (EffectCraft now the same row); Similar keys levels
120.3-160.0; with Edge Thin 1 / Edge Feather 2.5 the matte rises over rows
591-596 (EffectCraft within 0.2 of AE's alpha there). CPU and GPU.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
In After Effects 2026 the non-legacy curve of Brightness -40 is the inverse
of Brightness +40 (within 2.6/255 on a full black-to-white ramp) and Contrast
-50 the inverse of Contrast +50. EffectCraft fitted the negative brightness
with its own power (2^(1.32 |b|) on v), 20/255 off AE at -40; the negatives
now use the reciprocal exponents of the positive curves: Brightness -40 max
6.2/255 (was 19.8), Contrast -50 4.1 (was 7.0); positives unchanged (40:
5.5, 80: 7.8, Contrast 50: 2.7, 90: 5.0; B20 C30: 6.6, which confirms
brightness before contrast). The #681 oracle samples still pass. CPU and GPU.
The positive curves' remaining 5-8/255 needs a better curve family (a
two-point spline fits each capture within 1.6/255), left open.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
After Effects 2026 in a 32 bpc project, Levels (Individual Controls) with RGB
(0.1, 0.9, gamma 1.5, 0.05, 0.95), Red Gamma 0.8, Green Input White 0.8 and
Blue Output Black 0.2 on grey steps 0..255 (case 904 E07): every step matches
"each channel's controls, then the RGB controls" with nothing clipped
(values below Input Black end below Output Black, above Input White above
Output White). EffectCraft ran RGB first and clipped "Off for 32 bpc Color"
(it could not see the bit depth): up to 27/255 off on 95 % of the grid; now
0 grid points off, max 1/255, CPU and GPU.
EffectEnv gains float_depth (the renderer sets it for 32 bpc projects), so
"Off for 32 bpc Color" clips in 8 / 16 bpc projects as before. Unclipped
values below 0 take the gamma mirrored through 0. Plain Levels keeps its
order (its channel controls were not measured); its clipping follows the same
rule. EffectCraft's own projects default to 8 bpc and are unchanged.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
All twelve sliders (Master, Red, Green, Blue) take After Effects'
ranges: Exposure valid -100..100, slider -4..4, 2 decimals (was -20..20,
slider -5..5); Offset -2..2, slider -0.5..0.5, 4 decimals (unchanged);
Gamma Correction valid and slider 0.1..10, 2 decimals (was 0.01..9.99,
slider 0.1..3).
Every value inside the old Exposure and Offset ranges stays valid. Saved
values are not clamped on load, so a gamma below 0.1 from an older
project or a Photoshop import (0.01..9.99) is kept and still renders
(the renderer's 0.01 floor is unchanged); only new edits clamp to 0.1.
Test of the ranges and of an old gamma surviving the load refresh.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
With Bypass Linear Light Conversion off, Exposure decoded and re-encoded
with the piecewise sRGB curve. After Effects 2026 renders (sRGB working
space, 32 bpc) of Offset 0.0005 / 0.002 / 0.02 / 0.1 on black measure
8 / 15 / 43 / 90, which a pure 2.2 power predicts (8.06 / 15.13 / 43.08 /
89.54) and the sRGB curve does not (1.65 / 6.59 / 38.68 / 89.04).
The effect now uses its own 2.2 power curve on the CPU and in the GPU
kernel; the shared colour functions and other effects are unchanged. As
before, the conversion applies whatever the working space, also a
linearised one. Negative values go through both curves mirrored (input
was clamped at 0 before), so defaults are an identity for 32-bpc values
and a negative Offset darkens past black without NaN.
New test against the AE values; existing Exposure tests still hold.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
After Effects tints Black & White's gray like a Color blend: the tint colour's
hue and saturation at the gray's luminosity (weights 0.3 / 0.59 / 0.11, channels
outside 0..1 pulled back toward the gray). EffectCraft used the gray as HSL
lightness. Measured in AE 2026, Tint Color [1, 0.5, 0]: a red solid at Reds 10
(case 717) AE (43, 21, 0), EffectCraft was (51, 26, 0), now (43, 21, 0); a
yellow solid at the default sliders (gray 0.6, case 825) AE (255, 129, 2), now
(255, 129, 3); white stays white. The six sliders already matched AE on eight
colours (cases 816, 817). CPU and GPU.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
After Effects' Tritone weighs the working-space values with Rec. 601 (0.299,
0.587, 0.114), as its Tint does; EffectCraft used Rec. 709. Case 718 (red solid,
Highlights [1,1,0.8], Midtones [0.6,0.2,0.2], Shadows [0,0,0.3], Blend 25):
AE (132, 23, 46), EffectCraft was (113, 16, 49), now (132, 23, 46). On a grey
ramp (case 815) the shadows / midtones / highlights mapping already matched and
still does within 1/255. CPU and GPU (fx_color op 4).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
After Effects 2026 (sRGB working space, not linearised) maps red, green,
blue and 50% grey solids at Tint's defaults to 76, 150, 29 and 128/255:
Rec. 601 weights on the working-space values, not Rec. 709. CPU and GPU
kernel changed; tests pin the four greys within 1/255.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Engine part of viewer picking: replace / add / remove the top-coverage ID at a
layer-space point in one undo step, at the time the Selection was read. The
aux channels come from the render's own path (Renderer::layer_aux, shared with
the effect host; footage at its source time, 3D precomps) through a renderer
set up like Session::render (expressions, render prefs, layer cache). An
optional scale snaps the point to the pixel a preview at that resolution
samples. New effects::crypto_select quotes names and falls back to <hex> for
unnamed, wildcard-looking or ambiguous names. effect.cryptomatteAt is the
read-only hover query.
Upstream now translates the Timeline, Composition and Effect Controls context menus itself, so
command_label is left for the dock's tab titles and the workspace bar, on menu_catalog.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YMTAbGNRxnMEzRvYnQGphF
A terminal already gets a live `[1/1] frame 16/180 ... ~14.2s left` line while
`effectcraft-cli render` runs. A program that starts the CLI (FilmCraft runs it to
render a composition for a clip) reads stderr through a pipe, so it saw nothing
until the render ended.
`--progress` prints one line per update instead, at most four a second:
progress <frames done> <frames total> <seconds elapsed> <seconds left, or - when unknown>
It has no effect on a terminal, which keeps its live line. Without the flag
nothing changes.
Documented in the usage text, the module header and docs/agents.md.
Tests: cargo fmt --check and cargo clippy --all-targets -D warnings pass; the
effectcraft-cli tests pass except render_out_is_relative_to_the_working_directory,
which already fails on Windows (it compares a canonicalize()d `\?\` path with the
path the CLI prints) and is unrelated to this change.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Runs every scenario N times (default 1, unchanged). Every run is still
appended to results.jsonl; with N > 1 one "kind": "summary" row per key
follows, whose metrics are the medians of the successful runs (user_s and
sys_s included, byte/instruction counts rounded) and whose summary holds
median, p90 (nearest rank, = max for N < 10), min and max. A failed run marks
the summary failed so the gate refuses it.
--compare uses the latest row per key; the table labels each side "median
of N" or "1 run" and warns when they differ, and --fail-over refuses such
keys. --repeat with --with is rejected. docs/testing.md documents the format.
`path.convertToBezier` only cleared `roto_bezier` on mask groups, so on a shape
layer it did nothing at all: a Rectangle, Ellipse or Polystar path stayed
parametric and its vertices could not be edited or animated. In After Effects
the command replaces such a path with an editable Path 1 of the same geometry.
The geometry is not re-derived. `parametric_path` calls the same
`effectcraft_path::{rect, ellipse, polystar}` functions `render::shapes::collect`
calls, with the same defaults for a property a group doesn't carry, so the path
that comes out is the shape that was on screen; `from_kurbo` and
`build::shape_path` then make an ordinary Path 1.
Masks are unchanged: shape items take precedence when selected, and with none
selected the command falls through to the old mask behaviour. Path Direction is
carried over rather than reset, since reversing a path is a separate command,
and the new path is left selected so its vertices can be edited straight away.
The parametric properties are read at the current time and the result is a
static path: a Size or Roundness animation cannot survive becoming a vertex
list, in After Effects either. Undo restores the parametric shape.
Add Layer Styles submenu to the Timeline and Composition viewer layer context menu, matching After Effects parity and the application Layer ▸ Layer Styles menu.
- Adds Layer Styles submenu between Blending Mode and Effects
- Exposes Layer Style Options..., Convert to Editable Styles, Show All, Remove All, and the 9 individual styles
- Translates Layer Styles across all 7 UI catalogs
- Adds regression test verifying submenu presence, position, and action invocation