Commit Graph
3365 Commits
Author SHA1 Message Date
vangel76andClaude Opus 5.5 8b715fc227 Masks: coarsen the feather grid instead of dropping its padding on huge layers
Above MAX_GRID_PX the padded feather grid fell back to the unpadded buffer, so a
feathered Add mask just outside a very large layer (e.g. 8192 x 8192, feather 40)
covered nothing and the whole layer vanished (CodeRabbit on #1874). The grid is now
coarsened by 2, 4, ... until it fits; radii and padding scale with it, so the feather
of an edge outside the layer still fades into it. The doc comment on the Linear falloff
no longer says it is unchanged: wide linear ramps now go through the coarse grid.
Regression tests: a_grid_too_big_is_coarsened_and_keeps_its_padding,
a_coarsened_grid_still_feathers_a_mask_outside_the_buffer.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 18:18:58 +02:00
vangel76andClaude Opus 5.5 d9205fa5f4 Curves: a natural cubic spline through the points, as After Effects
After Effects' Curves effect interpolates its points with a natural cubic
spline (zero curvature at the ends), clamped to 0..1: AE 2026 renders of an
RGB curve (0,0) (125,199) (255,255) and a Red curve (0,0) (128,44)
(255,255) (cases 962 / 963, ROUND4) give exactly the natural spline's values
on every grey step (0, 30, 59, 115, 164, 202, 227, 242, 250, 255 and 0, 0, 1,
6, 19, 44, 83, 135, 194, 255). EffectCraft used a monotone (Fritsch-Carlson)
spline: 34 / 67 / 125 / 171 ... on the RGB curve, up to 10/255 off (ROUND4
measured up to 6 levels on real projects); now within 1/255, CPU and GPU (the
same Hermite tables carry the spline's knot slopes). Lumetri's curves and
Glow's Arbitrary Map keep the monotone spline (not measured).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 16:54:31 +02:00
vangel76andClaude Opus 5.5 8b64074ce3 Text: per-character 3D rotation turns Z first, as a 3D layer and After Effects
With per-character 3D on, After Effects turns each character by Rx * Ry * Rz
(Z first), as it turns a 3D layer's X / Y / Z Rotation (case 931, AE 2026:
"H" at 400 px with animator X / Y / Z Rotation 40 / 30 / 20). EffectCraft
composed Rz * Ry * Rx, so the glyph faced another way: 23 of 5184 grid
points off (max 255), now 3 at the anti-aliased edge (mean 0.015/255). The
same order fix-orientation uses for layers; texts with one rotation axis
are unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 16:41:16 +02:00
vangel76andClaude Opus 5.5 8ea876914d Text animators: Tracking Amount in pixels, Subtract selectors stop at 0, as After Effects
A text animator's Tracking Amount is in pixels in After Effects 2026, not in
1/1000 em like the Character panel's tracking: Amount 30 on every character
adds 30 px between neighbours (half before, half after each) at 80 px and at
40 px. And a Subtract range selector over characters the first selector
leaves out keeps them at 0 instead of selecting them negatively. With both,
the EXPORTER's t8 layer D (Tracking 30 on characters 2-4 by index, Subtract
over the last 20 %) puts every glyph where AE does (it ended 88 px short,
1553 vs 1641; now 1641).

The "Tracking In" text preset animates 40 -> 0 px (was 400 -> 0 thousandths
of an em, about the same at 100 px text); Lottie export writes a style run's
tracking (1/1000 em) as pixels for its tracking animator, which Lottie
players add in pixels.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 16:41:15 +02:00
vangel76andClaude Opus 5.5 83b134cdc8 Text: right-to-left point text with a justified paragraph sits flush right, as After Effects
After Effects 2026 lays out right-to-left point text whose paragraph carries a
justified code (justify last left / centre / right, justify all) flush at
its start, the right, like right-aligned text (EXPORTER read-back t7: point
rows with codes 3-6 at -152..-8 from the anchor). EffectCraft placed it by
the last-line side (left / centre / left). Left-to-right point text and box
text are unchanged; AE's slightly wider right-to-left box wrapping (1-2 px
narrower word gaps) stays open.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 16:41:15 +02:00
vangel76andClaude Opus 5.5 8bc57bc7ad Text: Justify All balances the lines with the every-line composer, as After Effects
With Justify All After Effects stretches the paragraph's last line too, and
its every-line composer breaks the paragraph so that line is not a lone
word: a 400 px box that the other justifications break into 6 / 6 / 1 words
breaks 4 / 4 / 4 (AE 2026, EXPORTER read-back t6). EffectCraft's composer
left the last line's slack out of its cost, so "twelve" stood alone on a
stretched line; it now counts that slack for Justify All and every word
starts within 1 px of AE's (what remains in that box is the known box-text
baseline offset). Other justifications and the single-line composer are
unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 16:41:03 +02:00
vangel76andClaude Opus 5.5 a7255f7608 Text: box text's first baseline is the height of "d" below the box top, as After Effects
After Effects puts the first baseline of paragraph (box) text the height of the
font's lowercase "d" (in whole thousandths of an em) below the box top, at the
text's nominal size; superscript keeps the line there and only raises its glyphs.
EffectCraft used the font ascent of the drawn size plus the superscript rise.
Measured in AE 2026 (case 818, box at y -200): Times New Roman 100 px -130.50
(EffectCraft -110.9), 50 px -165.25, superscript -163.80 (EffectCraft drew it
15.8 px lower), Arial 100 px -128.40, superscript -161.70; now within 0.15 px.
517 (four wrapped lines, Times New Roman superscript): the line bands now land
on AE's rows exactly (336-388, 434-486, 532-584, 643-682; were 16 px lower).

