Commit Graph
15 Commits
Author SHA1 Message Date
719b9170dd 3D rotation order, keyed Orientation, linear-to-eased keyframes and Timewarp behave as in After Effects (#1876)
* 3D: Orientation and X/Y/Z Rotation turn Z first, keyed Orientation slerps, as After Effects

After Effects composes a 3D layer's (and a camera's) Orientation and its X/Y/Z
Rotation as Rx * Ry * Rz each, Orientation before the axis rotations; EffectCraft
used Rz * Ry * Rx. Measured on synthetic AE 2026 cases: Orientation [10,20,30]
(488) was 5.2 % of the frame off and now matches to the anti-aliased edge (0.03 %);
X/Y/Z Rotation 10/20/30 (800), Orientation + X Rotation (801) and one-node
cameras (804, 805) likewise.

Keyed Orientation moves along the shortest arc between the keys (quaternion
slerp, eased in time, angles written in [0, 360)): keys [0,0,0] -> [10,20,30]
read back [6.2643, 9.3531, 15.2190] half-way where EffectCraft gave [5,10,15];
[0,0,0] -> [60,80,40] linear and eased match AE's read-backs within 0.002 deg.

lookAt() returns AE's angles (z axis on the target, x axis level; two AE
read-backs within 1e-3 deg). The camera tracker, VR editor, Look At and orbit
commands use the new decomposition.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Keyframes: a linear side next to an eased side has 16.67 % influence, as After Effects

In a segment that is Bezier on one side and linear on the other, the linear
side keeps the segment's average speed, but with the 16.67 % influence After
Effects shows for linear keys in the Keyframe Velocity dialog (and reports to
scripts), not 33.3 %. Measured on an After Effects 2026 time-remap render (a
square at x = 50 + 455 * remap): out of a key at 2 s (3.5, speed 0, influence
50 %) into a linear key at 4 s (0.5), AE plays 3.290 at 2.5 s and 2.657 at
3 s; EffectCraft played 3.308 and 2.629 (8 and 13 px off), now the same
square positions to the pixel.

LINEAR_SIDE_INFLUENCE is used by evaluation (scalar, per-dimension, paths and
spatial), side_ease (Graph Editor, velocity dialog, keyIn/OutTemporalEase) and
the Lottie export, so exported easing plays as EffectCraft does. Segments
linear on both sides stay straight lines.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Timewarp: retime the layer's source without the effects above it, as After Effects

After Effects' Timewarp reads the layer's source (with its masks) at the
retimed times and ignores the effects applied before it: a red solid with a
Gradient Ramp and then Timewarp (Speed 25) renders as the red solid in AE
2026 (EXPORTER e2 read-back). EffectCraft retimed the layer with its
effects (mean difference 127.5/255 over the comp), now identical (0, CPU and
GPU). Echo, Posterize Time and the other time effects keep reading the
effects before them, as measured before.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Image sequences: a gap in the numbering holds the previous frame, as After Effects

After Effects 2026 shows the last existing file across a gap in a sequence's
numbering (case 860: files 1, 2, 4, 5 show frame 2 at frame 3; VERIFY
read-back). EffectCraft drew colour bars there. The media pool now holds the
previous file (Footage::sequence_file_held); colour bars remain only where no
file precedes the frame. Missing-frame reports on import are unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Review: keyed Orientation uses LINEAR_SIDE_INFLUENCE for linear sides; real NaN assert

