Commit Graph
15 Commits
Author SHA1 Message Date
bflatasticandClaude Opus 5.5 923d978119 Effects: CC Particle World follows the comp camera (#397)
Cause: CC Particle World projected its particles through a fixed camera
(distance 2 layer widths, looking at the layer centre) and never asked the
host for the comp camera, so moving or orbiting a camera layer left the
particles flat on the layer. It also had no Extras > Effect Camera. Separately,
the layer cache key ignored the comp camera and lights, so the effects that
read them (Card Dance / Shatter / Card Wipe Comp Camera, First Comp Light,
Caustics) kept a stale frame when the camera, a light or the layer moved.

Fix: as the Cycore manual describes, Particle World sees its particles through
the comp's active camera layer when there is one (EffectHost::comp_scene now
says whether its camera is a camera layer's, CompScene::camera_layer), through
card3d's comp-camera projection (factored out of Card Dance as comp_proj, with
Proj::view for depth, size scale and screen velocity). Otherwise it uses the
new Extras > Effect Camera: Distance (2), Rotation X / Y / Z (0) and FOV (50)
orbit the world origin; FOV moves the camera so the origin's plane keeps the
scale Distance gives it, so the defaults reproduce the old fixed camera bit for
bit (golden hashes unchanged) and old projects render as before. The Effect
Camera is left out of the simulation cache key, so animating it doesn't
restart the simulation. The plan is shared, so the GPU compositor follows too.
The layer cache folds the comp scene into the key of layers running an effect
in effects::READS_COMP_SCENE (render::comp_scene is shared with the host).