A face without a "d" outline, and vertical type (not measured), keep the font
ascent. The paragraph-box test now
expects the caret (full ascent) to start a little above the box.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 16:41:03 +02:00
vangel76andClaude Opus 5.5 d57b73d4cb Shape rectangles start at the top-right, as After Effects, so Trim Paths cut the same segment
After Effects draws a Rectangle Path clockwise from its top-right corner, or
with round corners from the end of the top-right arc on the right edge;
Trim Paths measures from there (AE 2026, case 930: 400 x 300 rectangles,
Trim 0-25 % and 70 / 30). EffectCraft built the path with kurbo, starting at
the top-left corner, so trimmed rectangles drew another segment: case 930
was 86 of 5184 grid points off (max 255), now 5 at stroke edges. Start > End
was already drawn swapped, as in AE. Convert to Bezier now gives AE's vertex
order (top-right first); the engine test follows. Lottie rectangles share
the path and now start where lottie players start them.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 16:33:44 +02:00
vangel76andClaude Opus 5.5 710ffd9f7e Shapes: Repeater copy opacity steps 1 / Copies toward End Opacity, as After Effects
After Effects gives Repeater copy i the opacity Start + (End - Start) * i / Copies,
so the last copy stops one step short of End Opacity. EffectCraft reached End
Opacity at the last copy (i / (Copies - 1)). Measured in AE 2026 (case 709: 3
copies, End Opacity 40): copies at 100 / 80 / 60 % (EffectCraft 100 / 70 / 40);
the overlap of the two copies 92 % (EffectCraft 82 %). Now within 2/255 at the
sampled pixels.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 16:33:44 +02:00
vangel76andClaude Opus 5.5 25de452804 Masks: feather falloff as After Effects
The Smooth feather is three separable box passes of 2 round(0.37 F) + 1
pixels (a quadratic B-spline reaching ~1.11 F either side), fitted to
After Effects 2026 renders of feather 100, 300 and 1000 (rows, columns,
corner diagonal, case 398): max error under 1/255, where a Gaussian of
any width misses by 3/255 or more (it was sigma = F / 2). The coarse
grid for wide feathers picks the step whose three windows add up
closest to the full-resolution ones. Linear is unchanged (unmeasured).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 16:33:44 +02:00
vangel76andClaude Opus 5.5 b9e859fe3f Masks: feather reaches into the layer from a mask outside it, as in After Effects
The mask coverage was rasterised into the layer-sized buffer and then
blurred, so coverage outside the layer counted as 0: a feathered mask
past the layer edge faded at that edge, and one just outside the layer
gave nothing (the comment said the buffer grew; nothing grew it).

A feathered mask is now rasterised on a grid padded by the blur's whole
support (3 sigma + 3 for the Gaussian, the box radius for a linear
falloff), blurred there and cropped back to the buffer. Wide feathers
(sigma > 32 px) use a grid coarser per axis so the blur spans ~16 grid
pixels, which keeps the allocation near the buffer's size (feather 1000
on 1920x1080: a 160x134 grid instead of ~20 Mpx); the grid is capped,
feathers are clamped and non-finite ones ignored. Unfeathered masks and
masks inside the layer give the same coverage as before. The GPU uses
these CPU masks (adjustment footprint, masked sources): no GPU change.

