Commit Graph
951 Commits
Author SHA1 Message Date
bflatasticandClaude Opus 5.5 da165724e9 Plug-ins: Ease Presets moves out of core into a bundled ScriptUI panel
The Ease Presets panel (#254) is modelled on a third-party panel, so,
as with third-party tools in After Effects, it isn't core any more: it
is `extensions/scriptui-panels/Ease Presets.jsx`, a ScriptUI panel
bundled as an optional extension (Window ▸ Ease Presets.jsx), written
only against the public scripting API. Clicking a preset eases every
pair of neighbouring selected keyframes in one undo step (per
dimension, along the motion path for spatial properties, the keys'
other sides as they play); the fields edit the working curve, which the
panel draws; From Keys, Save, Rename and Delete as before. The twelve
built-in curves are unchanged.

Scripting API fixes it needed (After Effects parity):
- `app.settings` lasts between runs (`script_settings.json` in the
  settings folder; `script.settings.get` / `script.settings.save`).
- Per-key methods (`setTemporalEaseAtKey`, `setInterpolationTypeAtKey`,
  `removeKey`, the continuous / auto-Bezier / roving setters) no longer
  change the user's key selection (they selected the key they edited).
- `keyInTemporalEase` / `keyOutTemporalEase` report linear and
  auto-Bezier sides as they play, `keyIn/OutSpatialTangent` the
  tangents the motion path plays.
- `selectedProperties` includes the properties of selected keyframes.
- `isInterpolationTypeValid` is false for Linear / Bezier on values that
  only hold.

Removed from core: Window ▸ Ease Presets, the `keys.easePreset.*`
commands, `engine::ease_presets` and the `ease_presets.json` store,
`keyframe::EaseCurve` (nothing else used it) and the egui panel. User
presets saved by the v0.6.0 panel move into the panel's app.settings
section the first time settings load (the old file is left as is).
Docs: plugins.md (bundled extensions), parity.md, gaps.md G8, agents.md.

Test: app_settings_last_between_runs,
per_key_methods_keep_the_key_selection_and_report_eases_as_they_play,
spatial_tangents_are_reported_as_the_path_plays (each fails before),
the_ease_presets_panel_eases_every_selected_pair_in_one_undo_step,
a_typed_curve_scales_to_each_dimension_and_follows_motion_paths,
user_presets_save_rename_delete_and_persist,
presets_saved_by_the_old_core_panel_carry_over (script, through the
panel's controls), ease_presets_panel_eases_the_selected_keys_from_its_list
(UI: the panel docks and a click on a preset eases the keys).

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-09 21:03:12 +07:00
bflatasticandClaude Opus 5.5 9da33c157e Plug-ins: ScriptUI Panels folder scripts dock as panels and reopen, as in After Effects
EffectCraft's extension points compared with After Effects' (public
user guide and Scripting Guide) are now in docs/plugins.md, which
becomes "Plug-ins and extensions": scripts, ScriptUI panels and effect
plug-ins, with a short guide and an example panel for writing your own.

ScriptUI panels already came from `Scripts/ScriptUI Panels/` in the
settings folder, were listed at the bottom of the Window menu and
docked as tabs. What was missing: After Effects reopens the panels
that were open when it quit. Now the open panels are remembered in
`scriptui_panels.json` in the settings folder (a panel is added when
it opens and dropped when its tab or its script closes it; quitting
leaves the list), and `window.restoreScriptPanels` opens them again;
the desktop and web apps run it at start-up. A panel whose script is
gone or fails is reported and forgotten, and the others still open.
Where a panel was docked isn't kept, as workspace layouts aren't saved
between launches.

Gaps recorded in plugins.md and gaps.md G8: the Startup and Shutdown
script folders, keyboard shortcuts for scripts, ExtendScript's
`#include` / `#target` directives and `.jsxbin`.

Test: open_panels_open_again_at_the_next_launch (fails before: no
restore command), a_panel_dropped_in_the_folder_is_listed_and_opens_as_a_panel
(script), panels_open_at_quit_dock_again_at_launch (UI: the restored
panel docks with its controls; closing the tab forgets it).

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-09 21:03:12 +07:00
bflatasticandClaude Opus 5.5 6ce58040fd Viewer: the Snapping menu has After Effects' two options
The Tools bar's Snapping options menu (#265) offered per-feature
toggles (Edges, Corners, Centers, Anchor Points, Mask and Shape Path
Points) that After Effects' Snapping menu doesn't have. It now has the
two After Effects has:

- Snap Edges Extended (as before).
- Snap to Features in Collapsed Compositions and Text Layers: the
  visible layers inside a precomp layer with Collapse Transformations
  on are snap targets too, mapped into the outer comp (points always,
  edge lines while the precomp layer is unrotated); a snap highlights
  the precomp layer. Nested collapsed precomps are followed eight deep.

Every layer feature snaps again (corners, edge midpoints, centre,
anchor point, mask and shape path points); the snapping engine itself
is unchanged. `view.snappingOptions` takes `edgesExtended` and
`collapsedFeatures` (and `toggle` of either); the old keys are refused.

Test: collapsed_precomp_features_snap (fails before: no such option),
snapping_options_command_sets_and_toggles (the per-feature keys are
refused), snapping_options_pick_the_targets (AE behaviour kept: edges
extended or not, hidden layers, guides only), and the Snapping menu UI
test (only the two options are listed).

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-09 21:03:12 +07:00
BFlat b9d1f79f7d Merge pull request #422 from storytold/fix/297-start-timecode
Import: Interpret Footage has Start Timecode, as in After Effects (#297)
2026-10-09 21:02:18 +07:00
bflatasticandClaude Opus 5.5 a34aecd719 Import: Interpret Footage has Start Timecode, as in After Effects (#297)
After Effects' Interpret Footage has Start Timecode: Use Source File
Timecode, or Override Start, which changes the timecode the footage
shows and leaves its frames alone. The Start Frame field that trimmed or
padded a sequence's head isn't in After Effects, so it is replaced.

Footage.start_timecode (Override Start, in frames at the footage's
rate; None = Use Source, 0 as file timecode isn't read) relabels source
time: the Footage panel's current time and footage.info's `timecode`
count from it. file.interpretFootage takes `overrideStart` and
`startTimecode` (timecode, read at the footage's rate after any frame
rate change, or a frame number, 0 to 1e9). It applies to every footage
with time, not only sequences, and Reload keeps it. A sequence's frames
always run from its first file's number to its last.

Test: start_timecode_only_relabels_source_time (project),
interpret_footage_start_timecode_relabels_source_time (engine: the
reply, the Footage panel's timecode, frame numbers, Use Source, the
footage's rate, bad values, undo), Reload keeps it, and the Interpret
Footage fields in ui_drag_drop.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-09 20:50:39 +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
Brandon Thomas 2c199d55f8 Merge pull request #384 from storytold/feat/297-image-sequences
Import: image sequences with a Sequence option, ranges, folders and missing frames (#297)

# Conflicts:
#	docs/parity.md
2026-10-09 09:31:51 -04:00
Brandon Thomas 14417c0400 Merge pull request #354 from thanhcong2k7/fix/ui-dock-focus-outline-zorder
UI: Draw panel focus outline after panel body to prevent clipping
2026-10-09 09:31:43 -04:00
Brandon Thomas 3d1b87f0d4 Merge pull request #345 from thanhcong2k7/fix/ui-commit-text-on-tool-switch
UI: Commit text edit session when switching away from Type tool
2026-10-09 09:31:42 -04:00
Brandon Thomas e52ff9ab95 Merge pull request #342 from HEOJUNFO/fix-313-single-pin-jump
Puppet: the first pin no longer turns the layer about it (#313)
2026-10-09 09:31:41 -04:00
Brandon Thomas d5beb4b3c4 Merge pull request #344 from MindlessRuff/fix/exr-over-range
fix(export): keep values above 1.0 in EXR output (#339)
2026-10-09 09:31:40 -04:00
Brandon Thomas f87f3b3e1a Merge pull request #357 from HEOJUNFO/fix-317-aiff-float
Export: AIFF 32-bit float writes AIFF-C fl32 instead of 24-bit (#317)
2026-10-09 09:31:38 -04:00
Brandon Thomas b6ba84d828 Merge pull request #353 from cjcwwww/i18n/zh-hans-terminology
i18n: match the Simplified Chinese labels to the installed 26.5.0 UI
2026-10-09 09:28:40 -04:00
Brandon Thomas a990432962 Merge pull request #312 from FeiLiuEM/font/cjk-locale
text, ui: the CJK fallback fonts follow the interface language
2026-10-09 09:28:38 -04:00
Brandon Thomas 64d1965648 Merge pull request #319 from thanhcong2k7/main
fix: rewrite Audio Spectrum to match After Effects linear frequency/amplitude model
2026-10-09 09:28:36 -04:00
Brandon ThomasandClaude Opus 5.5 3df56ce9d9 MCP: describe_command and execute_command accept id again (#365 follow-up)
#365 rejects arguments missing from a tool's schema; both tools read `id`
as an alias of `command`, so declare it.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-09 09:25:25 -04:00
Brandon Thomas 7b41793ab4 Merge pull request #365 from storybored379/feat/mcp-conventions
MCP: core tools, resources, render progress and cancellation
2026-10-09 09:25:25 -04:00
Brandon Thomas 754e998989 Merge pull request #374 from storytold/fix/368-tflite-budgets
Fix #368: tflite rejects models whose scratch or work exceeds a budget
2026-10-09 09:25:24 -04:00
Brandon Thomas a3cfc3e014 Merge pull request #388 from KazW/fix/mediapipe-crop-sampling
segment: sample crops like MediaPipe's ImageToTensor; no overflow in crop
2026-10-09 09:25:23 -04:00
Brandon Thomas d3684216e4 Merge pull request #373 from storytold/fix/367-nms-degenerate
Fix #367: weighted_nms terminates on NaN or zero-area boxes
2026-10-09 09:25:22 -04:00
Brandon Thomas 68d94b8031 Merge pull request #281 from XusBadia/dmg-background
macOS DMG: branded window background and icon layout
2026-10-09 09:20:44 -04:00
WaWu 1eecb40a6a i18n: match the Simplified Chinese labels to the installed 26.5.0 UI
Checked every submenu of Adobe After Effects 26.5.0 (Build 89), Simplified Chinese, against
the catalog and took the wording the application shows. 81 of the 618 labels change; keys,
order, count and the Traditional Chinese catalog are untouched.

Three groups:

- 61 labels where #309 and this branch disagreed and the application matches this branch -
  including the five blend modes whose Chinese names differ between After Effects and
  Photoshop (屏幕, 发光度, 较深的颜色, 较浅的颜色, 纯色混合), 导入参考... / 导出参考...
  (the application omits the 线), and 类型... for the Type settings page.
- 11 labels where both catalogs were wrong and this takes the application's wording:
  向基本图形添加属性, 移除所有的文本动画器, 显示关键帧的属性, 显示动画的属性,
  将合成裁剪到工作区, 裁切合成至选定图层边界, 基于 3D 视图生成摄像机,
  创建立体 3D 设备, 使用摄像机控制光线, 使用显示色彩管理, 淡灰色.
- 9 labels of spelling and punctuation: 沿路径进行空值追踪 (a stray '1'), 启用逐字 3D 化,
  裁剪合成到目标区域, 中灰(默认) with full-width parentheses.

Left for the maintainers: Material (the application says 素材, but it also calls Footage 素材),
the 导出 prefix on the Premiere export row (the application repeats it but drops 'Pro'), and the
verb in Reset 3D View (the application is inconsistent between 重设 and 重置).
2026-10-09 21:20:41 +08:00
FeiLiuEM 5344f304c3 text, ui: borrow the app at the test call sites, and drop a redundant lifetime
Two things are one level deeper than the first pass at this review:

- Nine of the call sites that pass the resolved language are inside test functions, where `app`
  is owned, so `crate::i18n::language(app)` needs `&app`. `cargo check --all-targets` (which
  compiles the test modules as well) is what reported them; a check without it does not, which is
  how they survived the first round.
- `clippy -D warnings` rejects the explicit `'static` on `const KANA` / `const HAN`: a const
  already has one.

On this branch `cargo fmt --all --check`, `cargo check -p effectcraft-ui-egui --all-targets`,
`cargo clippy -p effectcraft-ui-egui --all-targets -- -D warnings` and
`cargo test -p effectcraft-ui-egui` (40 targets, 113 lib tests) are clean.
2026-10-09 20:34:03 +08:00
Brandon ThomasandClaude Opus 5.5 29c4d3ad15 Revert #200 (text always continuously rasterised): breaks kinetic_typography
The QA test's time-remapped precomp no longer matches the precomp rendered
directly (crates/automation/tests/qa/kinetic.rs:78); FreeBSD CI has been red
since. Reverting until the PR is reworked against that test.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-09 08:22:58 -04:00
bflatasticandClaude Opus 5.5 efd348335f Import: missing sequence frames show a placeholder, as in After Effects (#297)
After Effects shows a missing frame of an image sequence as a
placeholder (colour bars) and has no Hold Previous Frame or Skip choice
in Interpret Footage, so EffectCraft doesn't either.

Interpret Footage loses its Missing Frames field, file.interpretFootage
its missingFrames parameter, and Footage its missing_frames setting. A
gap in a numbered sequence's numbering always shows colour bars. A
sequence imported with Force Alphabetical Order still plays its files
one after another (its numbering doesn't count), as in After Effects;
that is now an internal Footage.alphabetical flag, set on import and
kept by Reload. The Interpret Footage note lists the missing frames.

Projects saved before this have no such field and open with the After
Effects behaviour: a sequence with gaps shows placeholders where it
used to close them up.

Test: project sequence unit tests (placeholders, alphabetical order,
projects saved without the flag), tests_sequence (Start Frame instead
of Hold / Skip), sequence_gaps_show_placeholders (media) and the
Interpret Footage fields in ui_drag_drop.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-09 18:52:19 +07:00
BFlat d5f78f3fc0 Merge pull request #391 from storytold/fix/279-275-284-ui
Menu-bar keyboard, comp marker bin, UI Scale and Settings scroll (#279, #275, #284)
2026-10-09 18:44:55 +07:00
bflatasticandClaude Opus 5.5 65d2c34e54 Menus: the Project panel's footage menu passes the keyboard navigator (#279, #290)
The footage item's context menu from #383 builds its entries with
menu_nodes, which #391 gave the menu bar's keyboard navigator and
depth; like the other context menus it passes a fresh one.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-09 18:38:39 +07:00
bflatasticandClaude Opus 5.5 7a9c459e42 Settings: Appearance > UI Scale sizes the whole interface (#284)
Settings > Appearance > UI Scale (appearance.uiScale, 75-200 %, default 100)
scales the whole interface on top of the display's own scaling, live as it is
chosen; Cancel puts it back, OK saves it and a saved scale applies from the
first frame. The Settings dialog's choice rows show a number setting with
choices as its text. Automation id: settings.appearance.uiScale.

egui's own Ctrl+= / Ctrl+- / Ctrl+0 zoom is off now: Ctrl+0 (Window > Project)
also reset the zoom behind the app's back, and the scale is a setting.

Test: engine tests_settings ui_scale_is_a_percentage_from_75_to_200; ui_panels
ui_scale_setting_sizes_the_interface.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-09 18:34:27 +07:00
bflatasticandClaude Opus 5.5 8e4d9988af Settings: the dialog no longer scrolls sideways (#284)
The page column had a fixed 590 pt width, a few points more than the dialog had
beside the page list, so the whole Settings dialog scrolled sideways a little.
It takes the rest of the dialog's width now.

Test: ui_scrolling settings_dialog_does_not_scroll_sideways.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-09 18:34:27 +07:00
bflatasticandClaude Opus 5.5 7056801eb2 Timeline: the composition marker bin adds comp markers where they are dropped (#275)
As in After Effects, the right end of the Timeline's time ruler has a
composition marker bin (an original icon drawn in code). Dragging out of it
shows a marker following the pointer along the ruler's marker strip, snapping
like a dragged marker (current time, work area, other markers); releasing over
the time ruler's width adds a composition marker there with comp.addMarker (one
"Add Marker" undo step). Dropped back on the bin, nothing is added. The time
graph ends 18 px before the panel edge to leave the bin a column above the
layers' scroll bar. Automation id: timeline.markerBin.

Numpad * (or * typed with Shift+8), the keymap's Add Marker, now works in the
window too: egui has no key for it, so it comes as text.

The marker glyph and colour are shared helpers now (markers, nested markers,
the dragged marker).

Test: ui_timeline_zoom dragging_out_of_the_marker_bin_adds_a_comp_marker.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-09 18:34:27 +07:00
bflatasticandClaude Opus 5.5 6bb9bd8dab Menus: arrow keys and Enter drive the menu bar; shortcuts wait while a menu is open (#279)
The in-window menu bar now works from the keyboard as After Effects' does on
Windows: Alt pressed and released on its own focuses the bar, Left / Right move
between its menus and Down, Enter or Space opens one. In an open menu Up / Down
move the highlight (skipping disabled entries, wrapping around), Right opens the
highlighted submenu and Left closes it (on a plain entry they open the next /
previous menu), Enter or Space chooses the entry and Escape closes the menus.
Hovering an entry moves the highlight there, and a highlighted entry scrolls
into view in long menus.

While a menu, context menu or popup list is open, or the bar has the keyboard,
keys go to the menus only: the app's shortcuts don't run (Space started the
preview behind an open menu) and the panels don't see the keys (Enter on an
entry no longer reaches the Project panel's rename).

Tall menus already scroll inside the window since #277 (ui_scrolling's
a_menu_taller_than_the_window_scrolls). F10 stays View > Switch 3D View > Front,
as in After Effects.

Test: ui_menus (shortcuts_wait_while_a_menu_is_open,
arrow_keys_drive_the_menu_bar, enter_chooses_the_highlighted_entry).

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-09 18:34:27 +07:00
FeiLiuEM ad3da3c8de text, ui: follow a language change, and resolve the language before the fonts
Review follow-ups on #312:

- `crates/ui-egui/src/theme.rs`'s `japanese_font_tests` still called `install` with two
  arguments, so `cargo test` did not compile. Every call site now passes a language.
- The call sites passed the stored `general.language` preference. With the default `system`
  that is `""`, which handed the CJK choice back to the environment locale — one macOS and
  Windows usually do not set. They now pass `crate::i18n::language(app)`, the resolved
  language, so Match System draws Chinese on a Chinese system.
- Changing Settings ▸ General ▸ Language only reached the fonts on the first frame.
  `EffectcraftApp` now remembers the language its fonts were installed for and installs them
  again when it changes, so the switch applies without a restart.
- Documented that `fonts::set_cjk_locale` is process-global: the Han preference therefore
  applies to composition text as well as the interface chrome (docs/preferences.md and the
  function's own comment).

Rebased onto main after #309 landed — `header.rs` gained an `install` call site in the
meantime, and the catalogs now resolve through `i18n::language`.
2026-10-09 19:28:42 +08:00
FeiLiuEM a4d1e8d0b3 text, ui: the CJK fallback fonts follow the interface language
- `effectcraft_text::fonts::set_cjk_locale` lets the host say whose face should draw Han
  ideographs instead of leaving it to the locale environment, and drops the fallback cache when
  it changes. `han_order` reads that request first; the tag → order rule moves into the pure
  `han_order_for`, so it can be tested without touching process state.
- `theme::install` now takes the stored `general.language` value and registers one CJK system
  fallback per script in every font family, the interface's own script first: kana for Japanese,
  a Han character for `zh-hans` / `zh-hant`, then the other script so names in it still render.
  A face is registered at most once, and a machine with no CJK font installs nothing (the web
  build installs nothing, as before).
- Before this the probe was always `あ`, so Han text was drawn by the Japanese face whenever the
  operating system's locale was not Chinese: a Chinese interface, and Chinese file, layer or
  template names on any locale, both got Japanese glyph forms.
- Tests: the tag → order rule (`zh`, `zh_Hans`, `zh-Hant-TW`, `ko`, `ja`, `en`, empty), and the
  registration order plus once-only registration for a Chinese, a Japanese and an English
  interface.
2026-10-09 19:27:47 +08:00
bflatasticandClaude Opus 5.5 50c9549529 Import: image sequences with a Sequence option, ranges, folders and missing frames (#297)
Image sequences were found only by the desktop media prober: one picked
numbered still brought its whole run, with no way to import just that
frame, picking every frame made one sequence item per frame, the browser
couldn't make sequences at all, and a gap in the numbering closed up
silently.

The engine now groups numbered stills itself (engine/src/sequence.rs):
one picked file brings its run from its folder, several picked files of
one run import as that range, a picked or dropped folder imports its
files with each run as a sequence, and Force Alphabetical Order takes
every image of that type in the folder by name. `file.import` takes
`sequence` (default on), `alphabetical` and `frameRate`; Replace Footage,
Reload, proxies and render outputs probe the same way. The media layer
probes one file; the browser lists its file table for the run and
registers every frame with its media pool.

File > Import > File... asks, like After Effects' "PNG Sequence"
checkbox, whether picked numbered stills import as a sequence, with
Force Alphabetical Order and the frame rate. Sequences are named
`shot_[0001-0250].png`.

Interpret Footage gains Missing Frames (Show Placeholder, colour bars as
in After Effects, the new default; Hold Previous Frame; Skip) and Start
Frame (the frame number at the footage's first frame: trims or pads the
head). Saved projects keep Skip, so their sequences play as before.

Form notes keep a readable width and the form fits its rows, so OK stays
in view. docs/footage.md explains importing footage and sequences.

Test: tests_sequence (engine: run, picked range, every frame, Sequence
off, folder, alphabetical, Interpret Footage Missing Frames / Start
Frame, Replace Footage and Reload), project sequence unit tests,
sequence_gaps_show_placeholders_hold_or_close_up (media),
import_dialog_offers_the_image_sequence_option and
dropped_frames_import_as_one_sequence_with_sequence_interpretation (UI).

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-09 18:00:07 +07:00
BFlat 4aaadd0ed3 Merge pull request #387 from storytold/fix/295-extractor-layers
Effects: EXtractoR picks layers and channels of multi-layer EXRs (#295)
2026-10-09 17:58:37 +07:00
Kaz WalkerandClaude Opus 5.5 5304437629 segment: sample crops like MediaPipe's ImageToTensor; no overflow in crop (#385, #386)
Fixes #385, Fixes #386.

crop now maps the square's corners to the output corners, reads the source position as a
pixel-centre index, rounds to a whole 0-255 value, and takes a Border (Zero for the detector,
Replicate for the mesh), matching MediaPipe's CPU ImageToTensor. The frame size product is
checked, so an absurd size gives an lo-filled tensor instead of an overflow panic.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-09 04:38:07 -06:00
bflatasticandClaude Opus 5.5 27cabcb36b Effects: EXtractoR picks layers and channels of multi-layer EXRs (#295)
EXtractoR's Red, Green, Blue and Alpha are text parameters naming
channels, and Effect Controls drew nothing for text parameters: there
was no way to choose a layer or channel. And a multi-layer OpenEXR file
whose colour is only in named layers (`diffuse.R`, Blender's
`ViewLayer.Combined.R`) didn't import at all: the image decoder wants an
unnamed RGB layer ("does not contain non-deep rgb channels").

- Effect Controls: EXtractoR gets a Layer popup listing the footage's
  OpenEXR layers. Picking one sets red, green, blue and alpha to its
  channels in one undo step, as After Effects' EXtractoR dialog does (a
  one-channel layer such as depth goes in all three colours). Red /
  Green / Blue / Alpha are popups of the layer's own R, G, B, A, every
  channel of the file, and (none). The lists are read only while open,
  so playing an EXR sequence doesn't parse files on the UI thread.
- `layer.channels {layer}` lists a layer's EXR layers and channels and
  what each layer shows in red, green, blue and alpha, for agents.
- Media: an EXR without an unnamed RGB layer imports and shows its
  colour layer (one named combined, beauty or rgba first); its channels
  stay available to EXtractoR and the 3D Channel effects.
- Raster: AuxChannels::layers / layer_rgba and split_channel.

Test: extractor_shows_the_chosen_layer_and_channels_of_a_layered_exr
(host: a layered EXR written with the exr crate imports, layer.channels,
EXtractoR renders spec and depth; it failed to import before),
extractor_offers_the_exr_layers_and_channels (UI: Layer popup, one undo
step, channel popup), layered_exr_without_an_unnamed_rgb_layer_imports
(media).

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-09 17:32:09 +07:00
BFlat a6c72acf94 Merge pull request #383 from storytold/fix/290-tweaks
Tweaks from #290: label colours, nudging, motion-path handles, Time Remap, masks, context menus
2026-10-09 17:28:27 +07:00
bflatasticandClaude Opus 5.5 a8bf9a5b88 Docs: gaps.md records the #290 fixes
Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-09 17:21:13 +07:00
bflatasticandClaude Opus 5.5 1afeb9d5c6 Timeline: right-clicking the work area offers Trim Comp to Work Area, Lift and Extract (#290)
The work area bar had no context menu. Right-clicking it now offers the
work area's commands from the menu bar: Trim Comp to Work Area, Lift
Work Area and Extract Work Area (After Effects).

Test: work_area_context_menu_trims_the_comp (ui_timeline_zoom).

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-09 17:21:13 +07:00
bflatasticandClaude Opus 5.5 0f44588bbd Project panel: footage items' menu has Interpret Footage, Replace and Reload Footage (#290)
Right-clicking imported footage offered no way to change its
interpretation. As in After Effects, right-clicking an item now selects
it, and footage items' menu has the File menu's footage commands:
Interpret Footage (Main, Proxy, Remember / Apply Interpretation),
Replace Footage, Reload Footage and Reveal in Explorer / Finder, with
the menu bar's labels, shortcuts and enabled state
(menus::submenu_at / entry_for). The panel's Interpret Footage button,
which only ever said to select footage, opens the dialog for selected
footage.

Test: footage_context_menu_interprets_the_footage (ui_project_rows).

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-09 17:21:13 +07:00
bflatasticandClaude Opus 5.5 2f3a507f8e Labels: label menus show each label's colour (#290)
The label menus listed the labels' names only, so a label couldn't be
picked by its colour. Every place a label is chosen now shows its
colour swatch before its name, as After Effects does: the Timeline's
label swatch (which now opens its menu on a click too, not only a
right-click), the Project panel's label swatch and a new Label submenu
in its item menu, Edit > Label, keyframe Label menus and the marker
dialog. One shared widget (widgets::label_entry / label_popup) draws
them; keyframe labels now show the names set in Settings > Labels.

Tests: label_swatch_opens_the_label_menu (ui_project_rows),
the_label_swatch_menu_shows_the_label_colours (ui_timeline_switches),
edit_label_menu_shows_the_label_colours (ui_panels).

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-09 17:21:12 +07:00
bflatasticandClaude Opus 5.5 3174652ce4 Viewer: double-clicking a mask point selects the whole mask (#290)
Double-clicking a mask or shape path's point (or segment) put its points
in a free-transform box but left only the clicked point selected, so
once the box was gone a drag moved that one point. As in After Effects,
the double-click now selects all the path's points too: dragging inside
the box, or afterwards any of the points, moves the whole mask.

The test also draws a mask with the Pen, moves a point and undoes: each
undo takes back one action (the move, the closing, the last point).

Test: pen_mask_undoes_step_by_step_and_double_click_moves_the_whole_mask
(ui_viewer).

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-09 17:20:43 +07:00
bflatasticandClaude Opus 5.5 ed5ad56eb5 Viewer: a straight motion path has Bezier handles to curve it (#290)
The Position motion path drew a key's spatial handles only where its
tangent wasn't zero, and auto-Bezier keys have none at the path's ends,
so a two-key path (the usual start) had no handles to pull it into a
curve. Auto-Bezier keys now show a handle on such a side too, pointing
where the path leaves the key, a third of the way to the next key;
dragging it makes the key Bezier with that tangent. Linear keys still
show none.

Keyframe Interpolation > Spatial Bezier copied those zero tangents, so
the keys stayed straight with no handles (and read back as Linear); it
now gives them the same handles. The path keeps its shape and timing.

The handles come from the new keyframe::spatial_handles.

Tests: spatial_bezier_gives_a_straight_path_handles (engine),
a_straight_motion_path_has_handles_to_curve_it (ui_viewer).

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-09 17:20:43 +07:00
bflatasticandClaude Opus 5.5 5b05a5ae80 Viewer: arrow keys nudge the selected layers 1 pixel at the current magnification (#290)
The arrow keys did nothing to a selected layer, so it couldn't be lined
up precisely. As in After Effects, over the Composition panel or the
Timeline an arrow key moves the selected layers 1 pixel at the viewer's
magnification (half a comp pixel at 200 %, so sub-pixel steps come from
zooming in) and Shift+arrow 10, one undo step per press; holding the
key repeats. Not while typing or with mask points selected.

The move is the new engine command layer.nudge {x, y (comp pixels),
layers?}: through each layer's parents into Position (or X/Y Position),
a key at the current time when Position is animated, locked layers left
alone. It shares the Align panel's move.

Tests: nudge_moves_layers_by_comp_pixels (engine),
arrow_keys_nudge_the_selected_layer_at_the_viewer_magnification
(ui_viewer).

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-09 17:20:43 +07:00
bflatasticandClaude Opus 5.5 e6fd1461d7 Timeline: the bar past a layer's source is striped; time remapping it ends at the source's end (#290)
A footage or precomp layer dragged out past its source's end holds its
last frame, but its bar looked the same all the way, so the source's
end couldn't be seen. That part of the bar (and any part before the
source's start) is now darkened and striped in the label colour, with
an automation id (timeline.layer.<id>.bar.afterSource / beforeSource);
with time remapping on, the remap decides what shows there, so it isn't.

Enable Time Remapping on such a layer put its end key at the extended
out point; it now ends at the source's end, where the last frame starts
to hold (After Effects). Trimmed and reversed layers keep their keys.

Tests: time_remap_on_an_extended_layer_ends_at_the_source_end (engine),
the_bar_past_the_source_end_is_striped (ui_timeline_switches).

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-09 17:20:42 +07:00
bflatasticandClaude Opus 5.5 567a947fd8 Timeline: deleting Time Remap turns time remapping off (#290)
Selecting Time Remap in the Timeline (its name, which selects all its
keys) and pressing Delete removed the keys, and a second Delete then
deleted the whole layer. As in After Effects, Edit > Clear with Time
Remap selected now turns time remapping off (Layer > Time > Enable Time
Remapping off), in one undo step, and the layer stays; one selected
Time Remap key on its own is still deleted as a key.

Test: deleting_time_remap_turns_time_remapping_off (engine).

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-09 17:12:22 +07: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 <[email protected]>
2026-10-09 17:12:22 +07:00
BFlat 735482d7ed Merge pull request #381 from storytold/fix/284-timeline-keys-tools
Timeline, keyframes, Graph Editor, Puppet and pick whip fixes from #284
2026-10-09 17:11:47 +07:00
bflatasticandClaude Opus 5.5 bf09a4fcad Expressions: the pick whip inserts at the cursor while editing (#284)
Dragging an expression's pick whip always replaced the whole
expression, also while it was being edited (and the editor then wrote
its old text back over the reference). As in After Effects, a pick
whip pressed while the expression is being edited now puts the
reference at the cursor, replacing the selected text, and the editing
goes on with the cursor after the reference. Without an edit in
progress it replaces the expression as before.

`prop.pickWhip` takes the text being edited (`expression`) and the
selection in it (`range`, in characters) to insert there.

Tests: the_expression_pick_whip_inserts_at_the_cursor_while_editing
(ui_inline_edit), pick_whip_inserts_into_the_expression_being_edited
(engine).

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-09 16:59:54 +07:00