evaluate_orientation still gave a linear side (and the unreachable missing-key fallback)
1/3 influence while segment_value, side_ease and the Lottie export use
LINEAR_SIDE_INFLUENCE (1/6), so a keyed Orientation next to an eased key moved on a
different curve than every other property (CodeRabbit on #1876). New test:
orientation_linear_side_next_to_an_eased_side_matches_a_scalar (both directions).
The always-true NaN assert in keyed_orientation_slerps_as_after_effects now checks that
a non-finite key comes back as given; Property::value_at says why the match_id
"orientation" routing is safe.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Format keyframe orientation test (cargo fmt)

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

* Move the image-sequence gap change out of this branch

The gap change (hold the previous file instead of colour bars) reverses
#297's documented behaviour and goes to its own PR, as requested in review.
pool.rs, sequence.rs, the footage test and docs/footage.md / docs/agents.md
are back to main.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Codex <noreply@openai.com>
Co-authored-by: FredApps <153173854+FredApps@users.noreply.github.com>
2026-11-07 00:03:52 +01:00
vangel76andClaude Sonnet 5.5 99caf83c62 Merge upstream/main into rfx-text
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-29 20:31:32 +01:00
vangel76andClaude Sonnet 5.5 ca00da2f55 Merge upstream/main into rfx-masks-shapes
render: upstream moved the tests_*.rs modules into crates/render/src/tests/; the branch's
tests_mask_feather.rs now lives at tests/mask_feather.rs and is registered in tests.rs.
path: rect() keeps the branch's explicit-outline version with an added NaN guard on the
roundness clamp bound (main's fix for the same panic).

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-27 16:57:13 +01:00
vangel76andClaude Opus 5.5 236e8c87ae Merge main into rfx-text
Conflict in crates/text/src/layout.rs (paragraph direction at the top of
paragraph()), against the closure-to-method-path cleanup (4e9fa51f): kept this
branch's direction resolved once from BidiInfo.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-26 15:30:09 +01:00
aiongg 0173abde8c CI: dev-profile gate, one test binary per crate, nextest, line tables only (#2235)
* Dev profile: line tables only for workspace crates, no debug info for dependencies

* xtask ci: dev-profile gate, nextest, tests without examples, wasm --keep-going

* One integration-test binary per crate

* xtask ci: run effectcraft-gpu's shared-device tests in one cargo test process

* xtask ci: run every stage and report all failures

* xtask ci: name the stage type (clippy type_complexity)

* xtask ci: run every test pass and report all failures

* cargo fmt
2026-10-23 12:59:51 -04:00
vangel76andClaude Opus 5.5 2fd7d933ee Review: fidelity notes no longer claim the Lottie tracking export change
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 19:10:41 +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 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 a8de199aca #783: Object Matte fidelity plan; gaps and parity notes updated
Problem: Object Matte had no After Effects comparison, and none can be made
on this Linux machine (no After Effects). The gap notes still listed the
viewer tool, background job and disk cache as missing.

Fix: docs/fidelity/object-matte.md states plainly that nothing is measured
yet and pins down the comparison for when an After Effects 26.2+ reference
is available: four original or openly licensed clips (the synthetic moving
disk from the engine tests, the disk with a jump, two objects with a box
prompt, one CC0/CC BY real clip), the prompt and settings, where reference
mattes stay (gitignored), and the metrics: per-frame IoU against After
Effects (headline), IoU against ground truth, boundary distance, soft-edge
error, temporal stability, drift and time per frame, plus a proposed pass
bar left to the maintainers. Linked from docs/fidelity/README.md.
docs/gaps.md (#14) and docs/target-app-parity.md now list what landed and
leave the comparison as the one remaining item.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 14:07:22 +02:00
KattandClaude Opus 5.5 6240ed646e Keyframes: auto-Bezier spatial tangents follow After Effects
Measured against After Effects 26.3 with the original
examples/ae-spatial-tangents.jsx (three paths, ten keys, even and uneven
timing): an auto-Bezier key's out tangent is (next - previous) / 6 and
the in tangent its mirror, whatever the key times; an end key uses its
one neighbour, (neighbour - key) / 6. EffectCraft gave end keys none and
scaled middle tangents by segment length, so paths with auto-Bezier keys
ran up to 28 px from AE's. All ten tangents now match; path samples are
within 0.05 px.

Tests that relied on end keys having no tangent now expect AE's: Spatial
Bezier keeps auto keys' handles (linear keys still get a third), the
motion-path handle is drawn at a sixth, and a straight loopOut path is
compared within 1e-9. docs/fidelity records the method and scores.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 02:44:49 +05:30
Vikram Bhaskaran c0b3bde66f Add rendered frame fidelity scoring 2026-10-10 01:59:03 +11:00
Dexter 39e6907b5f G2: improve editing reliability and Windows rendering fidelity 2026-10-06 00:00:31 -05:00