Tests: case 398 of the .aep corpus rebuilt in the project model (red
solid, adjustment layer with a default Gradient Ramp, a 1920x200 mask
below the layer, feather 1000) within 3 levels of the Gaussian and
within 14 of After Effects' render; a mask right of a solid, a mask
larger than the layer (edges stay opaque), linear falloff, half
resolution, and huge or broken feathers.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 16:33:44 +02:00
vangel76andClaude Opus 5.5 d37c087975 Transform effect: skew after the rotation and drawn outside the layer, as After Effects
After Effects draws the Transform effect as position + K * R * S * (p - anchor)
with the skew K = rot(-axis) * shearY(tan skew) * rot(axis) applied after the
rotation, and keeps what lands outside the layer's bounds. EffectCraft skewed
before rotating (shearX about the axis) and clipped to the layer.

Measured in AE 2026 on a grey 960x540 solid (cases 723, 819, 820): 723 (anchor,
position, scale 120/80, skew 10 axis 20, rotation 30, opacity 70) differed in
11.25 % of the frame and now in 0.065 % (edges, max 16/255), CPU and GPU alike;
819 / 820 (skew 15 axis 60, rotation -25, scale 130/70, anchor) match to the
edge. The buffer grows on each side by that side's overshoot (also for the
motion-blur samples), capped at 16 384 px a side and 16 Mpx in all so a layer
moved far away costs a bounded allocation (regression test); adjustment layers
keep their size.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 16:25:44 +02:00
vangel76andClaude Opus 5.5 60cf195236 Fractal / Turbulent Noise: lattice cells are two thirds of Scale, as After Effects
After Effects 2026 draws Fractal Noise's Block noise at Scale 100 and
Complexity 1 in cells of 66.67 px (the value changes every 66.67 px along a
row), not 100 px; Soft Linear noise has the matching correlation length.
EffectCraft's lattice is now Scale x 2/3 px (NOISE_CELL), CPU and GPU. Case
904 E03 (Soft Linear, Complexity 4, Scale 100): the noise's autocorrelation
at 32 px was 0.68 (AE 0.41), now 0.54; pixel values cannot match (other
seeds). Still open: AE's noise spreads about 20 % wider around its mean (std
48 vs 40/255 in E03). Existing projects and the Backgrounds presets with
Fractal Noise get finer noise (two thirds of the former cell size).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 16:25:44 +02:00
vangel76andClaude Opus 5.5 8d41ef7218 Radial Wipe: Feather in pixels on both edges of the wedge, as After Effects
After Effects feathers both edges of the wiped wedge (the start ray too) with
a Gaussian whose width is constant in pixels: Completion 40, Start Angle 30,
Counterclockwise, Feather 20 (AE 2026, case 904 E12) fits sigma = 0.4 x
Feather = 8.0 px at every radius (mean alpha error 0.0002 over the frame).
EffectCraft ramped only the moving edge, linearly over Feather degrees, so
the edge was 14 px wide near the centre and 140 px wide at 400 px out, and
the start edge was hard: 378 of 5184 grid points off (max 111/255, 6.6 % of
pixels > 8), now 1 (max 3), 0.009 % of pixels > 8 (near the centre). CPU and
GPU (the kernel now measures distances to the two rays). 0 % and 100 % are
unchanged, so the three Transitions presets keep their end frames; their
Feather (6 / 10) now means pixels.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 16:25:44 +02:00
vangel76andClaude Opus 5.5 47b3582a0a Venetian Blinds: stripes from the layer centre, Gaussian feather on both edges, as After Effects
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>
2026-10-19 16:24:05 +02:00
vangel76andClaude Opus 5.5 ae7081077f Radial Blur: samples outside the layer repeat its edge, as After Effects
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>
2026-10-19 16:23:42 +02:00
vangel76andClaude Opus 5.5 a8d4514a1b Glow: per-channel bright pass with After Effects' gain, glows above the threshold as bright as After Effects
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>
2026-10-19 16:23:25 +02:00
vangel76andClaude Opus 5.5 f4fbdc6c25 Glow: the glow covers the layer's blurred alpha, blur sigma 0.384 x radius, as After Effects
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>
2026-10-19 16:23:25 +02:00
Davit MatchakhelidzeandClaude Opus 5.5 2447b54856 docs: Georgian catalog counts at this head
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
2026-10-19 18:16:21 +04:00
Davit MatchakhelidzeandClaude Opus 5.5 dd29665939 text: the Georgian fallback test goes through fallback_for
system_fallback is the scan-order search; fallback_for is where the Georgian
families are preferred, so the test asks it for Mkhedruli in Inter.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YMTAbGNRxnMEzRvYnQGphF
2026-10-19 18:16:21 +04:00
vangel76andClaude Opus 5.5 84ffc8453e Fill: Opacity is the filled layer's opacity, as After Effects
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>
2026-10-19 16:16:12 +02:00
vangel76andClaude Opus 5.5 d7854b84a3 4-Color Gradient: weights 1 / (d² + Blend²), as After Effects
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>
2026-10-19 16:16:02 +02:00
vangel76andClaude Opus 5.5 75271bfe6c Luma Key and Extract: Rec. 601 luminance, as After Effects
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>
2026-10-19 16:16:01 +02:00
Davit MatchakhelidzeandClaude Opus 5.5 4d62e21e90 Merge i18n-improvements (CodeRabbit fixes)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YMTAbGNRxnMEzRvYnQGphF
2026-10-19 18:15:46 +04:00
Davit MatchakhelidzeandClaude Opus 5.5 ad8db289cf i18n: Settings page titles read the menu bar's Settings rows
The panel catalog's \"Type\" is the kind (Camera Settings, the Project column), so
the Type page drew as \"kind\" in Chinese; its title now comes from the
app.settings menu row (文字), as the Settings submenu draws it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YMTAbGNRxnMEzRvYnQGphF
2026-10-19 18:15:35 +04:00
Davit MatchakhelidzeandClaude Opus 5.5 60dab98e9b i18n: saved workspace names stay verbatim in the workspace menu
Only the built-in workspaces read the Window ▸ Workspace rows; a name the user
saved (\"Composition\", say) no longer falls through to the panel catalog.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YMTAbGNRxnMEzRvYnQGphF
2026-10-19 18:15:35 +04:00
vangel76andClaude Opus 5.5 39bd0efac2 Luma Key: Key Out Brighter and Darker cut hard at Threshold, as After Effects
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>
2026-10-19 16:15:02 +02:00
vangel76andClaude Opus 5.5 dc9f15ada1 Brightness & Contrast: negative settings invert the positive curves, as After Effects
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>
2026-10-19 16:15:02 +02:00
vangel76andClaude Opus 5.5 515cc3d5f7 Levels: channel controls before RGB, "Off for 32 bpc Color" unclipped in 32 bpc, as After Effects
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>
2026-10-19 16:14:42 +02:00
vangel76andClaude Opus 5.5 617b0a578d Exposure: After Effects parameter ranges
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>
2026-10-19 16:14:26 +02:00
vangel76andClaude Opus 5.5 c7060e2d75 Exposure: gamma 2.2 linear-light conversion, as After Effects
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>
2026-10-19 16:14:26 +02:00
vangel76andClaude Opus 5.5 70c1349cbc Black & White: Tint keeps the gray's luminosity, as After Effects
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>
2026-10-19 16:14:21 +02:00
vangel76andClaude Opus 5.5 960f41d50b Tritone: Rec. 601 luminance, as After Effects
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>
2026-10-19 16:13:41 +02:00
vangel76andClaude Opus 5.5 fb16d5573e Tint: Rec. 601 luminance weights, as After Effects
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>
2026-10-19 16:12:50 +02:00
SBaksa 71aafd6307 Text Range Selector: test the Timeline shows Index-unit values without % (#1814)
Start, End and Offset are read as painted in the Timeline: with % under
Units = Percentage, without it under Units = Index. Fails on the old
suffix rule ("0.0%").
2026-10-20 01:05:15 +11:00
dorfee 80158bb69b ScriptUI: install scheduled task runner in host sessions 2026-10-19 16:45:39 +03:00
SBaksa c17f9eb959 Text Range Selector: Start, End and Offset show as counts with Units = Index (#1814)
With Units set to Index the selector already counts characters (words,
lines), but the timeline kept showing Start, End and Offset as
percentages ("3.0%"), so switching looked like it did nothing. They are
now shown without the % sign while Units is Index
(render::text::in_index_units).
2026-10-19 21:08:16 +11:00
Camille Moine 8756ec1846 Timeline: Preserve Transparency toggles from the clicked row (#1849)
layer.setSwitch with no value toggles relative to the first selected layer in
composition order, so with a mixed selection (A checked, C unchecked) clicking
C's box could leave C unchanged. The checkbox now sends the value it toggles
to, as the switches do.
2026-10-19 10:25:17 +02:00
Camille Moine f72e17a2bb Engine: Video's Alt-click and Hide Other Video take cameras and lights along
The Timeline draws the Video switch (the eye) on every layer's row, nulls,
cameras and lights included, but set_switch_others and hide_other_video
skipped cameras and lights: Alt-clicking the eye of a selected layer neither
set them apart with the selection nor hid them with the rest.

Both now use the rule the eye cell shows: every layer but track mattes.
2026-10-19 10:25:17 +02:00
NetterSilverandClaude Haiku 5.5 7930fb2019 Use frozen Object Matte in sessions without the freezing model
Fixes #1457

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 10:09:07 +02:00
Camille Moine 4f3fa4d0fb docs: the Timeline row controls act on the selection (#1849)
One bullet in the Timeline section of docs/agents.md and a note on the
ui-parity Timeline row, next to the other multi-selection fixes.
2026-10-19 09:55:40 +02:00
Camille Moine 16d43346c4 Timeline: the label swatch and the Modes column act on the selection (#1849)
The label swatch's menu, the Blending Mode menu and Preserve Transparency
passed the clicked layer alone, so a colour or a mode had to be set one layer
at a time. They now act on the whole selection, with the Modes column edits
going only to the selected layers that have video, as its cells do.

The preserve-transparency checkbox also gets an automation id, like the cells
around it.
2026-10-19 09:55:24 +02:00
Camille Moine bf7aff11f8 Timeline: layer switches act on every selected layer (#1849)
A switch click on one of several selected layers passed that layer alone to
`layer.setSwitch`, so Lock, 3D, Video (and the rest of the A/V Features and
Switches columns) had to be set one layer at a time.

The click now gives the switch to the whole selection, with the layers it
doesn't apply to left out (3D on a camera, Effect on a layer without effects,
Audio on a layer without audio, ...). The targets are picked when the press
happens, so drawing a row costs nothing more than before. A row that isn't
selected still changes that layer alone, pressing and dragging over rows is
unchanged, and Alt-clicking an A/V feature sets the selected layers apart.
2026-10-19 09:54:16 +02:00
NetterSilverandClaude Haiku 5.5 ae5d090aed Hold position between identical auto-Bézier spatial keys
Fixes #1675

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 09:16:41 +02:00
NetterSilverandClaude Haiku 5.5 26636bfb18 Make Fractal Noise evolution progress linearly
Fixes #1816

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-19 07:00:02 +00:00
Matej Kozlovský d74cb70938 Cryptomatte pick: snap to the effect's input buffer grid, not the preview scale
At preview scales from 0.75 to 1 footage keeps native pixels, a proxy sets
its own buffer scale at any render scale, a Preserve Resolution precomp is
drawn at full size, and earlier effects can pad or offset the buffer, so
snapping to the preview grid could pick a different ID than the rendered
matte. Use the scale and offset of the buffer the Cryptomatte effect
receives (layer_input, rendered once and then cached).

The pixel centre goes to an aux point through effectcraft_effects::aux_point,
which index_map_at now calls too, so the two round identically (a division
vs the reciprocal picked the other ID on a 104 px proxy of 1920 px footage).

An unknown effect uid errors "no such effect" and a layer without pixels
"this layer has no pixels", as effect.pickColor does.
2026-10-19 08:40:16 +02:00
Matej Kozlovský 76098665b0 Cryptomatte: effect.pickCryptomatte picks the ID under a point into the Selection (#473)
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.
2026-10-19 06:10:27 +02:00
heojunfoandClaude Opus 5.5 4bc40c7ac3 Text: grow Faux Bold per axis under a non-uniform scale (#1676)
Synthetic bold grows a glyph's outline in its own space, so a
non-uniform character Scale stretches it more along one axis. The patch
and layer bounds reserved it through mean_scale and could clip the
stretched side; they now reserve how far the bold reaches along x and y.

A run of solid fills grows its glyphs together in layer space by one
radius, which only matches when the bold stays round there: a bold glyph
whose matrix stretches or skews is no longer gathered into a run.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-19 11:04:36 +09:00
Vikram Bhaskaran d3fd2c58d7 Key browser preview caches on a file generation, and hash bytes only when that key misses.
Replacing a virtual file bumps a counter the UI lookup reads. The content hash runs on that miss, from a callback, so the frame path does not stat every footage item or hash on every store write.
2026-10-19 13:04:16 +11:00
heojunfoandClaude Opus 5.5 a5f096324d Text: draw Faux Bold and synthetic bold (#1676)
The layout marks a glyph synth_bold when Faux Bold is on, or when a bold
style is asked of a family without a bold face, but the renderer never
read it, so both drew as regular.

PlacedGlyph now carries the bold radius (0.03 em, which brings Inter
Regular's stems to Inter Bold's). A bold fill is the outline's coverage
merged with a round stroke twice that wide, and a bold glyph's stroke is
the band between the outline grown by radius ± half the stroke width, so
it follows the bolder shape. Runs of solid fills only merge glyphs of the
same bold radius, and the patch and layer bounds grow by it.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-19 10:36:16 +09:00