A rayon worker running frame_at could wait on the in-flight condvar for a
frame whose decode sat lower on its own stack (work stealing during the
decoder's parallel join), hanging footage playback and the media tests.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Convert to Editable Styles / Show All / Remove All / Drop Shadow ... Stroke now
run main's layer.style.* commands; the layer.styles stub is gone.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Integrate main (render queue, timeline/keys, time remap, masks/pen, 3D, MCP/CLI).
- Menu tree now runs renderQueue.add, layer.enableTimeRemap, layer.timeReverse,
layer.freezeFrame/OnLastFrame, prop.separateDimensions, mask.setClosed,
layer.cameraSettings, view.3d.* / view.3d.last / view.reset3DView, main's
layer.autoOrient and keyframe velocity/interpolation/time-stretch dialogs;
matching stubs deleted (view.3d.default stays disabled).
- Keyframe clipboard is main's (keys.copy/paste); Paste Reversed Keyframes
reuses it. Animation-menu commands moved to commands/animation.rs.
- Main's spec menu paths/labels aligned with AE (Camera Settings under
Layer > Camera, "..." labels, Freeze On Last Frame).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Layer Styles (Drop Shadow, Inner Shadow, Outer/Inner Glow, Bevel and Emboss, Satin,
Color/Gradient Overlay, Stroke) and Blending Options (Global Light, Fill Opacity, R/G/B,
Knockout, Blend Interior Styles as Group) as a layerStyles property group with AE names,
order and defaults. Rendered in layer space after effects (exterior passes composite with
their own blend modes below the body), cached per pass, scaled with render resolution.
Commands layer.style.* (menu Layer > Layer Styles), Global Light shared per comp, timeline
eye switches.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Resolve conflicts with perf (layer cache / Arc<Buf>), export (RenderOpts.view: None
for output), timeline (separate dimensions + one-node POI visibility), mask/pen
viewer gestures (alongside camera tools and view-aware layer matrices), key
dialogs (alongside Camera/Light Settings), render queue + MCP command modules.
3D path tangent honours separated position; DOF blurs a per-frame copy so cached
layer buffers stay shared. New test: cached renders match uncached after camera,
focus, light and 3D view changes. Fix a clone-on-copy lint from main.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- layer.autoOrient {mode: off|alongPath|towardsCamera|towardsPointOfInterest}
(Layer > Transform > Auto-Orient…, Cmd+Alt+O); render support for Orient
Along Path (2D and 3D) and Orient Towards Camera (with recursion guard).
- Layers parented to cameras/lights follow their full rotation.
- Draft 3D turns off lights and shadows (and DOF).
- Turning the 3D switch off discards Z values, Orientation and X/Y Rotation.
- Tests for all of the above.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Comp durations (comp.new / comp.settings) are whole frames.
- layer.addItem start/out, layer.timing in/out/start/delta and time-stretch in/out snap to
the nearest comp frame; prop.addKey / prop.set with an explicit time key the nearest frame.
- The demo project builds every time on 29.97 fps frames (Lower Third in = frame 150 =
0:00:05:00, comp = 300 frames).
- Test: demo + commands stay frame-aligned.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Closed-form weather/bubble/star effects; stepped particle, wave and foam sims through the
checkpointed SimCache (seek-consistent); band-bucketed sprite/piece rasteriser and textured
3D pieces via per-piece inverse homography.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Engine (mask.rs, tests in tests_timeline.rs incl. render + undo/redo):
mask.new, mask.addVertex, mask.setVertex, mask.setClosed (Layer > Mask and Shape Path >
Closed), mask.selectVertices, mask.moveVertices (merged drags), mask.deleteVertices
(Delete with vertices selected), mask.remove / mask.removeAll (Layer > Mask). Edits of an
animated Mask Path key the current time.
Viewer: Pen tool on the selected layer - click = corner vertex, drag = Bezier vertex,
click the first vertex to close, Esc/Enter or another tool ends the path; rubber band to
the pointer. Selection tool: click/shift-click mask vertices, drag selected vertices,
drag tangent handles (symmetric; Alt breaks). Vertices register automation ids
viewer.mask.<uid>.vertex.<i>. Mode/inverted/feather/opacity/expansion stay in the
timeline mask rows.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Viewer renders through the comp's 3D view (RenderOpts.view; FrameKey hashes
the view camera), shows the view name, and the bottom-bar 3D View dropdown
(automation id viewer.view3d) switches Active Camera/Front/…/Custom View 3.
- Orbit / Pan / Dolly tools drag the current view (camera layer in Active
Camera, merged into one undo step; view cameras otherwise).
- Handles, gizmo and picking go through the view camera; 3D layers move in
the view plane at their depth.
- Camera frustum + POI and light position/direction wireframes
(viewer.camera.<id>, viewer.light.<id>).
- Camera Settings / Light Settings dialogs open from New Camera/Light,
Camera/Light Settings and Layer Settings; OK runs the engine commands.
- Timeline: POI only for two-node cameras/auto-oriented lights; "Z Rotation"
label on 3D layers.
- Headless egui_kittest tests (UI wiring + opt-in wgpu snapshots); fix the
remaining workspace clippy lints.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Properties with an expression get an editor row in the timeline: Expression label,
enable (=) switch, pick whip, syntax-error warning, and a multiline code editor in the
time-graph area (commits on blur or Cmd/Ctrl+Enter via prop.setExpression).
- Expression pick whip: drag onto another property row -> prop.pickWhip (AE reference
expression). Parent pick whip in Parent & Link: drag onto a layer -> layer.setParent.
- Alt-click on a stopwatch starts with the property's own reference (transform.opacity).
- Timeline rows have variable heights; the empty-graph box-select area sits under the rows.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
engine comp.settings/comp.new: anchor (shifts unparented layers and their
position keys on resize), startTime/startTimecode, renderer.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Current time shown as AE does: 0:00:02:15 (hours unpadded; time::format_timecode_ae),
frame count zero-padded to 5 digits (00075 (29.97 fps)).
- Time ruler labels in seconds:frames (00:15f, 01:00f) with frame-based adaptive spacing.
- time.set snaps seconds to the nearest frame (2.5 s at 29.97 -> frame 75).
- Mode / Track Matte columns hidden until Toggle Switches/Modes (F4), as in AE's default.
- Timeline outline pane sized to its columns and clipped so Parent & Link never draws
over the time graph in narrow timelines.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Engine (all commands with undo/redo + tests in engine/src/tests_timeline.rs):
- keys.copy/paste (Edit Copy/Cut/Paste route to keys when keys are selected;
relative timing kept, paste at CTI, cross-property paste of same type),
keys.selectAll (Cmd+Alt+A), keys.nudge* (Alt+Arrow, Alt+Shift+Arrow),
keys.set / keys.setEase (graph editor drags), keys.info (dialog data),
keys.timeReverse; keys.interpolation gains continuous/auto Bezier, spatial
interpolation and roving; keys.velocity takes per-dimension values and
Continuous.
- Roving keys (keyframe::retime_roving): constant speed along the motion path.
- Layer > Time: layer.timeStretch (percent|duration, hold in/current/out),
layer.timeReverse (Cmd+Alt+R), layer.enableTimeRemap (Cmd+Alt+T),
layer.freezeFrame, layer.freezeOnLastFrame; render uses Time Remap as the
source time for precomp/footage layers.
- prop.separateDimensions (X/Y/Z Position; prop.set on Position writes them).
- layer.setParent compensates so the layer stays in place (compensate:false
to opt out).
- prop.pickWhip writes AE-style reference expressions (thisComp.layer(..),
effect(..)(..), mask(..).maskFeather, temp=…;[temp,temp], …[0]).
- prop.setExpression: syntax errors keep the text but disable the expression.
- expr: arrays of properties returned by an expression are resolved.
UI: Keyframe Velocity, Keyframe Interpolation and Time Stretch dialogs;
Graph Editor (value + speed graphs, draggable keys and Bezier/influence
handles, auto-zoom, fit, show selected, separate dimensions, hold/linear/
auto Bezier/Easy Ease buttons); key + layer context menus. Clears the
workspace clippy -D warnings failures.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- 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>
- Properties panel (panels/properties.rs): Layer Transform with keyframe navigator
or stopwatch, AE value formatting (integers, %, Nx+N° rotation), linked Scale,
Reset; Text (font/style/size/leading/tracking/stroke, fill/stroke toggles);
Paragraph (7 alignments); Text Animation > Add Animator; scrolling.
- Tabs name what they show: Composition <comp>, <comp> timeline, Effect
Controls <layer>, Properties: <layer>.
- Default workspace: full-height right column, Preview over Properties.
- engine: time.go nextKey/prevKey accept prop uid; layer.setText supports all
seven justify modes, applyFill/applyStroke and Auto leading (fixes the
Paragraph 'justify' button mapping to Justify All).
- examples/snapshot: render the real UI headless (egui_kittest + wgpu) with
scripted control-channel steps.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>