Commit Graph
3365 Commits
Author SHA1 Message Date
onlykshitijandClaude Opus 5.5 bdcd2dc051 Scripts: subfolders of the Scripts and ScriptUI Panels folders become submenus
An extension that ships several panels no longer adds one Window menu entry per panel:
`Scripts/ScriptUI Panels/Motion Kit/Animate.jsx` shows as Window > Motion Kit > Animate.jsx,
and a subfolder of `Scripts/` is a submenu of File > Scripts. Top-level scripts are unchanged.

- Script names may be `Folder/File.jsx`: exactly one folder, each part a bare name (no `..`,
  `\`, NUL or empty part), never `ScriptUI Panels/...` under `Scripts/`.
- window.scriptPanel, file.runScript, file.uninstallScript, file.scripts.list and
  scriptui_panels.json take such names; a panel's tab is titled after its file.
- ConfigStore::list_dirs (DirConfig, MemoryConfig) lists the subfolders.
- menus::dynamic_nodes groups a folder's entries into a MenuNode::Submenu; the egui and native
  menus draw it with their submenu code.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-24 18:05:59 +05:30
dotCooCoo decc8b72f9 Advanced 3D: shadow jitter blends across its lattice cell, so GPU penumbrae match the CPU
The PCF tap jitter was keyed on the receiver's 1/8-texel cell in the
shadow map. The GPU computes the receiver's map position with last-bit
differences from the CPU, so a receiver next to a cell line could take
another cell's jitter on one backend, and every tap moved. In a wide
penumbra that changed the coverage by several 8-bit levels:
gpu_matches_cpu_wide_penumbrae failed on Windows with 15 of 4159
shadowed pixels on an NVIDIA RTX 5080 and 22 on an AMD Radeon iGPU,
against a budget of 8.

tap_jitter now blends the hashes at the four corners of the cell by
the receiver's position in it, in shade.rs and in advanced3d.wgsl. At
the lattice points the jitter is the per-cell hash it was before. A
CPU test checks that the coverage does not jump at a lattice line.
2026-10-24 04:25:03 -07:00
onlykshitijandClaude Opus 5.5 9514c127cb ScriptUI: test that paint_draw paints fill, stroke and text colours as sRGB
The first test only called draw_color. This one runs paint_draw on an egui
context and checks the colour of each painted shape, so a branch that skips
draw_color fails the test.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-24 15:33:34 +05:30
dotCooCoo eff747897d Fix #341: the close decision runs in App::logic
eframe runs App::logic without App::ui while the window is minimized or
hidden, and handles a close request then too. The unsaved-changes check, the
device-loss close and craft_quit::on_close_request ran from ui, so such a
close skipped the prompt and the macOS quit through terminate:. They now run
at the end of logic, with the platform hook last, as craft-quit asks.
2026-10-24 02:50:22 -07:00
Dylan M. TaylorandClaude Sonnet 5.5 c07604563e sonar: leave the duplicated cache blocks in object_matte and roto alone (new-code duplication gate)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-24 08:45:39 +00:00
Dylan M. TaylorandClaude Sonnet 5.5 4e9fa51f12 sonar: method paths instead of closures (rust:S1612)
Poison recovery, OsStr::to_str and char predicates only; S4325 casts are
f64 to f32 and stay.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-24 08:17:16 +00:00
onlykshitijandClaude Opus 5.5 47f55abb87 ScriptUI: fix script-drawn colours showing too bright
paint_draw passed a script's 0 to 1 colour values to egui::Rgba, which
stores linear light. egui then applied the sRGB curve, so every
fillPath, strokePath and drawString colour drew too bright. For example,
#2B2B2B drew as RGB 114 and #F28C28 as 249, 196, 110.

After Effects treats these values as plain screen colours. Convert them
with the existing to_color32 helper instead.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-24 13:09:51 +05:30
dotCooCoo aa296cf273 Merge branch 'main' into fix/macos-quit-crash 2026-10-23 23:01:09 -07:00
Jason LukerandClaude Fable 5.1 cb46d69e44 Window: start the wgpu surface from eframe's default, one frame in flight instead of two
`wgpu_options` built the window's configuration from `WgpuConfiguration::default()`, whose surface is
`SurfaceConfig::HIGH_THROUGHPUT` (two frames in flight); eframe's own `NativeOptions::default()` wraps
it with `LOW_LATENCY` (one), and replacing `wgpu_options` wholesale silently lost that. On Metal,
wgpu-hal sets `maximumDrawableCount = latency + 1`: three drawables instead of two, one more frame
between the pointer and the screen on every drag, scrub and slider (8 ms at 120 Hz, 17 ms at 60 Hz).

Start from `.with_surface_config(eframe::SurfaceConfig::LOW_LATENCY)`; everything else in
`wgpu_options` is unchanged.

Measured on an M2 Max (release, `footprint -p`): IOSurface 61 MB → 41 MB (three 21 MB drawables →
two). Interface frame rate during 10 s of playback of a 1080p comp whose frames cost 164–279 ms on
the GPU stays at 120 fps either way (median 120.1 vs 120.0, p10 116–119.5 vs 117–119.4), so one
frame in flight does not starve this comp at 120 Hz.

Test: `the_window_surface_is_low_latency` asserts `LOW_LATENCY`, `desired_maximum_frame_latency ==
Some(1)` and `AutoVsync` for every backend choice, and equality with eframe's default surface.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-23 21:50:06 -07:00
Christopher Linnett 34242e8c1b fix: move Buf offsets by the pad Image::padded actually applies (#2092 review follow-up)
Image::padded clamps the pad so each side stays within MAX_PADDED_SIDE, but
Buf::pad still added the requested pad to its offset, so a clamped pad left
the pixels and the offset disagreeing (a hostile pad of u32::MAX shifted the
pixels by 5 and the offset by ~4.3e9). The clamp now lives in one place,
Image::effective_pad, used by both padded() and Buf::pad.

The padded() doc now states what the clamp guarantees (output within the
largest image the engine supports) and that memory budgets belong to callers
that pad by a derived amount (DOF_PAD_BUDGET, GPU fits()).

Adds an effects regression test: Buf::pad(u32::MAX) moves the offset by the
clamped pad and the source pixel stays at its layer position (fail-before:
offset off by u32::MAX). cargo test -p effectcraft-effects 457/457,
-p effectcraft-raster 35/35, -p effectcraft-render 238/238; clippy -D
warnings and fmt clean on touched crates.
2026-10-24 11:49:53 +08:00
aiongg eb5108786b PDF: repin craft-pdf, hayro-syntax and hayro-jbig2 to craft-libs 9f75d3dc for its xref, object-stream, graphics-state and JBIG2 input bounds (#2265) 2026-10-23 23:27:29 -04:00
Christopher Linnett d3d23c2f74 fix: bound Image::padded() at the API so no caller can reintroduce the oversized-pad OOM (#2092 review follow-up)
Triage found the pad bound lived only in the DoF callers: Image::padded was
pub with a doc comment asking callers to bound pad, so a future caller could
reintroduce the exact oversized-buffer OOM this PR fixes. The cap now lives
inside padded(): pad is clamped so each output side stays <= MAX_PADDED_SIDE
(30 000, mirroring project limits::MAX_SIZE; raster cannot depend on the
project crate per layering), overflow unreachable by construction, no panic in
any profile. The caller-side padded_size guards stay for reject-on-error UX.

Adds raster regression tests: hostile pad (u32::MAX) clamps to cap with source
intact at the clamped offset (fail-before: pre-fix sized an oversized buffer);
legit pads byte-identical (anti-over-clamp). cargo test -p effectcraft-raster
35/35, -p effectcraft-render 238/238, clippy -D warnings clean, fmt clean.
2026-10-24 11:26:30 +08:00
aiongg 1400cf7c78 Merge pull request #2264 from aiongg/contrib-batch-4
Integration batch 4: 15 contributor PRs (interface, scripting, hardening, docs)
2026-10-23 22:57:03 -04:00
aiongg e3e9776c25 Batch fix: settings: size the page column from the titles it draws (#2171) 2026-10-24 02:12:59 +00:00
aiongg 07eda94115 Merge #2033: docs: escape the backtick in the twirlSelected shortcut (#2025) (@gmrmad1) 2026-10-24 02:12:25 +00:00
aiongg 2281e3ffec Merge #1761: Timeline: a shape group's inner Contents draws no row, as After Effects elides it (@elZanco)
# Conflicts:
#	docs/ui-parity.md
2026-10-24 02:12:25 +00:00
aiongg 9a9574baaa Merge #2016: Settings: list the languages alphabetically by their own name (@nikolainyegaard) 2026-10-24 02:12:11 +00:00
aiongg cf54196ad9 Merge #2171: Settings: fit translated page names in the sidebar (#2034) (@Maokus) 2026-10-24 02:11:49 +00:00
aiongg 39526acc86 Merge #1327: Timeline: focus newly added expressions after Alt-click (refs #1072) (@tylerjenningsw) 2026-10-24 02:10:16 +00:00
aiongg 0db7ddb089 Merge #2228: End an open text edit when Deselect All runs (#2096) (@ChristopherLinnett) 2026-10-24 02:10:16 +00:00
aiongg 1d61fc6979 Merge #1933: Viewer: keep hidden AV layers' controls visible (#1769) (@ki2pixel)
# Conflicts:
#	docs/ui-parity.md
2026-10-24 02:10:16 +00:00
aiongg 2b8bb3150e Merge #2156: Return None from Mat4::inverse for non-finite input (@Silvertree2010) 2026-10-24 02:10:03 +00:00
aiongg 9384ab7a47 Merge #1945: Reject non-hex characters such as '+' in Rgba::from_hex (@Silvertree2010)
# Conflicts:
#	crates/color/src/lib.rs
2026-10-24 02:10:03 +00:00
aiongg 0494226fc8 Merge #1997: Keep rgb_to_hsv and rgb_to_hsl hue within 0..1 (@Silvertree2010) 2026-10-24 02:09:49 +00:00
aiongg 1ea2c0416f Merge #1881: Reject non-finite numbers in CSS colour parsing (@Silvertree2010) 2026-10-24 02:09:49 +00:00
aiongg c00170bcc6 Merge #1867: Fix scheduled ScriptUI tasks in host sessions (@dorfee) 2026-10-24 02:09:49 +00:00
aiongg 63f4bacf83 Merge #1891: fix(script): interrupt blocked socket writes on close (@TimotheusG) 2026-10-24 02:09:49 +00:00
aiongg aa65e498ce Merge #1948: CLI: preserve template composition names when rendering (@tylerjenningsw) 2026-10-24 02:09:49 +00:00
aiongg 113b92ac8c Merge #2110: ui: scrub hot text from the slider range (#2097) (@gmrmad1) 2026-10-24 02:09:49 +00:00
aiongg b898ba7f03 Merge pull request #2260 from aiongg/contrib-batch-3
Integration batch 3: 19 contributor PRs (interface, engine, effects, GPU, PDF and EPS import)
2026-10-23 22:08:01 -04:00
aiongg 2cca29830e Batch fix: EPS: load returns an operator value, so an executable-name alias runs what its name is bound to (#1909) 2026-10-24 01:43:40 +00:00
aiongg a407281852 Batch fix: tests: the web-job GPU page blurs by 12, which the GPU still runs after #1968 (#1968) 2026-10-24 01:39:09 +00:00
aiongg 80a08e3a3f Batch fix: pdf: the u32 overflow tests reach their fonts from the page, as the object loader needs (#2163) 2026-10-24 01:29:13 +00:00
aiongg c028b49f99 Batch fix: EPS: executable names count against the PostScript call depth 2026-10-24 01:23:26 +00:00
aiongg 69d6e3d28a Batch fix: EPS: filter keeps its source, so an image's data source isn't skipped twice (#1909) 2026-10-24 01:22:55 +00:00
aiongg fec95ff7ea Merge #1909: EPS: Illustrator EPS files draw their artwork (#955) (@JWesCampbell) 2026-10-24 01:21:39 +00:00
aiongg f50019244a Merge #2163: Fix u32 overflows in PDF CID width tables and CMap ranges (#2147) (@MarekSpodBiedry) 2026-10-24 01:21:39 +00:00
aiongg a6d8d23dfc Merge #2045: GPU: devices favour memory use, so Purge and Close give video memory back (@arnav-hiwarkar) 2026-10-24 01:21:39 +00:00
aiongg 981d3116d1 Merge #2040: Fractal Noise: resolve the Blending Mode once per layer, not per pixel (@arnav-hiwarkar) 2026-10-24 01:21:39 +00:00
aiongg a622e6bc5d Merge #1604: Cryptomatte: skip the ID colours unless Colors shows them, key the layer in place, and cache each rank's last ID colour (@MatejKozlovsky) 2026-10-24 01:21:39 +00:00
aiongg 3cf11de7c2 Merge #1810: Shift Channels: After Effects' Take … From menu order, so 10 is Full Off (#1797) (@Anubhav-Rai) 2026-10-24 01:21:11 +00:00
aiongg 3385eafe1f Batch fix: blur: a NaN or vanishing sigma skips the Gaussian pass (#1968) 2026-10-24 01:21:11 +00:00
aiongg 65a199bbd7 Merge #1968: Make Gaussian Blur and Fast Box Blur continuous at small values (#1939) (@MarekSpodBiedry) 2026-10-24 01:20:43 +00:00
aiongg 6d0dc7ac57 Merge #2206: effects: CC Radial Fast Blur grows its buffer so streaks pass the layer edge (#2095) (@mercuryVM) 2026-10-24 01:20:43 +00:00
aiongg 017d08bbd0 Merge #2027: Fix #1708: calibrate CC Blobbylize from the AE oracle (@ki2pixel) 2026-10-24 01:20:20 +00:00
aiongg 546a9720b0 Batch fix: cargo fmt 2026-10-24 01:16:38 +00:00
aiongg 3b3b1846e5 Batch fix: i18n: drop the Georgian "Layer {}" row the Timeline no longer asks for (#2155) 2026-10-24 01:16:29 +00:00
aiongg d88a604e8d Merge #2041: Save: check the file's values without reparsing it in release builds (@arnav-hiwarkar) 2026-10-24 01:12:11 +00:00
aiongg a9d5ea90a8 Merge #1958: script: comp.width and comp.height resize the frame without moving the layers (#1942) (@Anubhav-Rai) 2026-10-24 01:12:08 +00:00
aiongg ad2f3a5e96 Merge #2184: Reload a numbered still as its own file (#2074) (@HEOJUNFO) 2026-10-24 01:12:00 +00:00