Commit Graph
3546 Commits
Author SHA1 Message Date
BFlat 429e44c8be Merge pull request #2542 from Silvertree2010/fix/h3276-lottie-text-stroke-colour-parser
Reject '+' signs in Lottie text stroke colour hex pairs
2026-10-30 00:07:18 +07:00
BFlat 9d0d1ee243 Merge pull request #2460 from Silvertree2010/fix/h2727-gltf-uri-decode-turns-x-into-a-c
Require hex digits in glTF uri_decode percent escapes
2026-10-30 00:07:05 +07:00
BFlat 41ae777480 Merge pull request #2288 from Silvertree2010/fix/2128-audit-f-08-svg-arc-with-a-huge-r
Bound SVG arc segment count for huge radii
2026-10-30 00:06:50 +07:00
BFlat b6cff1f522 Merge pull request #2287 from Silvertree2010/fix/h2000-framerate-from-f64-returns-a-zer
Keep FrameRate::from_f64 nonzero for tiny positive fps
2026-10-30 00:06:35 +07:00
BFlat 966fdd3c0a Merge pull request #1776 from sanyamsingh001/fix/hextile-centerline-symmetry
Fix HexTile centerline cell selection
2026-10-30 00:06:21 +07:00
BFlat 5ed0a3f9b1 Merge pull request #1669 from zitann2020/i18n/ja-comp-settings
i18n: two labels that already had a catalog row were formatted in English
2026-10-30 00:06:09 +07:00
BFlat 77b4d76455 Merge pull request #2338 from vangel76/camtrack-triangulate-stack
Camera tracking: avoid per-view triangulation allocations
2026-10-30 00:05:56 +07:00
BFlat 2546f3934e Merge pull request #2597 from storytold/fix/2129-xml-entity-expansion
SVG, FCP XML: bound XML entity expansion (#2129)
2026-10-30 00:02:06 +07:00
bflatasticandClaude Opus 5.5 c70fccff99 SVG, FCP XML: bound XML entity expansion (#2129)
A few kilobytes of internal entities expanded to millions of nodes (each top-level
reference stays under roxmltree's per-reference cap), so a 1 MB file exhausted memory.
SVG keeps DTDs, which Illustrator's exports use for entities, but caps the expanded
document at 4 million nodes. Final Cut Pro XML and FCPXML, which FilmCraft parses
without a node limit, are refused when they declare an entity; real exports never do.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-30 00:01:33 +07:00
Kushagra Kumar c31fad1b90 fix(engine): respect frame default template and force RGB only on transparent: false 2026-10-29 22:06:27 +05:30
zitann2020andDeepSeek V4.1 Flash 373112b38b i18n(ja): Paint and Generate must not draw the same category name
The Generate row added here drew 描画, which Paint already used, so the Effect menu showed the same
category name twice. 描画 is Adobe's name for Generate, so Paint becomes ペイント, and a test now
rejects two categories sharing a Japanese name.

Found by the review bot on this PR.

Co-Authored-By: DeepSeek V4.1 Flash <noreply@deepseek.com>
2026-10-30 01:30:04 +09:00
bflatasticandClaude Opus 5.5 8b43197065 Scripts: Startup and Shutdown folders aren't File > Scripts submenus, as in After Effects
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-29 23:24:20 +07:00
bflatastic 4aead36ecd Merge remote-tracking branch 'origin/main' into HEAD 2026-10-29 23:21:59 +07:00
bflatasticandClaude Opus 5.5 3d45065add Project: reads_markers stops at the first expression and allocates nothing
It runs for every frame identity and disk-cache key; walk() formatted a path per node.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-29 23:21:33 +07:00
bflatastic 1fde74b5f2 Merge remote-tracking branch 'origin/main' into HEAD 2026-10-29 23:19:56 +07:00
bflatasticandClaude Opus 5.5 3301c86f7f Export: the H.264 GPU-YUV frame loop takes the CPU cap too (Cx::inflight)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-29 23:19:41 +07:00
bflatastic f3f9be4be3 Merge remote-tracking branch 'origin/main' into HEAD 2026-10-29 23:18:39 +07:00
bflatasticandClaude Opus 5.5 92f60c1372 Model: rustfmt the OBJ/MTL sibling-lookup tests
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-29 23:17:37 +07:00
bflatastic a1d8cb675f Merge remote-tracking branch 'origin/main' into HEAD 2026-10-29 23:17:33 +07:00
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
G.J.R. Timmer 80d01f09d5 fix(web): a demo startup keeps the session snapshot once the user opens or edits a project 2026-10-29 10:57:00 -04: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
dotCooCoo 2bef8aa669 Cineon: the Cineon Converter keeps its Gamma scale
cineon_log_to_lin takes the exponent scale from its caller. Interpret
Footage > Cineon Settings passes 1 (Gamma 1 gives linear light) and the
Cineon Converter passes 1.7, as before, so the converter's output and
its default Gamma 1.7 are unchanged. The converter's Linear to Log, Log
to Log reference and GPU shader return to their earlier code.

A test checks the converter at its default Gamma and at 2.4, for all
three conversion types, against the earlier formula.
2026-10-29 06:46:51 -07:00
G.J.R. Timmer df9207d1be feat(web): keep the saved session on a demo start, bound the config request
An explicit demo startup no longer saves the session, so the demo cannot replace the last visit's project. The config request is aborted after 5 s, stops reading once the body passes the size limit, and is skipped for ?empty and ?demo. The packaged hosting notes link to the published docs.
2026-10-29 09:25:48 -04: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 89f33415bb #1436: take a preview back without taking other edits with it; sync the draft before OK keeps a preview
Cancel and Preview-off merge the checkpoint, the preview's result and the project now (new
preview_merge module), so an edit made while the dialog was open stays. OK first brings the
preview up to the draft it finds, and Composition Settings OK applies the Resolution after a kept
preview. The Gradient Editor's OK syncs and sets the draft when it differs from the last preview.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RDvxCS8xcR28VArjzn1x7U
2026-10-29 12:05:43 +00: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 383ff2d487 i18n: the panel tabs, and the labels the call-shape scan cannot see
Two English surfaces the translation work so far could not reach.

The dock's tab titles: `PanelKind::title()` is drawn by `dock_ui.rs`'s `tab_titles`, which listed only
the tabs that name a comp, a layer or a script and let every other one fall back to `title()`'s English
- so every panel tab (`Timeline`, `Preview`, `Properties`, `Effects & Presets`, ...) stayed English. The
Window menu already carries a (`window.panel`, title) row in every catalog, so the dock reads that pair
and falls back to the panel catalog for `Markers` (the one panel only it names); `History` and
`ScriptUI Panel` have no row anywhere and keep their English names. `app.auto`'s labels and the dock's
serialized state keep the English title, which the control channel needs.

The scan's blind shapes: `converted_panels_have_no_unwrapped_literals` only sees a literal that follows
a call token, so a label passed to a helper, the third argument of `Painter::text`, a `(key, label, ...)`
table, a `let` binding and a `match` arm were all invisible. The two that can be checked without
guessing are added (`helper_and_painter_labels_are_translated`), with the same single-character
exemption the call scan makes, and the 25 sites they find now ask the catalog (`Apply`, `Analyze`,
`Cancel`, `Create Camera`, `Add Point`, `Remove Point`, `Clear`, `Render`, `Stop`, `Save Current as
Template...`, `New Composition From Footage`, the three search fields, `(no composition)`,
`per second`, `Waveform`, `steps`), with 15 rows added to the Simplified and Traditional catalogs in
the conventions those tables already use (Render 算圖, Apply 套用, Add Point 添加點).

The `uic!` labels and the Keyboard Shortcuts dialog are a different shape and are still to decide
(#1451).

Verified on Linux: cargo fmt --all --check, cargo test -p effectcraft-ui-egui (every suite passes),
cargo clippy -p effectcraft-ui-egui --all-targets -- -D warnings clean. Reverting the dock's catalog
lookup fails `the_dock_draws_every_panel_it_can_in_the_interface_language`; unwrapping a helper or a
painter label fails `helper_and_painter_labels_are_translated` ("panels/project.rs:434: the interface
text \"Search project\" that widgets::search_field draws is not in the catalog").

Also answers #1451's question about languages whose rows have no Simplified row to be a subset
of: six labels the Composition Settings dialog draws from a `(label, value)` table, a tab array and
a `match` arm (`Square Pixels`, `Basic`, `Advanced`, `3D Renderer`, `Black`, `Composition Settings`,
plus `White` from the same `color_name`) had no row anywhere, so every interface drew them in
English; they have Simplified and Traditional rows now, in the existing menu wording. The seventh,
`Lock Aspect Ratio`, is only an automation name - the drawn label is `Lock Aspect Ratio to {}`,
which already had rows, and `comp_settings.rs` built it with `format!` where `dialogs.rs` already
used `tr_args`, so that one is wired now too.

Review fixes (CodeRabbit): the scan now runs over the whole file with line comments blanked, so a
`.text(` call split across lines is still one argument list - which found five more labels the
per-line loop could not see (`No effects. Drag one from Effects & Presets.`, the colour-ring hint in
`fx_editors.rs`, the Learn blurb, the Script Console hint, the Templates blurb, plus
`Building waveform…` from the review), all wired with rows. And the New Composition title is back to
the English source: `modal_fit` keys the modal id and the drag offset on the title (its own comment
says the id stays on the untranslated source) and translates the heading itself, so `tr(..)` there
would have moved the dialog when the interface language changed.

And the argument list is bounded by the call's closing parenthesis: `args_of` used to flush a
trailing argument at end-of-string, so a last argument without a trailing comma carried the `)` and
the source after it, which made the check skip it as "not a literal". Reverting that one line is a
two-line test (a literal last argument in `header.rs` is caught now and was silent before).

The label scan also understands the two string forms a label can be written in: a plain string ends
at the first unescaped quote, a raw string (`r"…"`, `r#"…"#`) at a quote followed by as many `#` as
opened it, and `literal_text` decodes the argument before the exemptions run - so an escaped or raw
label is checked like any other instead of being skipped.

Two more scan fixes from review: `without_comments` tracks the escape state rather than the previous
character, so a string ending in a backslash (`"a\\"`) closes where it should; and the scanned range
ends at the test *module* - the first `#[cfg(test)]` followed by a `mod` - rather than at the first
`#[cfg(test)]`, because `dialogs.rs` keeps a test-only helper above its test module and production
code between them was not scanned.

And call tokens are looked for in a code-only mask: comments blanked, the contents of plain and raw
strings blanked too, with the quotes kept and every byte offset preserved (a blanked character
becomes as many spaces as its UTF-8 length, and a debug assertion pins the mask length). The argument
list is read from the original source at that offset, so a sample string that quotes a call cannot be
mistaken for one. Building the mask from chars instead of bytes shifted every offset after the first
non-ASCII character, which the debug assertion now catches.

The dock's display path has its own test now: `tab_titles` is called with `general.language` set to
Chinese and the labels a window shows are asserted (`Timeline` 时间轴 ...), plus `History` keeping its
English tab and the English interface keeping all of them. Reverting the dock to `PanelKind::title()`
fails it with "Timeline is not drawn in Chinese", which the catalog-only test could not see.
2026-10-29 19:35:09 +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
Zaxaerith 8851ee25a0 docs: scope headless MCP access in agent overview (#2564) 2026-10-29 19:16:02 +08:00
G.J.R. Timmer c334c36645 feat(web): startup option in effectcraft-config.json
A startup key (last, empty or demo) chooses the project the page opens on load. empty restores the last visit's project and otherwise starts blank, never with the demo; demo always opens the demo project; last, or no key, is the current behaviour. ?empty and ?demo still win. The config file is fetched once per page load and the service worker never caches it.
2026-10-29 07:11:48 -04: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
Claude 87a645c8bd Merge main into fix/browser-auto-language
main follows the browser's language preferences itself now (set_system_locales /
first_supported), so this branch keeps only what it adds: the Russian, French and German catalogs
selectable by Match System and a locale, and their Undo and Redo menu labels.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RDvxCS8xcR28VArjzn1x7U
2026-10-29 10:40:57 +00:00