Commit Graph
367 Commits
Author SHA1 Message Date
dotCooCoo 5f560d7075 Merge #1762: Fix #341: on macOS, a quit goes through terminate:
# Conflicts:
#	Cargo.toml
#	crates/ui-egui/src/app/frame.rs
2026-10-28 15:31:45 -07:00
arnav-hiwarkarandClaude Opus 5.5 8ab492d8cd Disk cache: apply the free-space reading where it's taken, evict off the UI thread at open (#2551)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-28 22:45:48 +05:30
arnav-hiwarkarandClaude Opus 5.5 52dda004a5 Disk cache: evict before writing, reset the disk reading when the folder changes (#2551)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-28 21:55:33 +05:30
arnav-hiwarkarandClaude Opus 5.5 8af5f54c92 Disk cache: give space back below the free-space reserve, skip writes that can't fit (#2551)
A disk reported as 0 bytes (an automount map) counts as unknown.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-28 18:34:02 +05:30
arnav-hiwarkarandClaude Opus 5.5 6efeae3793 Disk cache: 20 GB default, a free-space reserve and cheaper eviction (#2551)
- Default disk cache size 20 GB (was 100 GB); settings version 3 migrates the stored old
  default and keeps a size the user chose.
- The cache keeps max(2 GB, 5% of the disk) free: sysinfo::disk_space (df -Pk / PowerShell
  DriveInfo) is read in the background from memory_tick and caps the limit
  (DiskCache::set_disk_space); cache.diskStats reports limitBytes.
- Eviction goes down to 90% of the limit, so the LRU sort runs once per tenth of the limit
  written instead of on every write at the limit.
- Failed writes are counted (cache.diskStats failed) and the first is logged.

Also fixes #2063.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-28 18:27:31 +05:30
dotCooCoo 32f058ea05 Merge main into feat/wiggle-paths-spatial-phase 2026-10-28 05:39:33 -07:00
Matej Kozlovský 6e69b91a80 Export: H.264 frames convert to YUV 4:2:0 on the GPU
Accelerator::comp_frame_yuv420 (default None) renders a top-level comp frame and
converts it over the background to the H.264 export's 8-bit BT.709 limited-range
4:2:0, every byte within one level of the CPU conversion (the GPU kernel follows
it operation for operation, including NaN and half-away-from-zero ties, but a
driver may contract its arithmetic). A 4K frame then reads back 12 MB of planes
instead of 133 MB of RGBA f32.

The H.264 export asks the accelerator for planes when a frame needs nothing after
the render (progressive, project depth, no crop/resize, rendered at the output
size) and otherwise renders and converts on the CPU as before. Deferred
readbacks (a browser worker) keep the pass-based path. Sizes the kernel can't
take (width not a multiple of 8, odd height) are declined before any GPU work.

Like Cx::frames, h264_frames caps GPU frames in flight only while the
accelerator is up (map_frames_while with the same liveness check): once the GPU
stops for good, the remaining frames render on the CPU side by side instead of
one at a time.

rgba_to_yuv420 moves to effectcraft_raster::yuv so the export and the GPU tests
share one reference. The GPU tests skip without an adapter (tests::gpu()), as
the crate's others do.
2026-10-28 13:19:24 +01:00
Dylan M. Taylor 5d71dce7fc Refactor render for strict Clippy checks 2026-10-28 06:09:21 +00:00
tylerjenningsw 8d008e53da Merge branch 'fix/particle-birth-history' into fix/particle-birth-history-ps2-mercury
# Conflicts:
#	crates/effects/src/sim.rs
2026-10-27 16:59:26 -04:00
minhero 9cdce36f9f Merge branch 'storytold:main' into fix/environment-light-no-effect-cast-shadows 2026-10-27 21:23:56 +01:00
minhero 9d44da761d Merge branch 'storytold:main' into feat/2100-instance3d-layer-create 2026-10-27 21:23:13 +01:00
tylerjenningsw cedc727da9 Merge remote-tracking branch 'origin/main' into fix/particle-birth-history
# Conflicts:
#	crates/effects/src/sim.rs
#	crates/render/src/lib.rs
2026-10-27 14:57:00 -04:00
dotCooCoo e0dc5eb2ff Merge main and retain Cineon Settings in the extracted modules 2026-10-27 11:41:43 -07:00
dotCooCoo bb4f976384 Merge main and retain the Wiggle Transform command schema 2026-10-27 11:41:42 -07:00
tylerjenningsw 0f8a65f6c2 Disk cache: drop segmentations and frames made before strokes applied in order (#1646)
Segmentations and rendered frames are keyed by their strokes, which now
segment differently where strokes overlap; bumping both versions keeps old
entries from showing the old result. Frozen mattes are stored in the project
and are untouched.
2026-10-27 14:13:40 -04:00
tylerjenningsw 74b309e6cf Merge remote-tracking branch 'origin/main' into enhance/avi-import
# Conflicts:
#	crates/project/src/lib.rs
#	crates/render/src/lib.rs
#	crates/ui-egui/src/menus.rs
2026-10-27 14:13:31 -04:00
NetterSilverandClaude Opus 5.5 db41fa7980 Skip transparent pixels and quantise while compositing
Much of a layer buffer is often transparent (a stroked ring, a glow-padded
text layer, a precomp canvas), yet every destination pixel sampled it
bilinearly, and 8/16 bpc comps then re-quantised the layer's whole rotated
bounding box.

- Bilinear warps skip 16x16 source tiles whose pixels (and a one-pixel
  apron) all have zero alpha: their samples are transparent and were never
  drawn.
- The fast affine warp reports the rectangle it changed and, given the
  comp's levels, quantises each pixel as it blends it, so draw_comp has
  nothing left to re-quantise for that layer. quantize_px moves to
  effectcraft-raster for this.
- quantize_rect skips runs of four all-zero (+0.0) pixels, which quantise
  to themselves.
- to_rgba8 / to_rgba8_over convert row by row instead of per 4-byte item.

Every pixel stays bit-identical: tests compare the warp against the
reference path, fused quantising against quantising after blending, and
the zero-run skip against per-pixel quantising.

With the previous commit, demo comp to H.264 (`cargo xtask bench --scenario
demo --format h264 --frames 300`, 11 interleaved runs on a 16-thread Ryzen):
wall 9.26 s -> 6.97 s median (-24.8%), 8.55 s -> 6.55 s min (-23.3%); CPU
time -23%. Output byte-identical.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-27 17:40:41 +01:00
dotCooCoo 87eb51a089 Include alpha interpretation in frame-blend cache keys 2026-10-27 09:22:14 -07:00
Christopher Linnett 60da124f11 Merge remote-tracking branch 'origin/main' into fix/issue-2092-camera-focus-crash 2026-10-28 00:13:40 +08:00
vangel76andClaude Sonnet 5.5 9fc04e8fe3 Merge upstream/main into fix-1083-beat-marker-audio-pause
Conflicts came from upstream splitting crates/project/src/lib.rs and moving the
frames tests. Re-applied the branch's change in the new places:
- Layer::same_pixels_with now in crates/project/src/layer.rs
- Comp::same_pixels_with, same_settings(o, with_markers), pixel_form_with and the
  timing-marker helpers in crates/project/src/comp.rs (same_pixels_ignoring_markers
  stays removed)
- Project::reads_markers in crates/project/src/item.rs
- crates/ui-egui/src/frames.rs uses reads_markers/same_pixels_with; the branch's
  two marker tests replace the old ones in crates/ui-egui/src/frames/tests.rs

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-27 17:09:17 +01:00
vangel76andClaude Sonnet 5.5 2078b492d9 Merge upstream/main into rfx-text
text/layout: upstream split paragraph() into Para/place_line helpers and moved the tests to
layout/tests.rs. The branch's changes are re-applied there: the resolved paragraph direction
is passed to margins_for/avail_for/align_for (RTL point text with Justify sits flush right),
first_ascent/plausible_first and ParaLine.first/style_first (box first baseline is the d
height, vertical text keeps the ascent), and the Justify All last-line cost in
optimal_breaks. The branch's seven new layout tests moved to layout/tests.rs.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-27 17:06:38 +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
dotCooCoo c0f6151185 Preserve font name fallback in the shared dropdown menu 2026-10-27 08:31:12 -07:00
dotCooCoo 97ef73d592 Preserve bug fixes after main module moves and bound workspace migration 2026-10-27 07:45:09 -07:00
Z User a8cba23edc Review fixes: the environment shadow follows the tinted radiance (#2436)
dominant_direction weighted texels by their raw channel sum before the
light's colour tinted the radiance, so equally bright red and blue regions
on opposite sides cancelled to no sun and no key — while a red Environment
light's tint removed the blue contribution and left the scene lit
directionally red, with no shadow for its Cast Shadows to show. The tint
now weights the direction sum (a white light weights [1; 3], a coloured
one its normalised colour), so the sun and key are derived from the
radiance the light actually emits; add_environment computes the tint once,
before the direction pass, and reuses it for the texel tinting. An
achromatic image is unaffected (its weights scale uniformly), so the
default studio and white-lit scenes keep their shadows exactly.

Tests: opposed red and blue texels cancel to a white light but a red tint
points the sun straight at the red one (a blue tint, at the blue one); end
to end, a red Environment light over an image with equally bright red and
blue regions on exactly antipodal positions casts the shadow a white light
over the same image does not — and the shadow falls opposite the red
region, the side the tinted radiance comes from.
2026-10-27 14:11:55 +00:00
Z User eb34d10d21 Review fixes: a failed environment source lights nothing (#2436)
Two review points on the merge:

- env_pixels returned None both for an unconfigured light (no Source, no
  Environment Layer) and for a failed source (a deleted layer, missing
  footage, a failed decode), so a selected source that failed silently
  swapped in the default studio environment — relighting and reshadowing
  the scene behind the user's back. It now tells the three apart
  (EnvPixels::Absent/Image/Failed): only the unconfigured light uses the
  default; a failed source contributes nothing, exactly like a layer whose
  source fails renders nothing. The repair the user can act on stays where
  it already lives — missing footage is flagged on the item, with the
  relink commands to fix it.

- The docs claimed only a uniform image casts no shadow. A non-uniform one
  can be directionless too: opposing bright regions cancel, and anything
  under 1% directional is rejected. agents.md, architecture.md and the
  sun/dominant_direction doc comments now say an image without a
  sufficiently strong dominant direction.

Tests: an unreadable Environment Layer (auto-picked), an unreadable
selected Source and a deleted one all light nothing — pixel-equal to the
unlit render, no studio default, no default-environment shadow — while an
unconfigured light still lights; two equal bright spots at opposite
azimuths cancel to no sun and no key, and tilting the balance re-emerges
pointing at the brighter spot.
2026-10-27 12:33:46 +00:00
Minher0 db1f798455 Merge main into #2410
PR #2491 moved the modules; the instance3d changes follow the new layout:
- tests_instance3d.rs lives in src/tests/instance3d.rs now (declared in src/tests.rs)
- solo_3d moved from render/src/lib.rs to render/src/pipeline.rs, pub(crate),
  and its FxHost::layer caller moved to render/src/fx_host.rs
- cmd/create.rs, effects/channel2.rs, gpu/fx_pixel2.rs and render/cache/dependencies.rs
  followed their moves automatically (rename detection)
2026-10-27 09:15:43 +00:00
Z User 978ca419b9 Merge remote-tracking branch 'origin/main' into fix/environment-light-no-effect-cast-shadows 2026-10-27 08:54:33 +00:00
heojunfo 7a665a67b3 Merge remote-tracking branch 'upstream/main' into fix/classic3d-shadow-diffusion 2026-10-27 14:06:18 +09:00
Minher0 743119d6e5 Give the Environment light After Effects' look (#2436)
The default studio environment's level-preserving mean of 1 acted like a
100% white Ambient light: with only the Environment light on, a white floor
rendered at full white (95% of the frame saturated) while its shadow core
went to pitch black — a fog over the scene, nothing like After Effects'
default. Three changes bring the look in line, CPU and GPU alike:

- The default environment is a dim studio now: a solid-angle-weighted mean
  of 0.3 (and a stronger key gradient), so a white floor reads a mid gray
  and the light's colour x intensity still scales the level.
- The shadow occludes only the image's directional (key) fraction of the
  light — |sum of dir x radiance| / sum of radiance, computed beside the
  dominant direction and carried in the scene — so the fill keeps shining
  inside the shadow: an area-light shadow, partial like After Effects'
  (a lone bright spot on black still shadows almost fully; a uniform image
  not at all).
- The environment shadow map's penumbra has a floor — eight output pixels,
  or four map texels where those are coarser — because the map covers the
  whole scene bounding sphere rather than the view, and its texels would
  otherwise stair-step the edge (all the more in a draft render's flat 512
  budget). Shadow Diffusion widens it further, as before.

Tests: the key fraction tracks directionality; the default keeps its dim
level, its direction and its key; the default and a bright key both shadow
the floor (the default partial, the key deep) with Cast Shadows off lit
everywhere; and the full look — a mid-gray lit floor (no fog), a partial
core, and a soft edge ramp in quality and draft renders alike.
2026-10-26 23:36:19 +00:00
aiongg b7b75ed37a style: cargo fmt on the moved files 2026-10-26 21:54:30 +00:00
aiongg cbce15f069 refactor(render): move footage, effect host, accelerators, options, pipeline, layers and frames out of lib.rs 2026-10-26 21:49:11 +00:00
aiongg 9526833a62 refactor(render): move loose test files to src/tests/ 2026-10-26 21:49:11 +00:00
aiongg 226f76a5bf refactor(render): move src/three_d/mod.rs to src/three_d.rs 2026-10-26 21:49:10 +00:00
aiongg 0497fa6250 refactor(render): move src/three_d/adv/mod.rs to src/three_d/adv.rs 2026-10-26 21:49:10 +00:00
Minher0 aff46dabb6 Cast shadows from the Environment light's default environment (#2436)
After Effects' default environment map casts shadows out of the box: an
Environment light with Cast Shadows on shadows the scene with no Source
set. The flat default cancelled its dominant direction to zero, so the
option did nothing until a Source image arrived. Give the default a soft
studio gradient (bright above and toward the initial camera, dark below
and behind), level-normalised so the light's colour x intensity still
sets the overall brightness; its dominant region drives the existing
shadow pipeline, CPU and GPU alike.
2026-10-26 20:26:03 +00: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
Minher0 0539098887 Environment lights: review fixes — edit keeps Classic 3D, NaN sun guarded (#2436)
Three small fixes from the review of the shadow commit:

- light_settings switched a Classic 3D comp to Advanced 3D whenever the
  edited light was an Environment light (the resulting kind), so editing
  the intensity of one in a comp the user had switched back to Classic 3D
  dragged the renderer back. The switch now happens only on the
  non-Environment to Environment transition (the sources before and
  after), matching the docs; ordinary edits leave the renderer to the
  user.
- dominant_direction's thresholds let NaN through (every NaN comparison
  is false): a NaN or infinite texel produced a NaN sun direction and
  NaN shading with it. A non-finite weight or length now returns no
  direction — garbage casts no shadow.
- add_environment walked the full-resolution image for the dominant
  direction even when the light casts no shadows, where nothing reads
  it. Only a shadow-casting light pays for the pass now.

Tests: editing an existing Environment light in a Classic 3D comp keeps
the renderer and stays toast-silent; a NaN and an infinite environment
image yield no sun direction.
2026-10-26 13:40:53 +00:00
Minher0 863f0e49c1 Render the Environment light's shadow from its image (#2436)
The Casts Shadows option Environment lights got is only half a fix if
nothing shades for it: an image lights the scene from every direction,
and what occludes that light is the image itself — its dominant bright
region, the sun in a sky map.

- dominant_direction finds it: the radiance-weighted mean texel
  direction (solid-angle weighted, rotation applied). A uniform image
  cancels to zero — a flat default environment shines from everywhere
  at once and casts no shadow, which a uniform environment test pins.
- The shadow is one orthographic map over the scene from that
  direction, after the lights' maps, like a parallel light's: PCF
  widened by Shadow Diffusion, darkened by Shadow Darkness, cleared
  when nothing casts, the image is directionless, or the texel budget
  drops it.
- It darkens the environment's own diffuse and specular light on
  Accepts Shadows surfaces and counts in Cast Shadows Only. CPU and
  GPU (WGSL) do the same; Globals carries the environment's sun
  direction and shadow settings (40 → 44 floats, preflight updated).

A bright-disc environment turned to shine from behind the camera now
shadows a sphere onto the floor behind it, Cast Shadows off lights it
evenly again, and the GPU scene's sky gradient takes a shadow-casting
Environment light. Also: the renderer-switch toasts read "...renderer,
which draws 3D models", the dialog's Casts Shadows checkbox gets an
auto id (dialog.light.casts) the tests click, and the docs' Environment
notes cover the shadow.
2026-10-26 13:05:16 +00:00
Minher0 1599790ac9 Light Environment lights: default environment, Casts Shadows, Advanced 3D switch (#2436)
An Environment light had no visible effect, and its Light Settings dialog had
no Casts Shadows option — both halves of #2436.

No effect had two causes:

- Classic 3D (the default for new comps) skips Environment lights entirely,
  so creating one did nothing. Adding one (or changing a light's type to it)
  now switches the comp to Advanced 3D in the same undo step, with a toast,
  exactly as model and primitive layers already do; switching back to
  Classic 3D with an Environment light in the comp explains itself too.
- In Advanced 3D, a light with no Source and no Environment Layer produced no
  environment at all. It now falls back to a flat default environment of the
  light's colour × intensity, as After Effects does, so the light always
  lights the scene per its parameters.

Cast Shadows was missing because the dialog and the light's property groups
shared one gate (Falloff and Shadows together) that excluded Environment.
The two are now split: every light but Ambient gets Casts Shadows, Shadow
Darkness and Shadow Diffusion (stored, edited and carried over on type
changes), while Falloff stays on Parallel/Spot/Point only — an environment
light shines from every direction at once and has no use for a falloff.

Tests: the renderer lights a card from a sourceless Environment light (colour
and intensity drive it, zero intensity lights nothing), the engine switches
Classic comps to Advanced 3D on creation and type change (one undo step,
toast, and the Classic 3D switch-back toast), Environment lights take and
carry shadow options but no Falloff, and the dialog ticks Casts Shadows on
a new Environment light.
2026-10-26 09:43:47 +00:00
skylar taylor-barrick 69b9ce2bd1 M0.37: reconcile shared docking and qualify migration follow-up 2026-10-26 06:47:07 +01:00
heojunfoandClaude Opus 5.5 f589809b59 Classic 3D Shadow Diffusion blurs instead of stamping copies (#2444)
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-26 12:27:44 +09:00
dotCooCoo f23272f725 Merge #2352: Proxies: a composition proxy draws with Separate Fields, Invert Alpha, linear light and Frame Blending 2026-10-25 20:17:15 -07:00
dotCooCoo d6d7104382 Merge #2283: Advanced 3D: shadow jitter blends across its lattice cell, so GPU penumbrae match the CPU 2026-10-25 20:17:12 -07:00
dotCooCoo 8ebacda419 Shapes: Wiggle Paths has Spatial Phase, which slides its wiggle along the path
Wiggle Paths had Size, Detail, Points, Wiggles/Second, Correlation,
Temporal Phase and Random Seed, but no Spatial Phase, which After
Effects lists among its properties (ADBE Vector Spatial Phase). Spatial
Phase now moves each point's own displacement along its subpath: 360
degrees is once around, and a fraction of a point is interpolated
between neighbors. At 0 degrees a path draws as before.

A project saved without the property gets it at 0 degrees, after
Temporal Phase, when it opens. Scripts can read and set every Wiggle
Paths property by its match name.
2026-10-25 16:06:28 -07:00
skylar c16a628849 chore(deps): refresh safe dependency bumps
serde_json 1.0.154, proptest 1.12.0, objc2 0.6.5, winresource 0.1.34, pollster 1.0.1, miniz_oxide 0.9.1, linesweeper 0.5.0, lz4_flex 0.14.0, muda 0.21.2.
2026-10-25 16:36:21 -06:00
Dylan M. Taylor e821feeec4 Merge pull request #2274 from storytold/sonar/rust-s4325-s1612
sonar: method paths instead of closures (rust:S1612)
2026-10-25 16:36:06 -04:00
tylerjenningsw 5808550c5a Merge main into fix/particle-birth-history-ps2-mercury 2026-10-25 14:26:29 -04:00
tylerjenningsw 20d8501ea2 Merge main into fix/particle-birth-history 2026-10-25 14:26:29 -04:00
tylerjenningsw a2f3ac41b1 Merge main into enhance/avi-import 2026-10-25 14:26:28 -04:00