Upstream moved crates/ui-egui/src/menus.rs into menus/*.rs; the dynamic-menu change that
draws script folders as submenus now lives in menus/bar.rs.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The default studio environment's level-preserving mean of 1 acted like a
100% white Ambient light: with only the Environment light on, a white floor
rendered at full white (95% of the frame saturated) while its shadow core
went to pitch black — a fog over the scene, nothing like After Effects'
default. Three changes bring the look in line, CPU and GPU alike:
- The default environment is a dim studio now: a solid-angle-weighted mean
of 0.3 (and a stronger key gradient), so a white floor reads a mid gray
and the light's colour x intensity still scales the level.
- The shadow occludes only the image's directional (key) fraction of the
light — |sum of dir x radiance| / sum of radiance, computed beside the
dominant direction and carried in the scene — so the fill keeps shining
inside the shadow: an area-light shadow, partial like After Effects'
(a lone bright spot on black still shadows almost fully; a uniform image
not at all).
- The environment shadow map's penumbra has a floor — eight output pixels,
or four map texels where those are coarser — because the map covers the
whole scene bounding sphere rather than the view, and its texels would
otherwise stair-step the edge (all the more in a draft render's flat 512
budget). Shadow Diffusion widens it further, as before.
Tests: the key fraction tracks directionality; the default keeps its dim
level, its direction and its key; the default and a bright key both shadow
the floor (the default partial, the key deep) with Cast Shadows off lit
everywhere; and the full look — a mid-gray lit floor (no fog), a partial
core, and a soft edge ramp in quality and draft renders alike.
After Effects' default environment map casts shadows out of the box: an
Environment light with Cast Shadows on shadows the scene with no Source
set. The flat default cancelled its dominant direction to zero, so the
option did nothing until a Source image arrived. Give the default a soft
studio gradient (bright above and toward the initial camera, dark below
and behind), level-normalised so the light's colour x intensity still
sets the overall brightness; its dominant region drives the existing
shadow pipeline, CPU and GPU alike.
Conflict in crates/text/src/layout.rs (paragraph direction at the top of
paragraph()), against the closure-to-method-path cleanup (4e9fa51f): kept this
branch's direction resolved once from BidiInfo.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The Casts Shadows option Environment lights got is only half a fix if
nothing shades for it: an image lights the scene from every direction,
and what occludes that light is the image itself — its dominant bright
region, the sun in a sky map.
- dominant_direction finds it: the radiance-weighted mean texel
direction (solid-angle weighted, rotation applied). A uniform image
cancels to zero — a flat default environment shines from everywhere
at once and casts no shadow, which a uniform environment test pins.
- The shadow is one orthographic map over the scene from that
direction, after the lights' maps, like a parallel light's: PCF
widened by Shadow Diffusion, darkened by Shadow Darkness, cleared
when nothing casts, the image is directionless, or the texel budget
drops it.
- It darkens the environment's own diffuse and specular light on
Accepts Shadows surfaces and counts in Cast Shadows Only. CPU and
GPU (WGSL) do the same; Globals carries the environment's sun
direction and shadow settings (40 → 44 floats, preflight updated).
A bright-disc environment turned to shine from behind the camera now
shadows a sphere onto the floor behind it, Cast Shadows off lights it
evenly again, and the GPU scene's sky gradient takes a shadow-casting
Environment light. Also: the renderer-switch toasts read "...renderer,
which draws 3D models", the dialog's Casts Shadows checkbox gets an
auto id (dialog.light.casts) the tests click, and the docs' Environment
notes cover the shadow.
After Effects lists Targa among its still-image output formats; EffectCraft
imported Targa (#745) but could not render to it.
- OutputFormat::TargaSequence ("Targa Sequence", `.tga`, numbered like the
other sequences; `tga` / `targa` as a format name or output extension).
- Written by the `image` crate's Targa encoder (its `tga` feature, already
enabled in effectcraft-media; no new crates, Cargo.lock unchanged), with
run-length compression off: an 18-byte header, top-left origin, 24-bit BGR
for RGB, 32-bit BGRA with 8 alpha bits in the image descriptor for
RGB + Alpha (straight or premultiplied), 8-bit grey for Alpha.
- The render queue's size estimate counts the uncompressed bytes.
- CLI usage, the renderQueue command specs, README, architecture.md and
file-format-parity.md name the new format.
Tests: each Targa frame holds exactly the pixels of the PNG sequence of the
same job, with the expected header, numbering and size; the frames read back
through the Targa importer as the same picture (straight, and premultiplied
when interpreted so); the image-sequence round trip, the format parser and
the renderQueue commands cover it too.
An Environment light had no visible effect, and its Light Settings dialog had
no Casts Shadows option — both halves of #2436.
No effect had two causes:
- Classic 3D (the default for new comps) skips Environment lights entirely,
so creating one did nothing. Adding one (or changing a light's type to it)
now switches the comp to Advanced 3D in the same undo step, with a toast,
exactly as model and primitive layers already do; switching back to
Classic 3D with an Environment light in the comp explains itself too.
- In Advanced 3D, a light with no Source and no Environment Layer produced no
environment at all. It now falls back to a flat default environment of the
light's colour × intensity, as After Effects does, so the light always
lights the scene per its parameters.
Cast Shadows was missing because the dialog and the light's property groups
shared one gate (Falloff and Shadows together) that excluded Environment.
The two are now split: every light but Ambient gets Casts Shadows, Shadow
Darkness and Shadow Diffusion (stored, edited and carried over on type
changes), while Falloff stays on Parallel/Spot/Point only — an environment
light shines from every direction at once and has no use for a falloff.
Tests: the renderer lights a card from a sourceless Environment light (colour
and intensity drive it, zero intensity lights nothing), the engine switches
Classic comps to Advanced 3D on creation and type change (one undo step,
toast, and the Classic 3D switch-back toast), Environment lights take and
carry shadow options but no Falloff, and the dialog ticks Casts Shadows on
a new Environment light.
craft-libs crates move to one rev, 37c907d2 (contains main's craft-update and craft-docpath pins).
Docs: native floating windows are Windows, macOS and X11 only; the UI estimate drops the
multi-monitor panel work that is done.
The batch merges grew Japanese 410 → 693, both Chinese catalogs 506 → 695,
Ukrainian 505 → 524, Czech 501 → 518 and Spanish 513 rows (its #996 landed)
without touching the doc's counts or shares; the overall figure was still the
10-October measurement. pt-br was the last count to update, so the row now
mirrors the code at this tree.
278 new rows (417 → 695), the Chinese catalogs' source list, keyed by the English
source string: panels, dialogs, tooltips and the Settings pages stop falling back
to English for every string the zh-hans catalog covers, including the six keys
the batch merges added on top. Terminology follows After Effects' Brazilian
Portuguese conventions; brand names stay English.
AI-assisted translation (OpenCode agents, GLM); not yet native-speaker proofread.
Layer > Create > Create 3D Layer Instance, as After Effects (public docs):
3D model layers take no masks or effects, so the command puts a comp-sized
solid at the top of the layer stack with CC Composite referencing the
selected model, and switches the model off (back on to keep its shadow) -
a 2D copy of its render, through the comp's camera, that 2D effects can be
applied to.
- CC Composite (ec.channel.cccomposite) gains an optional Layer parameter:
with a layer chosen it takes the original's place; In Front replaces the
solid's pixels, alpha included, the other Composite Original modes blend
with them. The GPU compositor runs such an instance on the CPU.
- FxHost serves a referenced model or primitive layer as After Effects
does - the layer rendered on its own through the comp's camera
(Renderer::solo_3d); the owner keeps no cache entry for it (it moves with
the camera and lights, without a trace in its own properties).
- layer.create {op: instance3d} skips layers that are not 3D model or
primitive layers (the ones that take no effects); one undo step, the copy
selected, the model's video off.
Tests: tests_instance3d.rs (behaviour, pixels, undo/redo, serde, 2D effects
on the copy), a CC Composite layer-parameter unit test; docs/effects.md
regenerated (3033 parameters).
- Default's right column is a short Preview frame (fixed 76 pt: tab strip and a 46 pt body)
over a Properties frame with Align, Audio and Effects & Presets as tabs. Essential Graphics'
right column is one Properties / Effects & Presets frame. No built-in workspace uses
accordions, so a frame there takes tabs and Maximize acts on one frame.
- Workspace files of version 1: a column of stacked frames becomes tab groups split top to
bottom. Each open frame keeps all its tabs and its height as a fixed size; a closed frame's
tabs join the open frame above it.
- Version 1 stored a native panel window's outer position; craft-ui places windows by their
content. The migrated rect moves by the main window's frame offset once the main window
reports it, and workspaces are not saved before.
craft-ui's native-windows feature is on for every non-wasm build. Keys and
dropped files from a floating window reach the main window's next frame, and
while a modal dialog is open the dock area blocks input in floating windows.
Move Panel to Main Window docks the panel again. The web, Wayland and embedded
viewports keep floating windows in the main window.
Edit ▸ Keyboard Shortcuts now lists the scripts File ▸ Scripts lists, under
File ▸ Scripts, and a key given to one runs it as its menu entry does. The
key is bound to the script's file name (file.runScript {"name": ...}) and is
saved with the preset. File ▸ Scripts and the macOS menu show it.
The shortcut table lists the Scripts folder again when a script is installed
or uninstalled, when the editor opens and when shortcuts.list runs.
shortcuts.set and shortcuts.reset look a script up in File ▸ Scripts' list
as it is now, and a script it doesn't list is an error instead of a key for
Run Script File....
Every craft-libs crate and the hayro-syntax and hayro-jbig2 patches are
pinned to storytold/craft-libs 2869b8cc. The workspace is a craft-ui
Workspace<PanelKind>: craft-ui draws the frames, tab strips, stacked
panels, floating windows and drop previews and owns the gestures.
EffectCraft keeps PanelKind, its built-in workspaces, the panel bodies,
the Timeline's comp tabs, viewer locks and the panel menu in each group
header, and the rule that no move or float empties the docked area.
window.dockAction applies craft-ui Actions; craft-ui's window.panel.*
commands, ui.dock and ui.dock.reset parse as DockCommand. Saved
workspaces are version 2 snapshots of craft-ui Workspaces; an earlier
file loads as the default layout and is left untouched.
Reconcile main 991904888a and preserve the reviewed lifecycle, IME, rendering and lockfile changes.
Formatting, strict lint, layers, assets and WASM passed. Full CI retained 3,961 passes, 14 baseline-matching GPU failures and 31 ignored executions. The local review commit has explicit approval to retain these documented failures; native/browser acceptance and paired app performance remain open.
The footage page said the 10 Bit White Point becomes the Converted White
Point. That holds with Highlight Rolloff at 0; at the default 20 the top of
the converted range is bent into a curve, as in the Cineon Converter effect,
and the white point converts to a lower level.
Unfiltered, list_commands returns ~134 KB and list_effects ~480 KB, more
than MCP clients accept in one tool result. With `compact: true`,
list_commands (and its command_list alias) returns only each command's
id and label, and list_effects only each effect's id, name and category
(~40 KB and ~23 KB). Default output is unchanged; filter and
enabled_only still apply.
DPX and Cineon footage showed its log code values as stored, with no
way to convert them. Interpret Footage now has the Cineon Settings that
After Effects' help page describes: Logarithmic Conversion, the
Converted Black and White Points, the 10 Bit Black and White Points,
Current Gamma, Highlight Rolloff and Units. With Logarithmic
Conversion on, the code values of each decoded frame are converted
from printing density to the Current Gamma between the converted
points, before Separate Fields, Frame Blending, Interpret As Linear
Light and the working space use them. With it off (the default), the
values stay as stored.
file.interpretFootage and file.interpretProxy take the settings as
parameters and report them. They return an error for out-of-range
values, and for Cineon parameters when none of the items is a DPX or
Cineon file. Apply Interpretation copies the settings between DPX and
Cineon files.
A subfolder of a Scripts folder can be a link to another folder (an extension's own checkout).
`file.uninstallScript {"name": "Motion Kit/Animate.jsx"}` then deleted Animate.jsx in that
folder, outside the settings folder. Uninstall now refuses `Folder/File.jsx` names and removes
only scripts at the top of the Scripts folders, where Install puts them; listing and running
through a linked folder still work.
Regression test: uninstall_never_deletes_through_a_linked_subfolder (failed before the fix).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
File ▸ Scripts gets a Recent Script Files submenu with the ten scripts run
last, newest first: script files run with Run Script File… or a command, and
the installed and bundled scripts of File ▸ Scripts. ScriptUI panels are not
listed. The list is kept in the settings. Each entry runs its script again
through `file.runScript {"recent": i}`, and Cmd+Alt+Shift+D runs the most
recent one; the key can be changed in Edit ▸ Keyboard Shortcuts. An entry
records whether it ran a file or an installed script, so a file named like a
bundled script runs again as that file.
An extension that ships several panels no longer adds one Window menu entry per panel:
`Scripts/ScriptUI Panels/Motion Kit/Animate.jsx` shows as Window > Motion Kit > Animate.jsx,
and a subfolder of `Scripts/` is a submenu of File > Scripts. Top-level scripts are unchanged.
- Script names may be `Folder/File.jsx`: exactly one folder, each part a bare name (no `..`,
`\`, NUL or empty part), never `ScriptUI Panels/...` under `Scripts/`.
- window.scriptPanel, file.runScript, file.uninstallScript, file.scripts.list and
scriptui_panels.json take such names; a panel's tab is titled after its file.
- ConfigStore::list_dirs (DirConfig, MemoryConfig) lists the subfolders.
- menus::dynamic_nodes groups a folder's entries into a MenuNode::Submenu; the egui and native
menus draw it with their submenu code.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Scripts in Scripts/Startup and Scripts/Shutdown in the settings folder
were never run. The desktop and web apps now run the Startup scripts at
launch, before a project opens, and the desktop app runs the Shutdown
scripts as it quits, after the project is closed. Each folder runs in
alphabetical order with case ignored, and files larger than 16 MiB are
not run. A Startup script that fails is reported in a toast and in the
log, a Shutdown script that fails is reported in the log, and the next
one still runs.
A Startup script that waits in a modal dialog goes on when the dialog
closes, while the next scripts run. A Shutdown script's dialogs close
as if canceled. With the settings folder on disk, each script runs as
its file, so #include, $.fileName and $.evalFile resolve against the
script's own folder.
The new commands file.runStartupScripts and file.runShutdownScripts
return the scripts that ran, those still waiting in a dialog, and those
that failed. Like script.run, both are refused in confined automation
sessions, in batches and in script steps, which now read one list of
script commands (RUNS_SCRIPTS). The list also holds window.scriptPanel
and window.restoreScriptPanels, which run ScriptUI panel scripts and
were not refused on main either. The apps still call
window.restoreScriptPanels at launch. plugins.md, scripting-parity.md,
gaps.md, target-app-parity.md and agents.md describe the folders. Each script
still runs in its own global scope, so a Startup script's variables are
not available to later scripts.