Commit Graph
95 Commits
Author SHA1 Message Date
daijroandClaude Opus 5.5 74b151cedc Footage: reduced-resolution renders get movie frames converted at their size
Cause: at Half, Third and Quarter resolution (the viewer's Auto resolution
in most windows) every movie frame was converted from Y'CbCr to f32 RGBA at
full size and then resampled down. In the browser (wasm, one thread) that
was about 8 ms converting a 1080p frame, 6 ms resampling it and 2 ms
zeroing a 33 MB buffer, per layer and frame, for a frame shown at a
quarter or a ninth of its pixels; the footage frame cache held the
full-size frames.

Fix: FootageSource::frame_at_size asks for a frame shown at a given size
(default: the full frame, as before). The renderer asks for it where it
resampled footage (below 3/4 scale; not for proxies, fields or Interpret
Footage's pixel options, which need the full frame). MediaPool makes opaque
4:2:0 movie frames of the footage's own size there: it box-filters them to
half size in Y'CbCr before converting (each 2x2 block of luma, and the
[1 6 1]/8 neighbourhood of its chroma sample, which is the mean of the
upsampled chroma its pixels get), resamples the rest of the way and caches
the result per size. Conversion is linear until colours clip, so this is
the RGB box filter resample starts with, except in blocks where some
colours clip. Other frames convert at full size and resample as before.
In the browser the conversion and resampling take about 4 ms instead of
16. Docs (architecture).

Tests:
- convert::scaled_conversion_matches_resampling_the_converted_frame: half,
  third, quarter and odd sizes of an unclipped 4:2:0 frame are within 1e-5
  of resampling the converted frame; larger sizes, odd frame sizes and
  4:4:4 convert at full size.
- tests_footage_size::reduced_renders_take_footage_resampled_by_the_source:
  a source that resamples frames itself renders the same frames as one
  that doesn't, at 8 and 32 bpc and every resolution, and is asked only
  below 3/4 scale, and not with Invert Alpha.
- footage::h264_frames_at_reduced_sizes (ffmpeg fixture): 1080p H.264
  testsrc2 frames, whose saturated colours clip, at 960x540, 640x360,
  480x270 and 323x182 are 58-62 dB from the resampled full frames, and
  are cached per size.
- convert's ignored 1080p bench also times the conversion at a third.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-09 16:44:49 -05:00
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
bflatasticandClaude Opus 5.5 d6de68b20d Import: Interpret Footage ▸ Preserve RGB keeps the file's values (#411)
Cause: float footage (OpenEXR, float TIFF) was always sRGB-encoded on
decode, and Interpret Footage could not turn that off, so an OCIO effect
on the layer converted values that were already encoded.

Fix: After Effects' Interpret Footage ▸ Color ▸ Preserve RGB
(Footage::preserve_rgb; file.interpretFootage {"preserveRgb": true}; a
checkbox in the Interpret Footage form; Remember / Apply Interpretation
carry it). The decoder keeps float values linear, and the working-space
conversion from the colour profile and Interpret As Linear Light don't
apply, so the file's values enter the composition unconverted. The media
cache key includes the flag, so both interpretations decode separately.

