Commit Graph
2768 Commits
Author SHA1 Message Date
bflatasticandClaude Opus 5.5 cef812b4c1 UI tests: the marker-name test is a module of the tests/it binary (#2491)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-29 23:17:07 +07:00
bflatastic d5163b6125 Merge remote-tracking branch 'origin/main' into HEAD 2026-10-29 23:16:09 +07:00
bflatasticandClaude Opus 5.5 c99b20cac3 av1enc: inline the DCT stage helpers so const-generic sizes fold through them
The strict-clippy split of inverse_dct (#2496) passes n at run time; inlining keeps
inverse_dct_n's compile-time sizes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-29 23:15:48 +07:00
bflatastic d1b736c594 Merge remote-tracking branch 'origin/main' into HEAD 2026-10-29 23:15:17 +07:00
zitann2020andDeepSeek V4.1 Flash 197d6cd229 fix(text): the tests and docs follow the layer being kept
Review of the first commit found three places that still asserted the old cleanup: the UI integration
test (which would have failed CI), docs/agents.md, and the comments on TextEdit::created, layer.newText
and the engine test itself.

Co-Authored-By: DeepSeek V4.1 Flash <noreply@deepseek.com>
2026-10-30 01:09:35 +09:00
zitann2020andDeepSeek V4.1 Flash f262e39c63 fix(text): keep an empty Type-tool layer, as After Effects does
Clicking away from a Type-tool layer without typing deleted it, so a click that was meant to place the
text point lost the layer. AE keeps it in the timeline as <空白のテキストレイヤー>, and the layer came from the
user's click rather than being a mistake to clean up.

edit.deselectAll already routes through text.endEdit, so one change covers both paths. The tests that
asserted the old cleanup now assert the layer survives.

Co-Authored-By: DeepSeek V4.1 Flash <noreply@deepseek.com>
2026-10-30 00:31:37 +09:00
Altynzhan Karybai 102b20207d Refactor animation presets reveal ID 2026-10-29 19:43:50 +05:00
Camille Moine a2f8913eb3 Expressions: follow Media Replacement source dimensions (#1747)
LayerInfo, sourceRectAtTime and Layer.source now resolve the effective footage item/size through the collapsed instance EvalCtx, matching the rendered pixels. Adds a regression test with different original and replacement footage sizes.
2026-10-29 15:21:16 +01:00
Camille Moine df0a88b795 Fix collapsed precomp Essential Property overrides (#1747)
Carry property, Font and Media Replacement overrides into the collapsed nested EvalCtx so nested layers render beyond the precomp frame instead of falling back to a clipped, flattened image. Key the layer cache on instance overrides to keep distinct collapsed instances isolated.
2026-10-29 15:21:16 +01:00
Claude 77050532a4 1010: keep authored easing on segments the baking cap leaves unchecked
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RDvxCS8xcR28VArjzn1x7U
2026-10-29 13:50:56 +00:00
zitann2020andDeepSeek V4.1 Flash 2a6cece4ea i18n(ja): the Generate effect category is 描画
JAPANESE_CATEGORIES had 20 of the 21 the Simplified table carries, so the Generate group in the
Effect menu drew its English name. AE calls it 描画.

Co-Authored-By: DeepSeek V4.1 Flash <noreply@deepseek.com>
2026-10-29 22:04:20 +09:00
Claude b0be02fff4 1010: cap baked Orientation keys per property; leave one-node rigs under a mirrored parent as authored
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RDvxCS8xcR28VArjzn1x7U
2026-10-29 11:52:23 +00:00
Minher0 93aed3bfd6 instance3d: the copy's cache key covers DoF, animated models and env light
The referenced model's solo render goes through the comp camera: its
depth of field (focus, aperture, iris, highlights) blurs it, none of
which is in the projection matrix — the evaluated Dof is hashed in now
(CodeRabbit, review of #2410).

A model with an animation clip selected is posed at its layer time
(Animation Speed and Looping are static and hashed): the layer time is
folded into the key, so every time is its own entry. A model without a
clip keeps one key across times, as before.

An Environment light's image lights Advanced 3D models, and its source
can be any layer's render (or any environment layer) — too open-ended
to hash: while one is on, the read is not cached. Each is covered by a
render test.
2026-10-29 11:50:58 +00:00
Claude b5b77f446e #1417: Reload Footage re-reads a file's markers; index marker times when merging them
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RDvxCS8xcR28VArjzn1x7U
2026-10-29 11:41:27 +00:00
FeiLiuEM 1354aa4019 i18n: the 31 tool names are translated (zh-hans, zh-hant)
The toolbar's tool labels come from Tool::label() through header.rs; they were the last English
surface on the chrome. 31 rows, Simplified and Traditional, and the header asks the catalog.
2026-10-29 19:39:52 +08:00
FeiLiuEM 02211f29eb i18n: the Preview panel's labels reach the catalog
The Preview panel draws Shortcut, Range, Play From, Frame Rate, Resolution, Overlays, Layer
Controls, Loop, Cache Before Playback, Pre-roll, Post-roll, Full Screen and the caching hint from a
local closure, a check table and a roll tuple, so the call-shape scan cannot see them and no catalog
had rows for most of them. They ask the catalog now, with Simplified and Traditional rows.

Verified on Linux: fmt, cargo test -p effectcraft-ui-egui, clippy --all-targets -D warnings.
2026-10-29 19:33:57 +08:00
Claude 942b478472 1063: name the companion properties of text animators (Track Type, Skew Axis, X / Y Rotation)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RDvxCS8xcR28VArjzn1x7U
2026-10-29 11:22:49 +00:00
Christopher Linnett b7242a8670 fix: progressive blur holds two levels at a time, not every level (#2092 review follow-up) 2026-10-29 19:22:28 +08:00
Camille Moine 7038f4f0ee Expressions: read bezier curve by position (#1884)
A missing or unusable curve no longer consumes the last value. The long form reads argument 5 and the short form argument 3, with the other arities falling back to linear interpolation. Adds the missing-curve and four-element-array cases reported in review.
2026-10-29 11:58:35 +01:00
Camille Moine efcdad04af Expressions: reject malformed bezier curves and bound the y error
- accept only four-element arrays for bezier(): extra values make the curve
  malformed, so it falls back to linear like the other invalid forms (#1884);
- stop Newton on the estimated y error (f * dy/dx) instead of a residual in x
  alone: near the endpoints dy/dx is in the thousands, so a 1e-9 residual in x
  could still move the returned value;
- tests: a five-element curve is linear, and three steep curves match a
  bisection reference within 1e-6.
2026-10-29 11:58:34 +01:00
Camille Moine 06bdd7e2b6 Expressions: offer bezier in the language menu and auto-complete (#1884)
Add the helper to the expression editor's completions (syntax highlighting and auto-complete) and to the Expression Language menu's Interpolation group, so accepting it inserts the call parentheses like linear/ease.
2026-10-29 11:58:34 +01:00
Camille Moine 53399c2831 Expressions: cubic-Bezier easing helper (bezier(...)) (#1884)
Add bezier(t, tMin, tMax, v1, v2, [x1, y1, x2, y2]) and the short bezier(t, v1, v2, curve) form: a CSS cubic-bezier easing curve solved with Newton-Raphson and a bisection fallback.

Scalars and arrays work like linear/ease; x1/x2 clamp to 0..1, y1/y2 may overshoot, t clamps to tMin..tMax, and a curve that is not four finite numbers falls back to linear instead of throwing.

Tests cover known curves (ease is [1/3, 0, 2/3, 1]), clamps, arrays, the short form, invalid curves and overshoot, plus two fuzz seeds.

Closes #1884.
2026-10-29 11:58:34 +01:00
Christopher Linnett 280a400be4 Merge origin/main into fix/issue-2092-camera-focus-crash
Conflicts were main's new code next to this branch's additions; both kept:
- crates/effects/src/lib.rs: main's Buf::pad_sides stays as main wrote it
  (Transform's transform_grow bounds that padding itself); Buf::pad keeps
  this branch's effective-pad clamp.
- crates/raster/src/lib.rs: main's quantize_px/round_half_up and this
  branch's MAX_PADDED_SIDE (still equal to limits::MAX_SIZE on main).
2026-10-29 18:44:49 +08:00
Minher0 7f1ec94810 Merge branch 'feat/2100-instance3d-layer-create' (synced with main) 2026-10-29 10:18:43 +00:00
Minher0 5b2f305f72 instance3d: a dedicated 3D Layer Instance effect, and the copy is cached
CC Composite stays After Effects-pure: its Layer parameter is gone, so
parameter indices match AE again (scripts and expressions that address
parameters by index). The model reference lives in its own effect,
ec.3d.instance3d (3D Channel, CPU, one layer parameter), which replaces
the layer's pixels with the referenced layer's render — alpha included.

A referenced model's solo render is now hashed into the owner's cache key
instead of declining the entry (Bflat, review of #2410): the layer, its
animated values and transform, the mesh item, the comp camera and lights,
draft 3D, the renderer setting and the in/out gate. Covered by a render
test: the copy is cached, served on the second render, and re-rendered
when the camera pans or the model leaves its in/out range.
2026-10-29 10:18:17 +00:00
Claude 0dd14e2706 Merge main into fix/1417-wav-markers
Footage.markers is added to the split footage.rs (#2491); the host integration test joins the
shared tests/it binary.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RDvxCS8xcR28VArjzn1x7U
2026-10-29 10:12:23 +00:00
Claude 51747b7f67 Merge main into fix/1010-orientation-followup
The parent-space code moved to cmd/layer/parent.rs (#2491); this branch's changes to it are
carried over unchanged.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RDvxCS8xcR28VArjzn1x7U
2026-10-29 09:31:29 +00:00
Claude 55761e226f Merge main into fix/1063-text-animator-stacked
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RDvxCS8xcR28VArjzn1x7U
2026-10-29 09:27:06 +00:00
Claude 6a8e28126e #2459: test the text-field Undo and Redo labels in the native Edit menu
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RDvxCS8xcR28VArjzn1x7U
2026-10-29 09:16:34 +00:00
Claude Code 7a3bd9dcdf #2465: test the Linear ease preset's interpolation and edited speeds
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RDvxCS8xcR28VArjzn1x7U
2026-10-29 08:58:50 +00:00
taehongandClaude Opus 5.5 6fc64bf512 Audio: keyframed Audio Levels and Stereo Mixer levels ramp within a mix block
The mixdown evaluated levels and effect parameters once per block, and export mixes WAV/AIFF
in one-second blocks, so a level fade became a staircase that changed once a second. Animated
Audio Levels are now evaluated on a 1 ms grid of comp samples and interpolated in dB between,
and animated per-sample effects (Stereo Mixer, Backwards) run in 1 ms pieces with their
parameters at each piece. The grid is aligned to comp sample indices, so the result still does
not depend on the block size.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-29 17:57:44 +09:00
mypenc b0befe1fd1 Viewer: Alt/Option-drop of a Project item replaces the layer under the pointer (#2173) 2026-10-29 08:43:09 +00:00
Claude 3cac49374d G1: use as_chunks in the premultiplied dither test (clippy) (#2022) 2026-10-29 03:38:24 -05:00
Claude 9bfbce5117 G1: keep dithered premultiplied colour at or below alpha (#2022)
Dither can round a colour byte up while alpha rounds down (colour = alpha = 100.25/255 gives
alpha 100, colour 101), breaking the premultiplied invariant. Clamp each dithered colour byte
to the written alpha byte.

Test: dithered_premultiplied_colour_never_exceeds_alpha.
2026-10-29 03:06:31 -05:00
Claude 85e061fe0c Merge main into fix/2022-render-banding (#1631)
Resolve the export tests' module list (banding and h264_gpu_yuv both stay). #1631's
yuv420_frame checked Render Settings Color Depth itself; that depth is now the project's
depth for the whole render, so the GPU YUV path is taken only for 8 bpc renders. Above
8 bpc frames take the RGBA path, which dithers, so H.264 exports don't band either.
Test: renders_above_8_bpc_skip_the_planes.
2026-10-29 03:06:31 -05:00
Claude 16fe448df9 G3: clamp ROI edges inside the frame (#1577)
Per review: as in After Effects, the region of interest lies inside the comp, so each converted
ROI edge is clamped to [0, w] / [0, h] and the far edge never passes the near one. A hostile ROI
reaching far outside the frame can no longer pad it into a huge crop, the wide-frame case keeps
its full width, and the i64 widening is no longer needed (frame_size is back to main's code).

Tests: hostile quads give edges >= 0 and a frame between 1 x 1 and the frame size, and an ROI
covering more than the frame is the whole frame.
2026-10-29 03:04:57 -05:00
Madhav Agarwal bad35b0092 tests: compare font styles case-insensitively and use instance attributes 2026-10-29 13:28:31 +05:30
Madhav Agarwal 0c6ca242e5 engine: keep a one-frame run a sequence when replacing footage 2026-10-29 13:26:48 +05:30
midasdf cbd67baf36 Text: the zh-hans Han order test replaces the skipping render test (#2039)
The CJK render test skipped wherever no Japanese face was installed, which
is every CI runner, and on a Mac it drew glyphs with or without the fix, so
it caught nothing. Replace it with a fallback-order test: fixture faces for
`Hiragino Sans` and `Hiragino Sans GB` show that a zh-hans Han lookup tries
the Chinese family first, that ja tries the Japanese one, and that a layout
gets Hiragino Sans GB. Synthetic fonts in an isolated child process keep it
independent of the host's fonts; with the Simplified list reverted it fails
on `[7]` against `[8, 7]`.

Delete `TEST_CJK_LOCALE`: the locale-mutating tests moved to an isolated
child process, so nothing used the lock and the test-only static failed
clippy's `-D warnings` gate.

Trim the documentation edits to the single docs/gaps.md gap-11 row: revert
the header and changelog edits in ROADMAP.md, docs/roadmap.md,
docs/localization-parity.md and docs/target-app-parity.md, and the gaps.md
header and changelog row, which conflict with other PRs.

Tests: cargo clippy -p effectcraft-text -p effectcraft-render --all-targets
-- -D warnings, cargo clippy --workspace --all-targets -- -D warnings,
cargo test -p effectcraft-text (79 lib), cargo test -p effectcraft-render
(264 passed, 1 ignored perf test), cargo fmt --all -- --check.
2026-10-29 14:47:22 +09:00
midasdf 667ebf229a Merge remote-tracking branch 'origin/main' into jp/cjk-composition-rendering 2026-10-29 14:41:28 +09:00
Madhav Agarwal 9fd14225eb engine: treat null sequence options as unspecified in Replace Footage 2026-10-29 10:20:20 +05:30
Madhav Agarwal a29eda3844 engine: Replace Footage keeps a still a still (#2073) 2026-10-29 10:20:20 +05:30
Madhav Agarwal 90acacd917 tests: match retained font faces and primary-style precedence 2026-10-29 10:20:06 +05:30
Madhav Agarwal cd8d55b40e tests: count variable font named instances as styles (#2072) 2026-10-29 10:19:58 +05:30
SusieeTheFemboyandClaude Opus 5.5 5224414d28 Transform: Fit to Comp refuses a scale that overflows (#2198)
A shape's painted bounds can be tiny enough (a 1e-305 px rectangle) that
the fit scale overflows to infinity. Non-finite bounds are skipped and a
non-finite scale returns an error before anything is written, instead of
storing infinity in the document.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-29 05:41:00 +01:00
SusieeTheFemboyandGLM-5.3-Flash a3a72d48aa Transform: Fit to Comp sizes shape and text layers by their painted bounds (#2198)
layer.transform's fit / fitWidth / fitHeight ops took the layer's size
from render::source_size, which returns (0, 0) for layers without a
source item — shapes and text — so the ops matched nothing and silently
did nothing, for the shortcut, the menu item and the command alike.

When the source size is empty and a fit op runs, the size falls back to
the layer's painted content bounds at the current time, and the anchor
goes to the bounds' centre: content bounds live in layer space, where a
shape is centred on the origin and text sits above its baseline, so
(w/2, h/2) would fill the frame but land off-centre. Reset and the
other ops keep the source size, so their defaults are unchanged.

The regression test asserts what the viewer shows — the painted bounds
mapped to comp space span [0, 0, 640, 360] after fit, and fitWidth
spans the width centred vertically — for a rect shape and a text layer.

Co-Authored-By: GLM-5.3-Flash <noreply@z.ai>
2026-10-29 05:22:57 +01:00
SusieeTheFemboyandGLM-5.3-Flash 63f1698cff Edit: an open text edit stands down the Project-panel Clear redirect (#2227)
Edit > Clear follows panel focus: with the Project panel focused it
redirects to project.delete, which removes the selection at once when
nothing uses it. With a text edit open, that deletes the composition
being typed into — the user is working in it — and undo restores the
item but not the active composition. During a text edit the redirect
stands down (Clear does nothing) and the Edit menu's Clear entry is
disabled, mirroring how Deselect All stands down in #2096.

Co-Authored-By: GLM-5.3-Flash <noreply@z.ai>
2026-10-29 05:22:56 +01:00
SusieeTheFemboyandGLM-5.3-Flash 60a356ea14 Edit: duplicating during a text edit ends the edit (#2226)
Edit > Duplicate replaces the layer selection with the copies, but an
open in-canvas text edit stayed on the original layer: typing kept
editing a layer that was no longer selected. When the duplicate leaves
the edited layer deselected, end the edit the way #2096's Deselect All
does (text_edit::end_edit), in the command every caller — menu, shortcut,
MCP — dispatches through.

Co-Authored-By: GLM-5.3-Flash <noreply@z.ai>
2026-10-29 05:22:56 +01:00
bflatasticandClaude Opus 5.5 5013012dab av1enc: decide.rs imports half_planes after the strict-clippy import list (#2496)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-29 10:34:57 +07:00
bflatastic 372c707e8c Merge remote-tracking branch 'origin/main' into HEAD 2026-10-29 10:34:55 +07:00