Tests: sim particle_world_follows_the_comp_camera (panning a camera layer moves
the particles, zooming spreads them, the Effect Camera is ignored then, the
default view keeps the Effect Camera, cameras facing away / zero / NaN draw
nothing) and particle_world_effect_camera (missing params = defaults, rotation,
distance and FOV change the view, extremes stay finite, the sim key ignores the
camera); render particle_world_follows_the_comp_camera (a real camera layer
panned 40 px moves the particles left, and the cached render after the move
equals an uncached one: it failed with the old cache key); gpu
particle_world_through_the_comp_camera (CPU vs GPU at 8 / 32 bpc, full and
half resolution). particle_golden / sim_golden unchanged. effects.md
regenerated; parity.md and gaps.md describe the fix.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 00:35:25 +07:00
Brandon Thomas e12bf5ca7d Merge pull request #289 from storytold/fix/227-shape-effect-points
Effects: effect points on shape layers start at the layer centre (#227)

# Conflicts:
#	crates/ui-egui/src/panels/puppet_tool.rs
#	crates/ui-egui/src/panels/viewer.rs
2026-10-09 09:32:13 -04:00
bflatasticandClaude Opus 5.5 56b374800d Masks: an open mask leaves its layer whole until it is closed (#290)
While a mask was being drawn with the Pen, its open path was filled as
if closed, so the layer went black except inside the points placed so
far, which made rotoscoping by eye impossible. As in After Effects, an
open mask makes no transparency: the layer shows whole until the path
is closed. Effects that take a mask as a path (Stroke and the others)
still get open masks.

Test: open_masks_make_no_transparency (render).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 17:12:22 +07:00
bflatasticandClaude Opus 5.5 940bea3ba7 Effects: effect points on shape layers start at the layer centre (#227)
Shape and text layers have comp-sized effect bounds centred on their
origin, but effects measured positions from the origin: a point at its
default "layer centre" sat at the comp's bottom-right corner, so Twirl
on a centred shape changed nothing and Bulge only its bottom-right
quarter. As in After Effects, effects now work in effect space,
measured from the top-left of the layer's effect bounds.

The renderer moves the layer buffer into effect space for the whole
stack (Buf::rebase, CPU and GPU alike) and hands effects everything
else in it: masks, other layers' pixels for layer parameters (each in
its own effect space, so Set Matte and displacement maps see a whole
shape layer), the layer's own frames (layer_input, also what Puppet,
Roto Brush and the Layer panel read) and the comp camera
(CompScene::rebased). Layer bounds are now right for every effect, so
pin_rect and EffectEnv::bounds_origin go and layer_rect serves edge
pinning too. Adjustment layers still run on the comp below as it is.

effect_bounds / EvalCtx::effect_to_comp replace the repeated "comp size
when there is no source" code; the viewer's effect point handles and
eyedroppers, Puppet pins, the Layer panel (paint, Roto Brush) and the
tracker's Corner Pin output use them.

Project schema 2: opening a schema 1 project moves positions held by
effects on shape and text layers by half the comp size, so set points
keep their place (point parameters with keyframes, Paint paths and
clone positions, Puppet seeds and pins, Liquify and Roto Brush
strokes). Points still at their default become the layer centre;
expression controls, adjustment layers and expressions are left as
they are (docs/architecture.md). The disk cache's render version is
bumped.

Tests: default_effect_points_sit_at_the_centre_of_a_shape_layer and
layer_parameters_see_a_whole_shape_layer (render, both fail before),
effect_points_on_a_shape_layer (GPU vs CPU),
opening_a_schema_1_project_moves_shape_layer_effect_points_into_effect_space
(engine), and the effects migration tests.

Part of #227

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 20:33:03 +07:00
bflatasticandClaude Opus 5.5 754e80bdf9 Effects: Turbulent Displace displaces the whole layer, not one quadrant (#227)
Edge pinning (Turbulent Displace's default Pin All, Wave Warp's
Pinning, Bulge's Pin All Edges) holds the layer bounds still: a
comp-sized rectangle for shape and text layers. That rectangle started
at the layer's origin, but a shape layer's content surrounds its origin
(anchor 0,0), so everything left of or above the origin counted as
outside the layer and was pinned: only the bottom-right quadrant of a
centred shape moved.

The renderer now passes the bounds' top-left in layer coordinates
(EffectEnv::bounds_origin): (-w/2, -h/2) for layers without a source
rectangle, (0, 0) otherwise. util::pin_rect places the bounds there and
the three effects use it on the CPU and the GPU. Effect point
parameters keep their current layer coordinates.

Test: edge_pinning_displaces_all_of_a_centred_shape_layer,
edge_pinning_on_a_shape_layer (GPU vs CPU).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 12:20:10 +07:00
Brandon ThomasandClaude Opus 5.5 fe89ab9146 Never crash: render and gpu crates without panic!()
render: the debug-only quantisation check uses debug_assert! instead of panic!. gpu: the
test-only panic on a wgpu validation error is cfg(test) with a narrow allow, and release
builds only log. Test-only unreachable!() calls become panic!(). Denies the panic lints in both
crates.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-04 14:20:37 -04:00
Brandon ThomasandClaude Opus 5.5 225f31bf50 Merge main into M9.13 (GPU kernels defer CPU-only controls via catalog::gpu_supported)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-03 07:29:30 -04:00
Brandon ThomasandClaude Opus 5.5 0ed5c87b94 M9.13: Card Dance / Shatter / Card Wipe camera systems, lighting and material
- card3d: shared Camera System (Camera Position with rotations, X/Y position and
  Transform Order; Corner Pins with focal length; Comp Camera via EffectHost::comp_scene),
  Lighting (Distant / Point / First Comp Light, colour, position, depth, ambient) and
  Material (diffuse, specular, highlight sharpness).
- Shatter: Custom Shatter Map (+ White Tiles Fixed), Gradient group, Textures group
  (front/side/back modes and layers, colour, opacity) and extrusion side rendering.
- Card Wipe: true 3D cards, Back Layer as a layer parameter (old None/Self popup migrated),
  Flip Direction, Position / Rotation Jitter.
- Renderer supplies the comp camera and first light to effects.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-03 02:59:10 -04:00
Brandon ThomasandClaude Opus 5.5 aafe46e091 M12.7: Classic 3D runs on the GPU (per-pixel depth sort, lights, ray-cast shadows, DOF); Auto sends 3D comps to the GPU
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-03 02:15:01 -04:00
Brandon ThomasandClaude Opus 5.5 41a796155f M12.2: test that the Auto backend keeps 3D comps on the CPU compositor
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-02 13:06:18 -04:00
Brandon ThomasandClaude Opus 5.5 029c0da5e5 M2.4: bit depth + linear blending + working space
8/16 bpc projects clamp and quantise layer pixels after source/masks and
every effect, and the comp after every layer (16 bpc = 0..32768); 32 bpc
keeps over-range values. Blend modes without HDR support clamp their inputs
in 32 bpc. Working space (sRGB, Rec. 709, Rec. 2020, Display P3; matrices
derived from the published primaries), footage colour profiles from stream
metadata or Interpret Footage, Linearize Working Space and Blend Colors Using
1.0 Gamma. Layer cache keys include the colour settings. Project panel depth
button: click cycles, Alt-click opens Project Settings.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-02 10:03:36 -04:00
Brandon Thomas 1e8768ad18 Merge branch 'worktree-agent-a022a00e662ea8d21'
# Conflicts:
#	crates/media/src/pool.rs
#	crates/render/src/lib.rs
#	crates/render/src/tests.rs
2026-10-01 22:58:51 -04:00
Brandon ThomasandClaude Opus 5.5 210ec66ecf M9.3: render tests for effect masks and layer parameters
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 22:32:50 -04:00
Brandon ThomasandClaude Opus 5.5 a2ff724ac2 M12.1: render cache + parallel compositing fast paths
- render: LayerCache (content-keyed processed-layer cache: source -> masks ->
  effects, keyed by a hash of the layer's non-transform props evaluated at the
  frame time, solid item, switches, scale; time folded in for clock-driven
  effects / wiggle paths). Static and transform-only layers render once;
  edits only re-render the edited layer. Session + UI frame jobs share it.
- effects: TIME_DEPENDENT list + test that every clock-reading effect is listed.
- raster: affine composite fast path (per-row span clipping, unchecked interior
  bilinear, integer-translation copies, inlined Normal blend), checked against
  composite_warp_reference; box/Gaussian blur without transposes, two
  ping-pong buffers; accumulate_warp so motion blur sums into one buffer
  instead of one full-frame image per sub-sample.
- ui: viewer frame is urgent and jumps the prefetch queue; stale-revision jobs
  are dropped; paused prefetch waits for the viewer frame; "Frame Render Time"
  reports viewer frames only; parallel f32 -> Color32 conversion.
- cli: `frame --bench N` (per-layer/per-effect timings, wall + CPU time) and
  `frame --bench-play N` (consecutive frames with/without the layer cache).
- tests: cache transparency (scrub, edits of values/keys/effects/masks/
  solids/text/timing), hit/miss accounting, time-dependent effects, demo
  cached == uncached, fast warp/blur/accumulate == reference.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 21:34:33 -04:00
Brandon ThomasandClaude Opus 5.5 808cd490cd M0.1–M0.7: workspace, time/geom/color/keyframe/project/raster/path/text/effects/render crates
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 14:05:20 -04:00