Tests: pool::preserve_rgb_reads_float_exr_values_unconverted,
tests_color::preserve_rgb_footage_is_not_converted (managed, linearized
and not), tests_proxy::guess_alpha_invert_and_linear_light (command,
render, Apply Interpretation).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 23:57:12 +07:00
bflatasticandClaude Opus 5.5 94e4afe8de Text: text layers are always rasterised at their on-screen scale (#390)
Text is vector in After Effects and stays sharp at any Scale. Here a
text layer was drawn at its font size and the bitmap resampled by Scale
unless Continuously Rasterize was on, so text grown with Scale went soft.
This reworks #200 (reverted in 29c4d3a for kinetic_typography).

Why kinetic_typography failed: its time remap key at 1.9 s sits on
frame 23 (1.917 s), so main-comp 0.3 s shows the precomp at 1.6026 s,
but the test compared it with the precomp rendered at 1.6 s. The moving,
motion-blurred title already differed by 0.89 of the 1.0 mean-difference
budget on main (0.987 in all); with continuous rasterisation the "Sub"
line, whose expression scale is 84.00 % at 1.6 s and 84.105 % at
1.6026 s, falls on either side of the 2^-1/4 quarter-octave step and was
drawn at 0.84 at one time and at 1.0 at the other, pushing the total to
1.075.

Fix: raster_scale treats text layers as always continuously rasterised
(shape layers and vector footage still follow the switch), and rounds
the quarter-octave step up past rounding noise only: an unscaled layer
at a fractional position measured its scale as 1 + 1e-15 and was
rasterised at 2^1/4, softening unscaled text. The QA test now compares
the remapped precomp with the precomp at the time the remap really
shows (read back from the property): difference 0.63, all of it the
title's motion blur, the Sub line identical.

Tests: tests_collapse::text_scaled_up_stays_sharp_without_the_switch
(from #200: 10 px text at 800 % matches 80 px text),
tests_collapse::unscaled_text_rasterises_at_the_output_scale (fails
without the noise tolerance), automation qa kinetic_typography.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 23:17:32 +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
bflatasticandClaude Opus 5.5 05188d036a M4.13: motion blur of collapsed precomps and of animated shape / text content
- Collapsed precomps: the renderer records the precomp layers a nested comp is drawn through;
  motion-blur sub-samples re-evaluate their transforms (when their motion blur is on) and map
  times down through each one, so the precomp layer's own motion blurs its nested layers. The
  containing (outermost) comp's shutter applies to collapsed layers. The GPU compositor gets
  this through Renderer::placement.
- Shape and text layers whose content changes within the shutter (compared by its cache key)
  draw their source at Samples Per Frame times and average them; the cache key covers every
  sub-sample's content.
- Tests: tests_motion_blur_depth (collapsed vs flat, the containing shutter, shape content vs
  the same move by Position); each fails without the change.
- Docs: roadmap, parity.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-05 12:35:30 +07:00
Brandon Thomas 4926dd2c4c Merge pull request #35 from storytold/pr/never-crash-render-gpu
Never crash: render and gpu crates without panic!()
2026-10-04 15:33:18 -04:00
bflatasticandClaude Opus 5.5 995d99f938 M4.11: one motion blur gate for layers, masks, effects and Advanced 3D
`Renderer::mb_on` (render options × the comp's switch × the layer's switch as the precomp
layers above limit it) now decides everywhere:
- Mask motion blur checked only the comp's switch and the layer's own switch, so Render
  Settings ▸ Motion Blur ▸ Off for All Layers and a precomp layer with motion blur off still
  blurred masks; it now takes the gate (`masks::MaskBlur`) and the comp's Samples Per Frame
  (four in Draft) instead of a fixed eight.
- Effects that read the shutter (`EffectEnv::shutter`) get it only when the layer is motion
  blurred in this render.
- Advanced 3D layers follow the precomp layers' Motion Blur switches too.
- The layer cache key of a layer with masks or effects includes whether it is blurred and the
  comp's shutter and samples, so a buffer blurred for the viewer is never reused by a render
  with motion blur off.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-05 01:55:34 +07:00
bflatasticandClaude Opus 5.5 0b5cff1743 M4.10: a nested comp shows nothing before it starts or after it ends
A precomp layer trimmed out (or time-remapped) past its nested comp's end kept drawing the
nested layers whose bars ran on. Like After Effects, the nested comp now shows nothing outside
its own span (`Comp::covers`), flattened, through a proxy or with Collapse Transformations, on
the CPU and the GPU (both go through `Renderer::source` / `collapse_into`).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-05 01:47:54 +07:00
bflatasticandClaude Opus 5.5 0fe6db00e8 M4.9: Preserve frame rate when nested or in render queue, Preserve resolution when nested
Composition Settings ▸ Advanced has both options (they were missing from the model, the
renderer and the dialog):
- Preserve frame rate: nested in another comp, the comp shows only its own frames
  (`EvalCtx::nested_time` floors the precomp layer's source time to the nested comp's frame
  rate; used for the nested frame, its proxy, aux channels, collapsed transformations and the
  viewer's internal wireframes), and the Render Queue renders it at its own rate whatever the
  Frame Rate override (`RenderSettings::rate`).
- Preserve resolution: nested in a comp rendered at Half / Third / Quarter, it renders at full
  size and the buffer's scale places it.
- `comp.settings {preserveFrameRate, preserveResolution}`, `comp.info` reports them, scripts
  read and set `CompItem.preserveNestedFrameRate` / `preserveNestedResolution`, Pre-compose
  copies them, and the dialog registers `dialog.comp.preserveFrameRate` /
  `dialog.comp.preserveResolution`.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-05 01:33:14 +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
bflatasticandClaude Opus 5.5 fa27d621e0 M4.8: Edit ▸ Purge clears what it names: disk and snapshot purges keep the RAM preview, memory purges drop decoded footage
- Every purge emptied the viewers' RAM preview; Purge ▸ All Disk Cache and Snapshot now leave
  it (Image Cache Memory, All Memory, All Memory & Disk Cache, All and All 3D Cache still
  clear it).
- The memory purges also drop the decoded footage frames (`FootageSource::purge`, the media
  pool's `clear_frames`; decoders stay open), so footage reads decode again.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-05 01:03:47 +07:00
Brandon ThomasandClaude Opus 5.5 f3715aac32 M13.30: web depth and polish
- GPU in browser job workers: each job worker opens its own WebGPU device
  (deferred readbacks); the Render Queue export and the analyses' frame loops
  are futures (render::passes, offload::run_request_async) whose frames
  render in passes, awaiting the device between them. GPU particles and
  Advanced 3D read back under keys too. workers.jobs reports passes and
  readbacks; the smoke test measures them.
- Layer buffers in the browser's OPFS disk cache: frame workers back their
  layer caches with a PrefetchStore; the page plans what to fetch before a
  request from recent misses (LayerPrefetch over the shared DiskIndex).
- Templates embed footage (default on, size-capped with a warning) and
  creating from a template extracts it next to the new project / into
  browser storage.
- ICC LUT profiles (lut8/lut16/lutAtoB/lutBtoA, from the public ICC spec) in
  Simulate Output > My Custom RGB, baked into a 3D LUT for the viewer.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-04 02:57:17 -04:00
Brandon Thomas ca9a30bf0c Merge branch 'main' into worktree-agent-a38a174c36aa9f23a 2026-10-03 19:52:55 -04:00
Brandon ThomasandClaude Opus 5.5 1b726349ab M13.24: web app depth (WEB-1) — GPU effects in frame workers, OPFS disk cache, storage manager
- GPU in the browser: each frame worker opens its own WebGPU device (Gpu::request_deferred) and
  renders the GPU compositor and GPU effects with deferred readbacks (effectcraft-gpu deferred):
  readbacks keyed by content start with map_async and miss, the pass returns placeholders, the
  layer cache's gate drops inserts, and FrameServer::resume renders again once the device
  delivered. Backend Auto times whole frames per comp in the workers. Frames with effects go to
  GPU workers instead of the page. CPU fallback without WebGPU in workers (?nogpuworkers).
- Fix: a WGSL constant (3.40282347e38) that Chrome rejects invalidated every GPU kernel in Chrome
  (the page's compositor too); a test checks every float literal fits f32.
- Disk cache in the Origin Private File System: workers write sealed frame entries with sync
  access handles (temp file + move), the page keeps the DiskIndex (LRU under the settings' limit,
  at most half the quota) and reads hits instead of rendering; survives reloads; blue cache bar.
- Storage manager: Settings ▸ Disk ▸ Browser Storage (usage/quota, persistent storage, Clear
  buttons, automation ids) and storage.info / storage.persist / storage.clear (StorageHost).
- Docs: web.md (GPU workers, deferred passes, disk cache, storage manager, threading design:
  one engine instance per worker), architecture, preferences, parity (WEB-1), roadmap.
- Tests: deferred passes vs CPU on a real device, placeholder gating, frame server passes and
  Auto, GPU worker routing + disk cache across a reload, storage commands and widgets, store
  usage by kind; smoke test: GPU effect frames in workers with pixel parity, disk hits after a
  reload, storage manager.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-03 18:35:03 -04:00
Brandon ThomasandClaude Opus 5.5 0c4e533460 M13.22: GPU compositing of Advanced 3D runs with blend modes, track mattes (2D and 3D), Preserve Transparency, and environment backgrounds (Classic and Advanced 3D skies)
render: three_d::adv::SplitRun (Renderer::split_adv_run) hands draw_run's split path to an
accelerator as data (main scene, special layers far to near, 3D mattes drawn solo);
Renderer::sky_draw / three_d::SkyDraw for Environment Light Background layers. gpu: the walk
draws skies (adv_sky kernel), resolves each special layer, hides it behind the nearer main
scene (occlude kernel) and composites it through the 2D path without readbacks.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-03 18:26:06 -04:00
Brandon Thomas a4f4d72f27 Merge branch 'main' into worktree-agent-a4b0610bd14276508 2026-10-03 10:53:00 -04:00
Brandon ThomasandClaude Opus 5.5 9ff0e5aa3c M13.13: gpu texture pool, Auto per-comp backend choice, warp-family GPU ports
- gpu: pooled working textures (released once every encoder that could read
  them is submitted), shared zero images, reused readback staging buffers,
  direct readback into Image; NaN-poisoned scratch images under test and
  NaN-aware diffs; validation errors panic under test
- render: AutoPick (per comp / scale / path EWMA of CPU vs GPU frame times,
  warm-up and periodic re-probe) behind Backend::Auto; viewer uses it too;
  cached adjustment footprints (uploaded once)
- gpu fx_warp: Warp, Bezier Warp, CC Bend It, CC Page Turn, Smear, Reshape,
  Color Emboss, Cartoon; sliding-histogram median for large radii; CC Power
  Pin perspective < 100
- cli: bench --gpu reports Auto and per-frame upload / readback MB

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-03 10:31:31 -04:00
Brandon ThomasandClaude Opus 5.5 dc132bc219 Merge main into M13.11 (bokeh kernel_spans/blur_levels, Essential Graphics as_type controls with mirrors and links)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-03 09:54:37 -04:00
Brandon ThomasandClaude Opus 5.5 bb24b931a6 M13.11: advanced 3d gpu
Advanced 3D runs render entirely on the GPU: every motion-blur sub-sample
rasterised, resolved and averaged, the depth-based iris depth of field
(Classic 3D bokeh spans, highlight boost, progressive levels), the sRGB
encode and the composite over the GPU canvas (Accelerator::render_3d,
Renderer::prepare_adv_run, adv3d.wgsl). Wireframe outlines draw on the GPU.
Fixes NaN environment lookups for straight up/down normals on Metal.
bench --gpu gains an Advanced 3D comp (--adv3d).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-03 09:38:11 -04:00
Brandon ThomasandClaude Opus 5.5 5c54ccd8d0 Merge main into M13.10
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-03 08:59:35 -04:00
Brandon ThomasandClaude Opus 5.5 5bb6768766 M13.10: web frame workers fed by project diffs, offloaded Roto Brush propagation, non-blocking wait jobs, browser Media Browser
Viewer frames render in long-lived Web Workers holding a project replica
(engine::remote: structural JSON diff/patch, Mirror, FrameServer); the
frame cache hands jobs to a RemoteFrames renderer (UI-thread fallback).
Roto Brush propagation runs in a job worker and streams segmentations
back (FrameSeg binary form), relayed to frame workers. Control-channel
wait:true commands whose job is offloaded reply when it ends. The Media
Browser browses a pluggable Browser: the file system on the desktop;
browser storage and File System Access folders on the web.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-03 08:36:00 -04:00
Brandon ThomasandClaude Opus 5.5 404b855986 Merge main into M13.6
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-03 07:53:31 -04:00
Brandon ThomasandClaude Opus 5.5 a2693c9d15 M13.6: Classic 3D bokeh depth of field on the GPU (WGSL); 3D-matte GPU check
Planes prepared for the GPU carry their depth of field (padding, radius map, levels) and the
bokeh_boost / bokeh_prefix / bokeh_gather kernels blur them where they are drawn, with the CPU's
spans; GPU-vs-CPU agreement tests for iris shapes, highlights, fringe, Fast Rectangle, tilted
planes and a 2D layer with a 3D track matte.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-03 07:44:43 -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 baf4716246 M13.5: extended viewer (custom 3D views / Draft 3D render the pasteboard around the comp frame; view.extendedViewer)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-03 05:14:12 -04:00
Brandon ThomasandClaude Opus 5.5 3a7c9c5f61 M9.13: Transform shutter-angle motion blur, Glow Operation / Arbitrary Map, Cartoon Edge Enhancement
- Transform: Use Composition's Shutter Angle / Shutter Angle, sampling the transform across
  the shutter via EffectHost::params_at (EffectEnv::shutter carries the comp shutter when
  motion blur is on); the GPU path defers to the CPU when blurring.
- Glow: Glow Operation (blend modes) and Glow Colors > Arbitrary Map.
- Cartoon: Advanced > Edge Enhancement (shock-filter sharpening / softening).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-03 04:23:15 -04:00
Brandon Thomas 7ac5317ce9 Merge main into M13.2 2026-10-03 04:19:01 -04:00
Brandon ThomasandClaude Opus 5.5 da0ec526f3 M13.2: PDF / Illustrator (.ai) / EPS vector footage (effectcraft-pdf): continuous rasterisation, layered composition import, Create Shapes from Vector Layer; SVG render tree clip groups
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-03 04:12:21 -04:00
Brandon ThomasandClaude Opus 5.5 3c586e2dba M9.13: Radio Waves Image Contours / Mask waves, Parameters Are Set At, reflection, profile
- Wave Type: Polygon, Image Contours (source layer channel threshold, pre-blur, tolerance,
  contour index, source centre) and Mask, rippling outward from the outline (exact signed
  distance transform, util::signed_distance).
- Parameters Are Set At Birth via the new EffectHost::params_at; Render Quality; Reflection
  off the layer edges; Stroke Profile.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-03 03:42:37 -04:00
Brandon Thomas 871362ba96 Merge branch 'worktree-agent-aba044eaf08eded94'
# Conflicts:
#	crates/render/src/three_d/compose.rs
2026-10-03 03:33:36 -04:00
Brandon ThomasandClaude Opus 5.5 fa27d000ea Merge main into M14.5 (settings and menus)
Display Color Space setting joins the live list; View3D::Default maps to view.3d.default for
the Assign Shortcut submenu; stub tests use the stubs that remain.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-03 03:29:39 -04:00
Brandon ThomasandClaude Opus 5.5 b17d2c05e6 Merge main into M14.5 (settings and menus)
Reconciled with main's keyframe labels (same Keyframe::label field; keys.setLabel and
keys.selectLabelGroup from main are kept, M14.5's duplicates removed; Edit ▸ Label on
selected keys delegates to the label helper), proxies (RenderOpts::proxy next to
nested_switches/draft_shadows), offloaded renders (Work carries nested_switches), wasm
audio pump (preview mix rate), variable font axes and mask feather points.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-03 03:11:45 -04:00
Brandon ThomasandClaude Opus 5.5 e7fdd6fdbd Merge main into M12.7 (environment background layers keep their 3D runs on the CPU path)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-03 03:03:21 -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 f855a4b55b M14.5: wire the remaining settings; keyframe assistants and labels; AE menu entries
Settings: 56 of 59 not-yet-wired settings now change behaviour (nested-comp switches,
constant vertex count, related-item time sync, match-name pick whip, split-layer order,
Home on open, motion path span, internal wireframes, zoom quality, label-coloured tabs,
mask colour cycling, gradients, grid/guide styles, text engine, font preview/recent/native
names, missing frames, unlabeled alpha, drag import, default output folder, segmenting,
bit depth names, preview sample rate, disk/media/conformed-audio caches, RAM reserve and
low-memory reduction, Video Preview window, 3D reference axes/extended viewer/draft
shadows, script file gate + File.execute warning, expression editor options and error
banner). Three stay display-only and are documented.

Features: Convert Audio to Keyframes, RPF Camera Import (JSON/CSV camera data),
keyframe colour labels + Select Keyframe Label Group, Recent Animation Presets.
Menus: Edit > History, File > Import Recent Footage, Replace Footage > With Layered
Comp, Save a Copy As XML (.ecprojx, opens again), Composition > VR (Create VR
Environment, Extract Cubemap), Assign Shortcut to 3D view / workspace, Window viewer
labels + open viewers, Help > System Compatibility Report / Enable Logging / Reveal
Logging File. Dynamic menu nodes (@dynamic:…) shared by the egui and native menus.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-03 02:45:44 -04:00
Brandon ThomasandClaude Opus 5.5 0e3b354520 M12.7: GPU particles (CC Particle World, CC Particle Systems II, Particle Playground cannon): compute-shader simulation with GPU checkpoints, CPU as the oracle
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-03 02:44:36 -04:00
Brandon Thomas 86b8e24417 Merge branch 'main' into worktree-agent-a15cecfec57d5290d
# Conflicts:
#	crates/effects/src/ocio.rs
#	crates/engine/src/commands/stubs.rs
#	docs/parity.md
2026-10-03 02:26:19 -04:00
Brandon ThomasandClaude Opus 5.5 9994f5d309 M7.7: viewer and colour completion
View > Switch 3D View > Default, Split with New Locked Viewer, Use Display Color
Management (sRGB/P3 display in Settings > Previews), Simulate Output (Rec. 709/2020,
P3, sRGB, Linear, NTSC, PAL, Mac 1.8, Custom; Preserve RGB). Project Settings: Color
Engine (OCIO built-in config with ACEScg/ACES2065-1 working spaces), HDR clip/compand/
tone map, output space incl. Rec. 2100 PQ/HLG (SMPTE ST 2084, BT.2100, BT.2408
reference white; GPU curves too), Time Display Feet + Frames (35mm/16mm) display and
entry. OCIO effects read custom .ocio configs (YAML subset; Matrix/File/Exponent/Log/
LogAffine/CDL/Range/Group transforms, roles, displays/views).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-03 02:25:56 -04:00
Brandon ThomasandClaude Opus 5.5 878b47b5ed M12.7: adjustment layers on the GPU (effect stacks resident on the device, CPU fallback per non-GPU effect)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-03 02:23:01 -04:00
Brandon ThomasandClaude Opus 5.5 be282ce194 Merge main into M12.7 (bokeh DOF: the GPU 3D path takes the CPU's bokeh-blurred plane buffers)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-03 02:17:50 -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 8696d1e9ba M7.7: camera/light rigs and Advanced 3D motion blur, blend modes, track mattes
Layer > Camera > Create Stereo 3D Rig (left/right eye comps with expression-linked eye
cameras, Stereo 3D Controls effect, stereo comp through 3D Glasses), Create Orbit Null,
Create Cameras from 3D Model; Layer > Light > Create Lights from 3D Model
(KHR_lights_punctual), Control Light with Camera, Create Environment Light Background
Layer (equirectangular sky drawn through the camera). glTF cameras and punctual lights
are parsed by effectcraft-model.

Advanced 3D: per-sample motion blur over the comp shutter, and blend modes / track
mattes / Preserve Transparency composited through the 2D path in depth order.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-03 00:27:47 -04:00
Brandon ThomasandClaude Opus 5.5 a4f32f8df2 Merge main into M13.5 long-tail polish
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-03 00:25:09 -04:00
Brandon ThomasandClaude Opus 5.5 dbcda2eba9 Merge main into CMP-7/ANM-5/PRJ-8/PRJ-3 work
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-02 23:43:41 -04:00
Brandon ThomasandClaude Opus 5.5 bbaee1fa0f M13.5: stroke taper/wave/multi-dashes, radial gradient highlight, variable-width mask feather, adaptive motion-blur samples
Shapes (SHP-2): Stroke Taper (pixels/percent start/end length, width, ease) and
Wave (amount, pixels/cycles, wavelength, phase) rendered as a variable-width
outline; Dash 2/Gap 2/Dash 3/Gap 3 (shape.dashes.add/remove, timeline +/-
buttons); radial gradient Highlight Length/Angle as a focal gradient.
Masks (MSK-1): mask feather points on the Mask Path (mask.featherPoint.*,
Mask Feather tool add/drag), per-point signed radius and tension, rendered
from the signed distance to the path; carried through vertex edits.
Motion blur (LYR-10): Adaptive Sample Limit comp setting; 2D layers take one
sample per pixel of shutter travel between Samples Per Frame and the limit.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-02 23:22:53 -04:00
Brandon ThomasandClaude Opus 5.5 c33b80614a PRJ-8: proxies — Set Proxy / None / Use Proxy / Create Proxy / Interpret Proxy, Proxy Use; PRJ-3 interpret fields, PAR, alpha guess
Items (footage and comps) carry a proxy rendered in their place at the source's size when
its switch and Render Settings > Proxy Use allow it; Create Proxy queues a half-resolution
render whose post-render action attaches it. Interpret Footage gains Separate Fields
(upper/lower first, fields become frames at twice the rate), Guess alpha with matte colour,
explicit matte colour, Invert Alpha, Interpret As Linear Light; non-square footage, solids
and precomps are stretched by their pixel aspect in the comp. The four proxy stubs are gone.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-02 23:11:03 -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 abd39f5fd8 CMP-7: Essential Graphics controls, master properties, .ectemplate templates, Responsive Design — Time
Comps expose controls (properties typed as text/color/slider/checkbox/point/angle/dropdown,
Media Replacement, groups, comments); precomp layers get an Essential Properties group whose
edits override per instance (Push to Comp / Revert); templates export/import as an open ZIP
(manifest.json + project subset + media + poster). Stretched precomps keep protected regions
at their original speed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-02 22:44:06 -04:00