Commit Graph
39 Commits
Author SHA1 Message Date
bflatastic d7ab6bc11b Merge main into #1387; clean 2026-10-30 05:46:52 +07:00
bflatastic 57b76bcc88 Merge remote-tracking branch 'origin/main' into HEAD 2026-10-30 05:08:13 +07:00
BFlat 5874304437 Merge pull request #1887 from ki2pixel/expressions-cubic-bezier
Expressions: cubic-Bezier easing helper (bezier(...)) (#1884)
2026-10-30 05:08:06 +07:00
tylerjenningsw 4b7ed9c77f Expressions: test that a frozen kept layer reads the project again 2026-10-29 17:53:50 -04:00
tylerjenningsw 2bd86c6cd8 Merge remote-tracking branch 'origin/main' into fix/paths-and-callable-layers
# Conflicts:
#	crates/expr/src/prelude.js
2026-10-29 17:42:29 -04: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
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 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
tylerjenningsw 95ee400ab2 Expressions: test that a change to Object.prototype doesn't reach the kept layers 2026-10-27 14:04:10 -04:00
tylerjenningsw e7cf022a7d Expressions: test that the kept layers are bounded 2026-10-27 14:04:10 -04:00
tylerjenningsw 2f2ebbdedb Expressions: test that deleting or redefining thisLayer and thisComp doesn't reach the next evaluation 2026-10-27 14:04:10 -04:00
tylerjenningsw d81716bfb6 Expressions: test that an expression can't change the prelude for the next one 2026-10-27 14:04:10 -04:00
tylerjenningsw 0860c7e03d Expressions: an expression can't delete a kept layer's fields 2026-10-27 14:04:10 -04:00
tylerjenningsw f4a4d76f2a Expressions: test that a kept layer's own fields don't carry over to the next evaluation 2026-10-27 14:04:10 -04:00
tylerjenningsw 754ed2fe84 Expressions: test that a kept layer reads the project again in each evaluation 2026-10-27 14:04:09 -04:00
tylerjenningsw 3f88c72a43 Expressions: a layer is a callable property group
In After Effects a layer is a property group: thisLayer("transform"),
thisComp.layer("Other")("effects")("Blur"), thisLayer(1). In
EffectCraft's expression runtime a Layer was a plain object, so those
failed with "TypeError: not a callable function", including the
references the pick whip writes with Compact English off
(thisComp.layer("Other")("effects")("ec.noise.fractal")(...)).

A Layer is now callable like a property group (built as __mkGroup
builds groups), looking up its own properties by match name, name or
index, and keeps its methods, name and index. The places that took a
layer for a plain object (the result reading as the layer's index,
thisComp.layer(layer, offset), a Layer Control's value handed through
the property proxy) accept it.

Test: layers_are_callable_property_groups (fails before).
2026-10-27 14:03:59 -04:00
Barzabel 6686cc75ca fix(expr): bound runtime parser and native recursion depth (#2124, #2125)
eval, Function and the generator/async function constructors now check the nesting of their source like the expression text. join, toLocaleString, flat and JSON.stringify check the run's stack use per level, results nested past the detached levels become [object], and Proxy/Reflect are no longer available to expressions. Each of these overflowed the stack and aborted the app.
2026-10-22 20:28:38 +03:00
NetterSilverandClaude Haiku 5.5 28f97be7ee Fix integer overflow in sampleImage for huge sample points
Found while testing crates/expr/src/sample.rs:102

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-21 02:39:20 +02:00
Gert Pellin 0bdf9ec5e3 Merge branch 'main' into expr-property-group-1619 2026-10-16 14:28:34 +02:00
bflatasticandClaude Opus 5.5 cc138fcb90 Expressions: timeToFrames keeps whole durations whole under float error
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-16 18:38:56 +07:00
Gert Pellin d347a0efca Expressions: propertyGroup() and a group's propertyIndex (#1619)
The After Effects stagger idiom
  id = thisProperty.propertyGroup(2).propertyIndex;
failed with "not a callable function": the expression object model had
no propertyGroup() and property groups had no propertyIndex.

- Property.propertyGroup(countUp = 1) and PropertyGroup.propertyGroup()
  return the group countUp levels up; from a top-level group they reach
  the layer. A count below 1, not a number, or above the layer is an
  error naming propertyGroup, never a crash.
- PropertyGroup.propertyIndex: the group's 1-based index among its
  siblings (Child requests now carry it).
- One new host request (Ancestor) walks up from the node's full uid
  path, so it also works for the property being evaluated.
- Tests for the stagger expression, effect parameters, reaching the
  layer, other layers' properties and groups and out-of-range counts;
  the fuzzer seeds and tokens include the new members.
2026-10-16 05:31:49 +02:00
sanyamsingh001andCodex 36ebe2eada Honor duration rounding in timeToFrames
Round nonzero duration frame counts away from zero while retaining
absolute-time rounding, default argument selection and numeric coercion.

Cover fractional durations, absolute controls, defaults and coercion.
Sort expected paths in the existing footage test for temporary-directory portability.

Co-authored-by: Codex <codex@openai.com>
2026-10-14 03:21:23 +10:00
Kristian MyramandClaude Haiku 5.5 4d105f02d4 #809: layer.source and a Layer Control's layer work in expressions
layer.source was undefined in expressions, and a layer from a Layer Control had no transform.
Both now work.

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
2026-10-12 19:19:11 +02:00
vangel76andClaude Sonnet 5.5 d7a03ef3a7 #786: make the expression budget tests independent of machine load
fanning_out_reads_stop_at_a_budget expects the run-count error, but under heavy load
the 5 s wall-clock budget could fire first (different error). Add a test-only
per-thread time limit and lift it in that test. Wall-clock assertions in the other
new tests are now only generous hang guards (>=10x), the fuzzer's hang deadline is
24x MAX_TIME and the perf bound is 10x looser.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-11 20:52:39 +02:00
vangel76andClaude Opus 5.5 9da66d9063 #786: fuzz expressions; fix the overflows, hangs and panic it found
Problem: expression text is input we don't control, and nothing fuzzed the
expression parser and evaluator. A seeded mutation fuzzer found stack
overflows (a few hundred `?:`/`=>`/`if`, a few thousand `.`/`<`/`()` links,
75 nested template substitutions or regex groups, a chain inside one
template), hangs (an expression reading its own layer's transform nested
2^16 times; fanning-out reads; 10M-iteration loops re-run per read; loops
calling looping functions), an i64 overflow panic in wiggle noise, and NaN
path vertices tripping the rasterizer's clipping assertion.

Fix: a dependency-free seeded fuzzer (crates/expr/src/tests/fuzz.rs: real
AE-style seeds, char/token mutations, worker thread with a 2 MiB stack,
catch_unwind, deadline, env vars for long runs); a weighted nesting
estimate covering chains without brackets and template/regex insides;
cycle detection per (property, time, text); a per-evaluation budget of
20 000 script runs and 5 s (runs are interrupted through boa's budgeted
evaluation; native only); loop limit 1M; wrapping noise lattice indices;
non-finite path results rejected. Each fix has a regression test.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 14:40:03 +02:00
Claude 9495810ff5 Tests: the near-plane check tests for the flip, and loopOut compares within float tolerance (#572, #456 follow-up)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QiAJeFttZp83Fh7YuzAR5f
2026-10-10 21:48:52 +00:00
Claude a12242c806 Format the merged community fixes (#561-#566 follow-up)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QiAJeFttZp83Fh7YuzAR5f
2026-10-10 12:49:52 +00:00
Nigel Ihza Firdausy 6ed3d210fb fix(expr): reflect pending TextStyle baseline edits in expression getters (#545) 2026-10-10 15:50:18 +07:00
BFlat 26f577cb1a Merge pull request #6 from storybored379/pr/expr-runtime-stack-leak
Expressions: keep the runtime usable after errors and property reads
2026-10-05 12:10:53 +07:00
bflatastic 244cee4687 M8.1: expressions keep working on long-lived threads — boa leaves values on its VM stack when an exception unwinds through call frames (every pending host request does), so after tens to hundreds of evaluations that read layers or effects every expression on the thread failed with "maximum stack size"; a run that hits the limit now gets a fresh context and is retried once (regression test: 6000 host-reading evaluations on one thread) 2026-10-04 00:19:22 +07:00
storybored379andClaude Opus 5.5 0ae7a1925a Expressions: keep the runtime usable after errors and property reads
boa leaves the value stack of inner call frames behind when an exception
leaves a script (or a function called from Rust) from a nested call. Every
property read throws the pending-host-request abort from inside a prelude
helper, and so does any helper error (`thisComp.layer("Ghost")`), so the
thread's runtime filled up after ~100 evaluations of a pick-whip
expression: from then on every expression on that thread failed with
"RuntimeLimitError: reached the maximum stack size" and silently fell back
to its keyframed value (e.g. a follower layer stops following after ~90
render_frame calls).

Wrap the script and `__finish` in try/catch and rethrow from their own
frame, which unwinds the stack; backtraces (error line numbers) survive.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-03 09:31:41 -07:00
Brandon ThomasandClaude Opus 5.5 0698b23cd7 M13.7: Save Frame As Photoshop Layers / ProEXR, Watch Folder, Vanishing Point (disabled), Create Nulls From Paths, VR Comp Editor, Help tutorials
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-03 07:55:04 -04:00
Brandon ThomasandClaude Opus 5.5 6d0d7de922 ANM-5: sampleImage, data footage (JSON/CSV/TSV) with footage().sourceData, thisProject, error list, Expression Language menu
sampleImage renders the sampled layer through the evaluating renderer's footage source
(EvalCtx::footage), cached per thread and frame. File > Import reads .json/.csv/.tsv as data
footage kept in the project. expr.errors collects failing expressions for the error bar;
expr.languageMenu lists the categorised Expression Language menu. Marker keys expose
protectedRegion and cue points; colorDepth, timeToFeetAndFrames, comp.activeCamera.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-02 22:58:04 -04:00
Brandon ThomasandClaude Opus 5.5 f78435927b M9.9: text style runs + paragraph settings
TextDoc gains character style runs (font, size, colours, tracking, leading,
baseline shift, h/v scale, tsume, faux styles, caps, super/subscript, kerning
metrics/optical/manual, ligatures) and per-paragraph settings (justification
with last-line modes, indents, space before/after, direction, composer,
hanging punctuation), serde-compatible with single-style documents. Layout
handles mixed runs on a line (shared baseline, largest leading), every-line
composer, editing geometry (carets, hit testing, selection quads) and basic
vertical type. Renderer colours per run. Expressions get the sourceText style
API (style, getStyleAt, createStyle, setters with character ranges).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-02 10:34:13 -04:00
Brandon ThomasandClaude Opus 5.5 fedb5cb715 M9.6: text animation UI (Animate:/Add: pop-ups, flattened animator rows, path popup, presets, menus)
Timeline: Text group 'Animate:' and animator 'Add:' pop-ups (properties and
Range/Wiggly/Expression selectors), selectors/properties listed directly under
each animator, Path Options ▸ Path lists the layer's masks and hides the
other path options until one is chosen. Properties panel Add Animator lists
every animator property plus Enable Per-character 3D, and a Presets menu.
Animation menu: Animate Text, Add Text Selector, Text Animation Presets.
Expression Selector result replaces the selection (no Mode); selector popups
are non-keyframable like AE.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-02 00:12:41 -04:00
Brandon ThomasandClaude Opus 5.5 c5cf189e1a M9.6: text animation depth (selectors, animator properties, per-char 3D, path text, presets)
Range selector complete (units, based on, modes, shapes, smoothness, ease
high/low, randomize), Wiggly and Expression selectors combined by mode;
all AE animator properties incl. line anchor, character offset/value,
skew axis, tracking type, fill/stroke HSB+opacity, blur; More Options
(anchor grouping, fill & stroke order, inter-character blending); Path
Options (text on a mask path); per-character 3D rendered as planes in
the 3D compositor; text animation commands and original presets.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-02 00:01:19 -04:00
Brandon ThomasandClaude Opus 5.5 4ce50e00a0 M8: expressions engine (boa) with AE object model
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 14:39:02 -04:00