Commit Graph

803 Commits

Author SHA1 Message Date
bflatastic 8d5e4ae0ef Timeline: a selected key selects its property and layer (#252)
Clicking (or marquee-selecting) keyframes in the Timeline selected only
the keys. Their property and layer stayed unselected, so the Graph
Editor, which shows the selected properties or else the animated
properties of the selected layers, came up empty until the property
was selected separately. As in After Effects, the Timeline's key
selection now selects the keys' properties and layers too (Shift adds
to them). keys.select takes this as `selectProperties`; the Graph
Editor's own key clicks leave what it shows alone.

Test: a_key_clicked_in_the_timeline_shows_in_the_graph_editor
(ui_keyframes).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 16:19:53 +07:00
BFlat 72a2d47131
Merge pull request #249 from storytold/docs/248-py-aep-g4
Docs: gaps.md G4 lists py-aep as a candidate for .aep import (#248)
2026-10-08 14:40:58 +07:00
bflatastic 9fc4407a37 Docs: gaps.md G4 lists py-aep as a candidate for .aep import (#248)
A user suggested py-aep (MIT, Python), which reads and writes .aep
files. G4 now records it for the clean-room decision, with the two
ways it could be used: as an external converter, or ported, which
means reading another implementation of the format.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 14:40:30 +07:00
BFlat 55defcb167
Merge pull request #247 from storytold/fix/243-gl-fallback
App: a launch whose window never drew makes the next use OpenGL (#243)
2026-10-08 13:59:08 +07:00
bflatastic d554724aa4 App: a launch whose window never drew makes the next use OpenGL (#243)
On some older Intel integrated GPUs (UHD 600, UHD with 2020 drivers)
the graphics driver crashes EffectCraft as its window's DirectX 12 or
Vulkan device is created (exit code 0xC0000005): the process
disappears with no message, and only WGPU_BACKEND=gl helped. A driver
crash can't be caught, so each launch now leaves a marker in the
settings folder until its window draws. A launch that finds the
previous one's marker switches the new Settings ▸ Startup & Repair ▸
Window Graphics (Automatic / OpenGL) to OpenGL and says so in the
status bar. A window that fails to open says the next launch will try
OpenGL. WGPU_BACKEND still wins; macOS has no OpenGL backend, so it
never switches there.

Tests: a_launch_that_never_drew_switches_the_next_to_opengl (app),
window_graphics_is_validated (engine). Checked end to end with a
leftover marker: the app opened on OpenGL with the notice and cleared
the marker.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 13:57:21 +07:00
bflatastic fdb655e78e GPU: the compositor declines OpenGL adapters at once (#243)
On OpenGL the compositor translated its compute kernels for tens of
seconds (22 s on an RTX 4090) before one failed validation and it fell
back to CPU compositing, all before the window's first frame. It now
declines GL adapters up front, as it declines adapters without compute
shaders. OpenGL is what Window Graphics falls back to for drivers that
crash with DirectX 12 or Vulkan.

Test: opengl_adapters_get_cpu_compositing_at_once (gpu tests_init;
skips without an OpenGL adapter).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 13:57:08 +07:00
BFlat 4d5765f158
Merge pull request #233 from ulanch/fix-variable-font-axis-test
Fix variable-font animator test axis selection and endpoint delta
2026-10-08 13:38:03 +07:00
BFlat 06aa138c94
Merge pull request #245 from storytold/fix/232-golden-libm-variant
Effects: the sim golden test accepts macOS 27's libm hash for Mr. Mercury (#232)
2026-10-08 13:36:30 +07:00
bflatastic e61f0e5560 Effects: the sim golden test accepts macOS 27's libm hash for Mr. Mercury (#232)
On macOS 27.2 (rustc 1.98) one of the 404 pinned simulation hashes,
CC Mr. Mercury at non-default settings, 32 bpc, t = 2.2 s, came out
different. The reporter rendered every case at the commit that pinned
the hashes and at current main on that machine, and the frames were
byte-identical. So the code didn't change: the platform's libm did
(the hashes are exact f32 bits through sin, cos and powf). The test
now also accepts listed per-case libm variants, with that hash as the
first, and every other case stays exact. Its docs say how to tell a
libm difference from a code change.

Test: libm_variants_are_accepted_for_their_case_only (sim_golden; runs
on every platform).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 13:36:09 +07:00
BFlat f4319c1917
Merge pull request #244 from storytold/fix/234-startup-logging
Logging: RUST_LOG prints to stderr, and start-up logs its milestones (#234)
2026-10-08 13:32:44 +07:00
bflatastic 468ed0b297 Logging: RUST_LOG prints to stderr, and start-up logs its milestones (#234)
The logger kept warnings in memory and wrote to a file only after Help
▸ Enable Logging, and it ignored RUST_LOG. An app that never opens its
window (macOS 27 on Apple Silicon, #234) therefore left no trace. Now
RUST_LOG (a level, or env_logger-style `target=level` directives)
also prints what it lets through to stderr, including eframe, winit
and wgpu. The desktop app logs its start-up milestones: opening the
window, the graphics adapter, the app created, the first frame drawn,
the window being asked to close, and the window closed.

Test: rust_log_filters_by_level_and_target (engine logging). Checked
by running the app with RUST_LOG=info and quitting it over the control
channel.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 13:32:16 +07:00
BFlat 5a7119d5fa
Merge pull request #242 from storytold/docs/gaps-reports-8-oct
Docs: gaps.md records the user reports of 8 October
2026-10-08 13:11:12 +07:00
bflatastic 6a8d339316 Docs: gaps.md records the user reports of 8 October
The reports of 8 October (#225-#227, #229-#231), their fixes (#235,
#237-#241), what remains of #227 (multi-monitor support, the Project
panel's empty-area menu, effect points on shape and text layers) and
the regression tests for each.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 13:10:57 +07:00
BFlat 49af6472bc
Merge pull request #240 from storytold/fix/227-shape-contents
Shapes: draw into, copy, paste and duplicate shape contents (#227)
2026-10-08 13:09:50 +07:00
bflatastic 25c01aa5a0 Docs: gaps.md lists the regression tests for the #227 shape fixes
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 13:03:46 +07:00
bflatastic 89e075d1b1 Shapes: Tools bar Tool Creates Shape / Mask and Fill / Stroke Options (#227)
The Tools bar had Fill and Stroke swatches and a Stroke Width, kept in
the interface only, so agents couldn't set them and new shapes could
only be a solid fill with a solid stroke. As in After Effects:

- With a shape layer selected and a shape tool or the Pen active, Tool
  Creates Shape / Tool Creates Mask choose whether drawing adds shapes
  to the layer or masks on it (Fill and Stroke hide while drawing
  masks).
- Clicking the word "Fill" or "Stroke" opens Fill Options / Stroke
  Options: None, Solid Color, Linear Gradient or Radial Gradient, the
  blend mode and the opacity. The swatches show the kind; Alt-click
  steps through the kinds.
- New shapes and Pen paths are painted with them: a Gradient Fill or
  Gradient Stroke across the shape for the gradient kinds.

The options are engine state (EditorState.shape_tool) set with the new
shape.toolOptions command; shape.newShape and shape.newPath use them
unless given paint parameters (which now include fillType, fillBlend,
fillOpacity and their stroke twins; layer.newShape takes them too). A
Pen path without paint parameters now takes the Tools bar's stroke
(none by default) instead of a fixed 2 px white one. layer.addMask also
draws rounded rectangle, polygon and star masks, so every shape tool
makes a mask on a selected footage or solid layer (rounded rectangles,
polygons and stars made a new shape layer).

Test: shape_tool_options_paint_new_shapes,
masks_of_every_shape_tool_kind,
tool_creates_mask_draws_a_mask_on_the_selected_shape_layer,
fill_options_paint_the_next_shape.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 13:03:38 +07:00
bflatastic 0048569682 Shapes: Duplicate duplicates the selected shape items, not the layer (#227)
Edit > Duplicate (Ctrl+D) with a shape group or other shape item
selected in the Timeline duplicated the whole shape layer. As in After
Effects it now duplicates the selected items inside their group, each
copy above its original and numbered on ("Rectangle 1" gives
"Rectangle 2"), and selects the copies. With only layers selected the
layers are duplicated as before.

Test: duplicate_with_shape_items_selected_duplicates_them_in_place,
ctrl_d_duplicates_the_selected_shape_group_in_its_layer.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 13:03:38 +07:00
bflatastic 95bb346c89 Shapes: Copy, Cut and Paste shape items between shape layers (#227)
Edit > Copy with a shape group (or a path, fill, stroke or path
operation) selected in a shape layer's Contents copied the whole layer,
and Paste made a new layer. As in After Effects, Copy now copies the
selected items, Paste puts them into each selected shape layer's
Contents (above its selected item, in that item's group, else on top,
with names kept unique there: "Rectangle 2"), and Cut removes them, so
Cut + Paste moves them. Pasting with no shape layer selected is an
error rather than a new layer. Copying anything else clears the shape
item clipboard, as it does the other clipboards.

Test: shape_contents_copy_cut_and_paste_between_shape_layers,
ctrl_c_and_ctrl_v_copy_a_shape_group_into_another_shape_layer.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 13:03:38 +07:00
bflatastic 9968950b71 Shapes: drawing with a shape tool adds to the selected shape layer (#227)
With a shape layer selected, the Rectangle, Rounded Rectangle, Ellipse,
Polygon and Star tools made a new shape layer for every shape. After
Effects draws into the selected shape layer instead: the shape becomes a
new group on top of its Contents ("Rectangle 2", ...), placed by the
group's Transform. The new shape.newShape command does that (in the
layer's space, so a moved or scaled layer still gets the shape where it
was drawn), and makes a new shape layer only when no unlocked shape
layer is selected. The viewer's shape tools use it; masks on other
selected layers are unchanged. layer.newShape and the Pen's
shape.newPath share its layer and Contents helpers.

Test: shape_tools_draw_into_the_selected_shape_layer,
shape_tool_draws_into_the_selected_shape_layer.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 13:03:38 +07:00
BFlat 7e4a7cd863
Merge pull request #238 from storytold/fix/227-interface
Spacebar hand tool, Effect Controls menu, New Comp drop, switch drags (#227)
2026-10-08 13:02:49 +07:00
bflatastic 764eee409b Gaps: regression evidence for the #227 interface fixes
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 12:59:40 +07:00
bflatastic c4c28682eb Timeline: dragging over layer switches sets them all (#227)
Each layer switch toggled on its own click only, so hiding or locking
many layers took a click per layer. As in After Effects, pressing a
switch in the A/V Features or Switches column now sets it at once, and
dragging up or down gives the same switch of every layer the pointer
passes the state the first one got, whatever their own state was
(rows passed in a quick drag included). The whole drag is one undo
step: layer.setSwitch takes a `merge` key like other gesture edits.
A single click still changes only that layer, so clicking the eye of
one selected layer doesn't change the others (Layer > Switches still
sets all selected layers).

Test: dragging_over_layer_switches_sets_them_all.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 12:59:40 +07:00
bflatastic 6b95b7a182 Project panel: items dropped on New Composition make a comp (#227)
Dragging Project items onto the Create a new Composition button at the
bottom of the Project panel did nothing. As in After Effects, the
button now takes the drop and runs File > New Comp from Selection with
the dragged items (the selection when the dragged item is in it): one
item becomes a comp of its size, frame rate and duration holding it,
and several open the New Composition from Selection dialog. The button
is outlined while items are dragged over it.

Test: project_items_dropped_on_new_comp_make_a_composition.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 12:59:40 +07:00
bflatastic fab6dedd7c Effect Controls: right-click shows the Effect menu (#227)
Right-clicking the Effect Controls panel did nothing outside an
effect's header. As in After Effects, a right-click anywhere a control
has no menu of its own (the empty area, property names, buttons such
as Reset) now opens the Effect menu: Effect Controls, Last Effect,
Remove All, Manage Effects and every effect category, applying the
chosen effect to the selected layers. It is the menu bar's own Effect
menu tree and drawing code; an effect header keeps its own menu.

Test: right_click_in_effect_controls_shows_the_effect_menu.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 12:59:40 +07:00
bflatastic e008085a93 Spacebar: a tap previews on release, held it is the Hand tool (#227)
Spacebar started or stopped the preview on its press, so holding it to
pan the Composition panel (Space+drag already panned there) also
toggled playback. As in After Effects, plain Spacebar now runs its
shortcut when it is released, and only if no mouse button went down
while it was held and the press didn't go to a text field; key
auto-repeat toggles nothing more. Shift+Spacebar and the numpad
preview shortcuts still run on the press.

Holding Spacebar over the Timeline's ruler and time graph is the Hand
tool there too: dragging scrolls the time graph (when zoomed in, never
before the comp's start or past its end) instead of moving bars, keys
or markers.

Test: spacebar_taps_preview_and_held_spacebar_pans_the_viewer,
spacebar_drag_scrolls_the_time_graph.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 12:59:40 +07:00
BFlat e1062ab81b
Merge pull request #241 from storytold/feat/229-system-language
Settings: Language ▸ Match System follows the system language (#229)
2026-10-08 12:58:55 +07:00
bflatastic fd572949f3 Settings: Language ▸ Match System follows the system language (#229)
The interface language was English unless Japanese was chosen in
Settings ▸ General ▸ Language. Language now has a Match System choice
(`general.language` = `system`), the new default: the operating
system's interface language where EffectCraft has a translation
(Japanese), else English, as After Effects installs in the system's
language. English and Japanese can still be chosen; a language chosen
before stays. The browser build stays in English with Match System,
since it has no Japanese font of its own.

The system language comes from sys-locale (MIT OR Apache-2.0, no
dependencies on the desktop platforms), on desktop builds only.

Tests: match_system_uses_the_system_language_where_there_is_a_catalog
(i18n), interface_language_is_validated_persisted_and_backward_compatible
(engine).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 12:58:11 +07:00
BFlat bb3e63e8f3
Merge pull request #239 from storytold/fix/230-viewer-selected-layer-first
Viewer: a press on a selected layer behind others acts on it (#230)
2026-10-08 12:50:11 +07:00
bflatastic 2c7eca7ef2 Viewer: a press on a selected layer behind others acts on it (#230)
A press in the Composition panel always acted on the topmost layer
under the pointer, so a selected layer could not be dragged where
another layer covered it: the press selected the layer in front. As in
After Effects, a selected layer under the pointer now comes first: it
stays selected and a drag moves it. With no selected layer there the
topmost layer is picked as before, and Shift still toggles the topmost
one. The context menu's list of layers under the pointer shares the
same hit test.

Test: viewer_press_prefers_a_selected_layer_under_the_pointer
(ui_viewer).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 12:47:30 +07:00
BFlat 5d1b818fa1
Merge pull request #237 from storytold/fix/225-226-231-web
Web: short Project panel, unreadable picked files, lost graphics device (#231, #226, #225)
2026-10-08 12:46:13 +07:00
bflatastic db3b34b134 Web: a lost graphics device says so and offers a reload (#225)
When the page's WebGPU device was lost, the canvas kept showing its
last frame: edits still went through and rendered frames were right,
but the editor never showed them and nothing said why (the status
message about it is drawn in the canvas that can't present any more).
The page now covers the canvas with a notice that offers Save Project
(a download) and Reload. Reload first writes pending changes to
browser storage, so the session snapshot brings the project and its
unsaved changes back; if that write fails it says so and offers
Reload Anyway. Without a kept session (?empty, memory storage) the
notice says to save first.

Test: apps/effectcraft-web/tests/page.mjs (Node, fake DOM).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 12:38:11 +07:00
bflatastic 82a1862fa1 Web: Media Browser reports a picked file it can't read (#226)
Add Files... and Upload Folder... read every picked file in one go and
rejected on the first file the browser couldn't read; the Media
Browser dropped that rejection, so nothing was added and nothing said
why. Each file is now read on its own: the readable ones are added and
the status bar names the unreadable ones with the browser's reason and
suggests picking them again. Cancelling the picker is not reported.

Test: apps/effectcraft-web/tests/page.mjs (Node, fake DOM).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 12:38:11 +07:00
bflatastic 7612b220ef Project panel: a panel too short for the scroll bar draws (#231)
The Project panel's vertical scroll bar clamped its thumb between 16
points and the track's height. When the track was shorter than 16
points (an empty project in a 1280 x 800 browser window at device pixel
ratio 2, or any short panel), that clamp panicked on the first frame:
the browser canvas went blank and the app stopped responding. The
thumb is now at most the track's length, and both scroll bars share
the calculation.

Test: a_short_project_panel_draws (ui_project_rows).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 12:38:10 +07:00
BFlat 543bff29dc
Merge pull request #235 from storytold/fix/227-turbulent-displace
Effects: Turbulent Displace displaces the whole layer, not one quadrant (#227)
2026-10-08 12:36:29 +07:00
bflatastic 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
Alex Ulanch d506a80639 Fix variable-font animator test axis and endpoint selection 2026-10-07 21:38:19 -07:00
Brandon Thomas 172b7cfcc0 Release CI: macOS job on macos-15-xlarge
Custom macOS larger runners in a runner group do not pick up jobs; the
built-in M2 Pro label does. Only release.yml uses it, and the
actions_macos_xl budget caps the monthly spend.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-07 22:08:03 -04:00
Brandon Thomas 904c0671b1 Release CI: macOS job on the org macos-release runner
The standard macOS runners are shared with all CI and queue for an hour or
more. The macos-release runner (GitHub-hosted M2 Pro) is in a runner group
usable only by release.yml on the release branch, with a monthly spend cap
on the actions_macos_xl SKU.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-07 21:54:58 -04:00
Brandon Thomas ab5ebfbae1
About: contributor and model credits compiled in (grab bag + table, self-submitted names) (#228)
* About: contributors compiled in from contributors.json (grab bag + table, sortable, name toggle)

About EffectCraft now has tabs About · Contributors · Models, following the craftrules standard
(standards/contributors.md): contributors/contributors.json is generated by
craftrules/scripts/contributors.py and baked into the binary by crates/ui-egui/build.rs as static
tables. Each contributor line: @username, opt-in display/real name, PRs, commits, lines +/−/Δ,
binary assets +/−, first/last commit. Sortable by every column; alphabetical ignores case and
the leading @. Every control registers an automation id (about.tab.*, about.credits.*).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Contributors: self-submitted names in contributors/people.toml; AGENTS.md credit-yourself section

build.rs reads contributors/people.toml next to the generated contributors.json and shows a name only
for entries the generator verified as written by that person (craftrules standards/contributors.md).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Contributors: regenerate (verified people.toml entries)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-07 21:16:47 -04:00
BFlat e38a92e792
Merge pull request #224 from storytold/fix/215-216-218-web-workers
Web: replaced files reach reused workers, failed worker starts fail their job, failed storage writes retry (#215, #216, #218)
2026-10-08 05:33:59 +07:00
Claude 1ca78821b9
Web: a failed storage write is retried and flush() rejects (#215)
A write to browser storage that failed (quota exceeded) was dropped:
effectcraft.flush() resolved anyway, nothing retried it, and a reload
restored the project from before the change. The failed key now stays
pending and is written again after 2 s (doubling to a minute while it
keeps failing; a newer change of the key goes with it), and flush()
rejects with the error.

Test: failed_writes_retry (store). The flush itself runs only in the
browser.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018gnTnH3Jmk5zr4tMq1Mc9f
2026-10-07 22:33:04 +00:00
Claude 72b935fe26
Web: a job worker that fails to start fails its job (#216)
worker.js left a rejected start (its async init) unhandled, which a
page's Worker error event doesn't see: the page waited for "ready"
forever and the render stayed pending until cancelled. The failed start
is now re-raised where the page's onerror sees it, like the other
worker failures; the job fails with the error and the worker is
terminated.

Test: apps/effectcraft-web/tests/workers.mjs (worker.js with a stub
module whose init rejects; host.js with a worker whose start fails).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018gnTnH3Jmk5zr4tMq1Mc9f
2026-10-07 22:33:04 +00:00
Claude a2f22bb35b
Web: a replaced file goes to reused workers again, even at the same size (#218)
Job workers remembered the files they were sent by path and byte
length, so footage replaced by different bytes of the same length at
the same path was never resent: a Render Queue export through a reused
worker rendered the old image while the page showed the new one.
Frame workers remembered paths only, so they never got a replacement
at all.

Every write of a stored file now gets a version, and both kinds of
worker remember the version they were sent.

Tests: versions_change_with_every_write (store) and
apps/effectcraft-web/tests/workers.mjs (Node, fake Worker: the
replacement is sent once, an unchanged file not again).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018gnTnH3Jmk5zr4tMq1Mc9f
2026-10-07 22:33:04 +00:00
BFlat da6cb73142
Merge pull request #223 from storytold/docs/gaps-reports-7-oct
Docs: gaps.md records the user reports of 7 October
2026-10-08 05:17:25 +07:00
Claude 603a9bfdb4
Docs: gaps.md records the user reports of 7 October
#198, #201, #203–#206, #208, #209 and #212, with their regression tests.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018gnTnH3Jmk5zr4tMq1Mc9f
2026-10-07 22:17:13 +00:00
BFlat 2d40171789
Merge pull request #222 from storytold/fix/212-puppet-input-cache
Puppet: dragging pins keeps the layer under the Puppet cached (#212)
2026-10-08 05:17:06 +07:00
BFlat ff163d42a0
Merge pull request #221 from storytold/fix/203-205-206-timeline-shapes
Timeline, shapes and masks: Add menu, Change Renderer, toolbar Fill / Stroke, Alt+Shift+P reveal, mask selection, linked feather, Project selection box (#203, #205, #206)
2026-10-08 05:16:48 +07:00
BFlat 0e6d37061a
Merge pull request #220 from storytold/fix/198-201-204-app-startup
App: starts with an empty project, opens on older GPUs, shows comps wider than the texture limit (#198, #201, #204)
2026-10-08 05:16:25 +07:00
BFlat a3468f6781
Merge pull request #219 from storytold/fix/208-209-audio-preview
Preview: audio visualisers follow time in the viewer; sound starts once rendering keeps up (#208, #209)
2026-10-08 05:16:00 +07:00
Claude a831d12975
Puppet: dragging pins keeps the layer under the Puppet cached (#212)
Every pin move re-rendered the Puppet's input (source, masks and the
effects before it) at full size on the UI thread and deep-copied it
for the mesh overlay: the cache key of a layer's input hashed all of
its effects, so moving a pin of the Puppet changed the key of its own
input. The input key now covers only the effects that run before the
Puppet, and the overlay shares the cached buffer.

Test: input_keys_ignore_later_effects.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018gnTnH3Jmk5zr4tMq1Mc9f
2026-10-07 22:13:19 +00:00