mirror of
https://github.com/storytold/effectcraft.git
synced 2026-10-14 19:27:05 -04:00
Merge upstream/main into gap-object-matte
Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
This commit is contained in:
commit
4acea86d4f
275 files changed
+24783
-1912
No files matched your search
+21
-6
@@ -107,7 +107,7 @@ See [MCP conventions](mcp.md) for core tools, resources, strict arguments, and r
|
||||
| `set_property {layer, path, value?, time?, timeBase?, expression?, comp?}` | Sets a static value. With `time` it sets a keyframe (`timeBase: "comp"` for comp seconds); with `expression` it sets an expression. |
|
||||
| `add_keyframe {layer, path, time+value \| keys:[...], timeBase?, interpolation?, comp?}` | Adds keys (layer seconds, or comp seconds with `timeBase: "comp"`), then optionally applies linear/bezier/hold/easyEase. |
|
||||
| `list_effects {filter?}` | Effect ids, names, categories, GPU / 32-bpc support and parameters. |
|
||||
| `list_fonts {query?, rescan?}` | Font families text layers can use, bundled and installed, with their styles, origin and own-language name; `rescan` picks up fonts installed since launch. |
|
||||
| `list_fonts {query?, variable?, rescan?}` | Font families text layers can use, bundled and installed, with their styles, origin, whether each is a variable font and own-language name; `variable` lists only variable fonts; `rescan` picks up fonts installed since launch. |
|
||||
| `add_effect {layer, effect, values?, comp?}` | Apply an effect and set its parameters in one call and one undo step (a failing value leaves nothing applied); returns the instance path (`effects/#n`) and its parameter paths. |
|
||||
| `render_frame {comp?, time?, max_side?, path?, inline?, transparent?}` | Returns a PNG image of a frame; `transparent: true` keeps the alpha (as an RGB + Alpha render writes it) instead of compositing over the comp background. |
|
||||
| `open_project {path \| demo \| new}` / `save_project {path?}` | Open and save files. |
|
||||
@@ -123,7 +123,8 @@ See [MCP conventions](mcp.md) for core tools, resources, strict arguments, and r
|
||||
| `render_preview` | Render a PNG without writing a file (`comp`, `time`, `max_side`, `transparent`). |
|
||||
|
||||
Layers are referenced by id (from `get_comp`), `"#n"` (1-based index from the top) or name. Comps are
|
||||
referenced by id or name, and default to the active comp. Property paths come from `get_layer`, for
|
||||
referenced by id or name, and default to the active comp. An id may also be sent as a string (`"98"`):
|
||||
an all-digit string that matches no name is taken as the id. Property paths come from `get_layer`, for
|
||||
example `transform/position`, `transform/opacity`, `effects/#1/blurriness` or `@57` (by uid). Times
|
||||
are in seconds. Keyframe times are layer time, which equals comp time unless the layer is offset or
|
||||
stretched.
|
||||
@@ -144,7 +145,7 @@ carries outside-range warnings; the existing objects from `keys.set` and `prop.g
|
||||
also report both bases and warnings. `prop.get.time` is comp seconds. Separated Position
|
||||
`prop.set` retains per-axis replies; for these commands, `path` or `prop` identifies a property, not a group.
|
||||
|
||||
Set offsets with `layer.timing {layer, start: 10.5}`; `in`, `out` and `delta` also use comp seconds.
|
||||
Set offsets with `layer.timing {layer, start: 10.5}`; `in`, `out` and `delta` also use comp seconds; `inDelta` / `outDelta` trim each layer from its own in/out point.
|
||||
For an unstretched layer starting at 10.5 s in a 30 fps comp,
|
||||
`prop.addKey {layer: "A", path: "transform/opacity", time: 15.3,
|
||||
timeBase: "comp", value: 0}` writes a key at comp 15.3 s (layer 4.8 s), matching
|
||||
@@ -219,6 +220,10 @@ build real projects through these interfaces; they are worked examples of everyt
|
||||
* **Nested comps**: `comp.settings {preserveFrameRate, preserveResolution}` (Composition Settings ▸
|
||||
Advanced); `comp.info` / `get_comp` report both. A precomp layer shows nothing outside its
|
||||
nested comp's span.
|
||||
* **Viewer Resolution** belongs to each comp and is saved with the project, as in After Effects:
|
||||
`view.res.full|half|third|quarter|auto {comp?}` or `view.res.custom {factor: 1..40, comp?}`
|
||||
(headless too; no undo step, the project becomes modified). `comp.info` reports `resolution`
|
||||
and `resolutionFactor` (`null` for Auto).
|
||||
* **Several footage items at once**: `file.newCompFromSelection {single, dimensionsFrom, duration,
|
||||
sequence, overlap, overlapDuration, transition, addToRenderQueue}` is one undo step (select the
|
||||
items first: `project.select`).
|
||||
@@ -511,12 +516,19 @@ whole layer, or only characters `range: [start, end]` (character indices): chara
|
||||
work on the selected text; `text.endEdit` commits (an empty Type-tool layer is removed).
|
||||
|
||||
Fonts: `text.fonts` (MCP `list_fonts`) lists every family a text layer can use, bundled and installed, with its
|
||||
styles, origin (`bundled`, `system`, `user`) and own-language name (`{"query":"gothic"}` filters
|
||||
by name; `{"rescan":true}` first picks up fonts installed since launch). Pass a listed `family` and
|
||||
styles, origin (`bundled`, `system`, `user`), `variable` (it has variation axes) and own-language name
|
||||
(`{"query":"gothic"}` filters by name, `{"variable":true}` keeps only variable fonts, like the font
|
||||
menu's Variable Fonts filter; `{"rescan":true}` first picks up fonts installed since launch). Pass a listed `family` and
|
||||
one of its `styles` to `layer.setText {"font", "style"}`; `text.fontFeatures` says which OpenType
|
||||
options a font draws with its own glyphs.
|
||||
A tool with its own font library can hand it over without installing it: folders listed in
|
||||
`EFFECTCRAFT_FONT_DIRS` (a path list, `:`-separated, `;` on Windows) are scanned like the system font folders.
|
||||
On Linux and the BSDs the system font folders are `/usr/share/fonts`, `/usr/local/share/fonts`,
|
||||
`~/.local/share/fonts`, `~/.fonts`, `$XDG_DATA_HOME/fonts`, `fonts` in each `$XDG_DATA_DIRS` folder,
|
||||
every `<dir>` the fontconfig configuration names (`/etc/fonts/fonts.conf` with its includes,
|
||||
`~/.config/fontconfig/fonts.conf`) and, in the Flatpak, the host's fonts under `/run/host`. The
|
||||
Flatpak can't see other folders; grant one with
|
||||
`flatpak override --user --filesystem=<dir>:ro --env=EFFECTCRAFT_FONT_DIRS=<dir> ai.storyteller.effectcraft`.
|
||||
|
||||
In expressions, `text.sourceText.style` / `getStyleAt(i, t)` read styles and the setters
|
||||
(`setFontSize(v, start?, count?)`, `setFillColor`, `setText`, `setJustification`…) return a
|
||||
@@ -532,7 +544,10 @@ Scripts that build ScriptUI windows publish them to the session; agents drive th
|
||||
3. `scriptui.click {"widget": "ok"}` presses a button / toggles a checkbox / picks a radio button or
|
||||
tab; `scriptui.set {"widget": "#4", "value": "Shot_"}` types into edit text, moves a slider or
|
||||
picks a list item (index or text); `scriptui.close {"result": 2}` closes. Controls are addressed
|
||||
by id, `#id`, `properties.name` or text; `window` can be omitted when one window is open. Each
|
||||
by id, `#id`, `properties.name` or text; `window` can be omitted when one window is open.
|
||||
`scriptui.mouse {"widget": "pad", "type": "mousedown", "x": 10, "y": 20}` sends a mouse event
|
||||
(`mousedown`, `mouseup`, `mousemove`, `mouseover`, `mouseout`, `click`; `x`/`y` relative to the
|
||||
control, `button`, `detail`, `shiftKey`…) to the script's `addEventListener` listeners. Each
|
||||
returns the handler run's `{ok, output, error}`.
|
||||
|
||||
A dialog's `show()` waits for the user: the `script.run` / `file.runScript` reply carries
|
||||
|
||||
+26
-3
@@ -95,7 +95,10 @@ XML). Saving goes through `Project::to_file_json`, which checks that the text re
|
||||
anything is written (JSON can't hold NaN or infinity), and files are written atomically. Opening
|
||||
a file that a newer EffectCraft saved shows a warning: fields this version doesn't know are
|
||||
dropped if it saves the project. Save, Save As, Save a Copy and Increment and Save keep the
|
||||
file's format (`.ecprojx` stays XML).
|
||||
file's format (`.ecprojx` stays XML). Next to `savedBy` the file records the active comp and the
|
||||
open comp tabs (`activeComp`, `openComps`), which opening restores; they are editor state, not
|
||||
part of `Project`, so older files (and ids that no longer name a comp) open on the first comp and
|
||||
older versions ignore them.
|
||||
|
||||
`schema` changes when a saved value changes meaning; a project from an older schema is converted
|
||||
when it is opened (`effectcraft_engine::upgrade_effects`, which also refreshes effect instances
|
||||
@@ -191,7 +194,10 @@ are dropped; running jobs finish into the cache. When the budget (Settings ▸ M
|
||||
full the least recently shown frames go first. The timeline's green bar counts cached frames
|
||||
of the current content and viewer settings.
|
||||
Resolution Auto renders the pixels the magnification needs, as in After Effects (Full above
|
||||
50 %, Half down to 33.3 %, Third down to 25 %, then Quarter). Below 100 % the viewer averages
|
||||
50 %, Half down to 33.3 %, Third down to 25 %, then Quarter). The Resolution is the comp's
|
||||
(`Comp::resolution`, saved with the project): setting it is no undo step (undo, redo and history
|
||||
jumps carry the current values over) and, like the Shy switches, it is outside
|
||||
`Comp::same_pixels`, so cached frames stay valid. Below 100 % the viewer averages
|
||||
instead of skipping pixels (Viewer Zoom Quality More Accurate): GPU frames carry a mip chain
|
||||
sampled trilinearly, CPU frames go up averaged down by the whole factor that leaves about one
|
||||
texel per screen pixel.
|
||||
@@ -388,6 +394,9 @@ their on-screen scale, as text is vector in After Effects; on shape layers and v
|
||||
switch is Continuously Rasterize and does the same. Quality: Draft samples
|
||||
nearest-neighbour, Wireframe draws the layer bounds. Slip edit (`layer.slip`, Alt+PageUp/Down,
|
||||
dragging the source bar in the timeline) moves the source under fixed in/out points.
|
||||
Dragging a layer bar's in or out edge with several layers selected trims every selected layer by
|
||||
the same amount from its own in/out point (`layer.timing {inDelta | outDelta}`), clamped to the
|
||||
comp and to one frame of layer, as one undo step.
|
||||
|
||||
**Nested comps** show nothing before they start or after they end (`Comp::covers`), even when
|
||||
the precomp layer is trimmed or remapped past them. A comp with **Preserve frame rate when nested
|
||||
@@ -540,10 +549,24 @@ text, disables the expression and shows a warning, like After Effects. `sampleIm
|
||||
sampled layer through the evaluating renderer's footage source (`EvalCtx::footage`), cached per
|
||||
thread and frame; `footage(name)` reads data footage (JSON, CSV, TSV imported with File ▸ Import,
|
||||
text kept in the project) through `sourceData`, `sourceText` and `dataValue`. `expr.errors`
|
||||
lists failing expressions for the viewer's error bar. Each thread keeps one boa context; boa
|
||||
lists failing expressions on demand. The viewer's error bar uses the same checks against an
|
||||
immutable project snapshot, after 150 ms without editing, pointer interaction or playback.
|
||||
Native builds run these automatic checks on one persistent worker; layout and paint only read
|
||||
completed results. Requests are coalesced per comp, cancelled between properties when obsolete,
|
||||
and bounded to eight comp entries. Results must match the current project, revision and time.
|
||||
Disabling Show Expression Error Banner cancels automatic checks. Non-solo layers still receive
|
||||
diagnostics, including disabled expressions with syntax errors. The single-threaded web build
|
||||
shares the cache and debounce but evaluates one scan on the UI thread after interaction stops.
|
||||
Each thread keeps one boa context; boa
|
||||
leaves values on its stack whenever an exception unwinds through call frames (every pending
|
||||
host request does), so a run that hits the stack limit gets a fresh context and is retried once.
|
||||
|
||||
Snapping memoizes expression values while collecting one immutable set of targets. Bounds,
|
||||
vertices and transforms share those values; the cache is discarded before the next query, so
|
||||
time changes and edits always use current geometry. Native timeline disk-cache indicators also
|
||||
request missing content hashes in the background, coalescing edits per comp. Their blue bars
|
||||
appear after the key is ready instead of serializing composition content during painting.
|
||||
|
||||
## 5a. Scripting
|
||||
|
||||
`effectcraft-script` runs JavaScript (boa, a fresh context per run; the Script Console keeps one)
|
||||
|
||||
@@ -134,7 +134,10 @@ Viewer state that agents drive headless too: `view.snapping`, `view.snappingOpti
|
||||
`header.snappingOptions`: After Effects' Snap Edges Extended and Snap to Features in Collapsed
|
||||
Compositions and Text Layers), `view.channel {channel, colorized?}`,
|
||||
`view.exposure {stops | delta}`, `view.resetExposure`, `view.takeSnapshot`, `view.showSnapshot`,
|
||||
`view.fastPreviewMode {mode}`, `view.setRegionOfInterest {rect}`, `view.addGuide`,
|
||||
`view.fastPreviewMode {mode}`, `view.res.full|half|third|quarter|auto {comp?}` and
|
||||
`view.res.custom {factor, comp?}` (the comp's Resolution, saved with the project but no undo
|
||||
step; `ui.set {viewer: {res}}` sets the active comp's, and `ui.inspect` reports it as
|
||||
`ui.viewer.res`), `view.setRegionOfInterest {rect}`, `view.addGuide`,
|
||||
`view.moveGuide`, `view.removeGuide`; editing: `shape.newPath` (Pen on shape layers),
|
||||
`shape.newShape` (the shape tools: a new group in the selected shape layer, else a new shape layer),
|
||||
`shape.toolOptions` (the Tools bar's Tool Creates Shape / Mask and Fill and Stroke Options),
|
||||
|
||||
@@ -16,7 +16,7 @@ After Effects', and does the preset library exist. The per-effect catalogue is t
|
||||
| On the GPU | **280** (92%) | Measured: registry flags; GPU vs CPU agreement tested per effect |
|
||||
| 32-bit float, no clamping | 306 | Measured: registry flags |
|
||||
| **Rendered output matches After Effects** | **unmeasured** | No effect is compared with an After Effects render yet. `effectcraft_effects::fidelity::compare_frames` exists for the corpus ([fidelity/README.md](fidelity/README.md)); simulation effects are pinned by golden hashes of our own output (M13.27) |
|
||||
| Animation presets | **8** original text-animator presets against After Effects' **621** `.ffx` presets | Measured: `crates/engine/presets/text_animators.json`; the After Effects `Presets` folder |
|
||||
| Animation presets | **31** original presets (8 text-animator, 23 Transitions) against After Effects' **621** `.ffx` presets | Measured: `crates/engine/presets/text_animators.json`, `crates/engine/presets/transitions.json`; the After Effects `Presets` folder |
|
||||
| 26.x additions | Curl Noise (26.3) present (#463 open); effect colour labels and the rebuilt Effect Controls (26.5) missing | Release notes |
|
||||
|
||||
**Breadth ≈ 85%** (presets weigh in; the effects themselves are ≈ 100%). **Ready ≈ 40%**: until a
|
||||
|
||||
+2
-2
@@ -3,7 +3,7 @@
|
||||
<!-- Generated from the effect registry (crates/effects/src/catalog.rs); do not edit by hand.
|
||||
Regenerate: UPDATE_DOCS=1 cargo test -p effectcraft-effects --lib effects_doc_is_current -->
|
||||
|
||||
EffectCraft ships 307 effects with 3029 parameters in total, grouped into the same categories as the Effects & Presets panel. Every effect is our own implementation, written from public behaviour descriptions and standard image-processing literature. Parameter names, order, popup options, units, defaults and ranges follow the reference application so that projects, expressions and muscle memory carry over.
|
||||
EffectCraft ships 307 effects with 3032 parameters in total, grouped into the same categories as the Effects & Presets panel. Every effect is our own implementation, written from public behaviour descriptions and standard image-processing literature. Parameter names, order, popup options, units, defaults and ranges follow the reference application so that projects, expressions and muscle memory carry over.
|
||||
|
||||
- **GPU**: 280 effects also run on the GPU compositor with identical results.
|
||||
- **32**: 307 effects process 32-bit float (HDR, overbright) pixels without clamping.
|
||||
@@ -307,7 +307,7 @@ Effects are addressed by id (`ec.<category>.<name>`) or display name in commands
|
||||
| 3D Glasses | `ec.perspective.3dglasses` | 8 | GPU | 32 | Implemented |
|
||||
| Bevel Alpha | `ec.perspective.bevelalpha` | 4 | GPU | 32 | Implemented |
|
||||
| Bevel Edges | `ec.perspective.beveledges` | 4 | GPU | 32 | Implemented |
|
||||
| CC Cylinder | `ec.perspective.cccylinder` | 12 | GPU | 32 | Implemented |
|
||||
| CC Cylinder | `ec.perspective.cccylinder` | 15 | GPU | 32 | Implemented |
|
||||
| CC Environment | `ec.perspective.ccenvironment` | 4 | GPU | 32 | Implemented |
|
||||
| CC Sphere | `ec.perspective.ccsphere` | 14 | GPU | 32 | Implemented |
|
||||
| CC Spotlight | `ec.perspective.ccspotlight` | 8 | GPU | 32 | Implemented |
|
||||
|
||||
+14
-13
@@ -44,13 +44,13 @@ trips and renders, checked by tests, not against After Effects), **partial** (na
|
||||
| OpenEXR (multi-layer, Cryptomatte) | R/W | yes | yes (32-bit sequence) | good; HTJ2K compression fails (#482); EXRs without an unnamed RGB layer decode twice (#474) |
|
||||
| Photoshop PSD / PSB | R (footage, composition) / W (layers, sequence) | yes (layers, groups, masks, styles, smart objects) | Save Frame As ▸ Photoshop Layers; no Photoshop sequence output | good, from Adobe's published spec |
|
||||
| Illustrator `.ai`, PDF, EPS | R | yes (vector, Continuously Rasterize, Create Shapes) | — | partial: no JPX / JBIG2 images, no Illustrator procset EPS |
|
||||
| SVG | R | yes | — | good; pasting SVG/AI as shape layers (26.3) missing |
|
||||
| SVG | R | yes | — | good; SVG markup on the clipboard pastes as a shape layer (26.3, #738); Illustrator's own clipboard data (PDF/AI) doesn't |
|
||||
| GIF | R/W | yes | yes (animated) | good |
|
||||
| BMP | R | yes | — | good |
|
||||
| WebP | — | yes | — | beyond After Effects |
|
||||
| Targa `.tga` | R/W | none | none | Media Browser lists it but import refuses (gap 17) |
|
||||
| DPX / Cineon `.dpx` `.cin` | R/W | none | none | Same; common in film VFX |
|
||||
| Radiance `.hdr` | R/W | none | none | Same |
|
||||
| WebP | — | yes (still; animated WebP as footage with its frames, timing and alpha, #762) | — | beyond After Effects |
|
||||
| Targa `.tga` | R/W | yes (still and sequence; alpha interpreted on import) | none | good for import (#745); no Targa output |
|
||||
| DPX / Cineon `.dpx` `.cin` | R/W | yes (still and sequence; 8/10/12/16-bit luma, RGB, RGBA, both byte orders; log code values shown as stored) | none | partial: import (#756); no Interpret Footage ▸ Cineon Settings (log to linear), no DPX output; common in film VFX |
|
||||
| Radiance `.hdr` | R/W | yes (still and sequence, 32-bit linear float like OpenEXR) | none | good for import (#745); no Radiance output |
|
||||
| SGI, PICT, ElectricImage, RLA/RPF images | R | none | none | Legacy; RPF camera data import exists (`keys.rpfCameraImport`) |
|
||||
| Camera Raw (DNG, CR3, NEF…) | R (Camera Raw) | none | none | LightCraft has decoders that could be shared |
|
||||
| HEIF / AVIF | R (platform) | none | none | — |
|
||||
@@ -64,7 +64,7 @@ trips and renders, checked by tests, not against After Effects), **partial** (na
|
||||
| AV1 | R | yes | yes (MP4 `av01`, WebM) | beyond After Effects' export; no B-frames / CDEF |
|
||||
| Apple ProRes (422 family, 4444) | R/W | yes | yes | good; 4444 colour tag wrong (#340); no ProRes RAW |
|
||||
| WebM / Matroska (VP9, AV1, Opus) | R (limited) | yes, incl. VP9 alpha | yes | beyond After Effects |
|
||||
| MXF (OP1a / OP-Atom) | R/W | none (FilmCraft reads it; not wired) | none | Media Browser lists it |
|
||||
| MXF (OP1a / OP-Atom) | R/W | yes (FilmCraft's demuxer: AVC, MPEG-2 incl. XDCAM / D-10, VC-3 / DNxHD, ProRes; PCM audio) | none | partial: import (#767), checked against ffmpeg; no MXF output |
|
||||
| AVI | R | none | none | Media Browser lists it |
|
||||
| DNxHD / DNxHR | R/W | unverified (FilmCraft decodes it; reachable only inside `.mov`) | none | — |
|
||||
| BRAW, R3D, ARRIRAW | R (plug-ins / SDKs) | none | none | proprietary SDKs |
|
||||
@@ -78,9 +78,9 @@ trips and renders, checked by tests, not against After Effects), **partial** (na
|
||||
|---|---|---|---|
|
||||
| glTF / GLB | R | yes (meshes, PBR, skins, animations) | good |
|
||||
| OBJ / MTL | R | yes | good |
|
||||
| FBX | R (`usdFbx`) | none | gap 13 |
|
||||
| FBX | R (`usdFbx`) | yes (7.x binary and ASCII: meshes with normals, UVs and per-polygon materials, the Model hierarchy with pivots and pre/post rotation, Lambert/Phong materials with embedded or relative textures, axes turned to Y-up; no animation, skinning, cameras or lights; 6.x rejected) | partial |
|
||||
| USD / USDZ | R (`usd_plugins`) | none | gap 13 |
|
||||
| STL | R (`usdStl`) | none | gap 13 |
|
||||
| STL | R (`usdStl`) | yes (binary and ASCII, VisCAM and Magics facet colours; Z-up turned to Y-up) | good |
|
||||
| Substance 3D materials `.sbsar` | R (26.0) | none | gap 13 |
|
||||
|
||||
## Interchange and data
|
||||
@@ -96,18 +96,19 @@ trips and renders, checked by tests, not against After Effects), **partial** (na
|
||||
| Mocha shapes | R (Mocha AE) | own documented JSON | — | Mocha's format is not public |
|
||||
| Vanishing Point `.vpe` | R | none | — | no public specification; the menu entry explains why |
|
||||
|
||||
## Render queue outputs (`OutputFormat::ALL`, 12)
|
||||
## Render queue outputs (`OutputFormat::ALL`, 13)
|
||||
|
||||
H.264 MP4, HEVC MP4, AV1 MP4, ProRes MOV, WebM (VP9 or AV1 + Opus), PNG / JPEG / TIFF / OpenEXR
|
||||
sequences, animated GIF, WAV, AIFF. Missing against After Effects + Media Encoder: uncompressed
|
||||
or lossless single-file video (#372), DPX / Targa / Photoshop sequences, MXF, DNxHR, hardware
|
||||
H.264 MP4, HEVC MP4, AV1 MP4, ProRes MOV, uncompressed 8-bit RGB / RGB + Alpha MOV (`raw `, + PCM;
|
||||
#372), WebM (VP9 or AV1 + Opus), PNG / JPEG / TIFF / OpenEXR sequences, animated GIF, WAV, AIFF.
|
||||
Missing against After Effects + Media Encoder: 16-bpc uncompressed, AVI and lossless-compressed
|
||||
single-file video (Animation / PNG codecs), DPX / Targa / Photoshop sequences, MXF, DNxHR, hardware
|
||||
encoders ([hardware-parity.md](hardware-parity.md)), and rendering safely over an existing file
|
||||
(#325).
|
||||
|
||||
## Estimate
|
||||
|
||||
**≈ 130–230 h**: `.aep` / `.aepx` import 80–160 h (after the owner decision), wiring TGA / DPX /
|
||||
HDR / MXF / AVI / DNx import and DPX/TGA output 10–20 h, FBX / USD / STL and Substance 25–45 h,
|
||||
HDR / MXF / AVI / DNx import and DPX/TGA output 10–20 h, FBX animation and skinning, USD and Substance 20–40 h,
|
||||
relinking 6–12 h, `.mogrt`-compatible templates 15–30 h (partly parallel with the rest).
|
||||
|
||||
## Revision history
|
||||
|
||||
+36
-10
@@ -63,25 +63,25 @@ are grouped by area; the issue tracker has the rest.
|
||||
| 4 | **No CI gate on pull requests** | `.github/workflows` has release, packaging-lint, FreeBSD and Windows ARM64 jobs only; `cargo xtask ci` runs locally | Regressions reach main unseen; 49 community PRs landed in one batch (#598) | 4–8 h | G3 · this file |
|
||||
| 5 | **Playback and scrubbing feel** | #595 stutter on cached frames, #304, #329 slow scrubbing, #554 / #504 / #335 audio late or crackling, #586 puppet lag | Preview is where motion designers spend their day | 25–50 h | G5 · [hardware-parity.md](hardware-parity.md) |
|
||||
| 6 | **Linux and Windows interaction bugs** | #491 multi-layer edits, #488 rename arrows, #493, #492, #467 shortcuts, #268 drag and drop, #320 workspaces not persisting, #302 docking, #613 Direct3D 12 compositor, #596 GPU not detected | Many reports come from Linux; some Windows GPUs fail to start the compositor | 25–45 h | G2 · [ui-parity.md](ui-parity.md) |
|
||||
| 7 | **Animation presets: 8 against 621** | After Effects ships 621 `.ffx` presets (Behaviors, Backgrounds, Shapes, Synthetics, Text, Transitions…); we ship 8 original text-animator presets and read only our `.ecpreset` | Presets are how many designers start; tutorials assume them | 20–40 h (original presets; `.ffx` reading is out of clean-room scope) | G8 · [effects-parity.md](effects-parity.md) |
|
||||
| 7 | **Animation presets: 31 against 621** | After Effects ships 621 `.ffx` presets (Behaviors, Backgrounds, Shapes, Synthetics, Text, Transitions…); we ship 31 original presets (8 text-animator, 23 Transitions: wipes, clock and fan reveals, blinds, dissolves, card flips, CC wipes, fades; #757) and read only our `.ecpreset`. Missing: Behaviors, Backgrounds, Shapes, Synthetics, Image and more Text | Presets are how many designers start; tutorials assume them | 15–35 h (original presets; `.ffx` reading is out of clean-room scope) | G8 · [effects-parity.md](effects-parity.md) |
|
||||
| 8 | **Mask and shape bugs** | #510, #513, #527 (first Intersect/Darken mask), #509 Roto Brush size, #303 Mesh Warp, #553 pen tools on motion paths | Masks are core compositing | 10–20 h | G2 · [target-app-parity.md](target-app-parity.md) |
|
||||
| 9 | **Effect behaviour bugs** | #580, #526 Fractal reset, #514 Apply Color LUT, #463 Curl Noise, #369 Motion Tile output size, #473 Cryptomatte selection, #474 multi-layer EXR decoded twice, #534–#536 community fixes pending | Each one breaks a look someone built | 10–20 h | G1/G2 · [effects-parity.md](effects-parity.md) |
|
||||
| 10 | **Colour pipeline differences** | #494 32-bpc blend modes clamp and apply opacity differently; #495 no Working Gamma 2.4; #340 ProRes 4444 tagged bt709 but sRGB-encoded; ACES 2.0 / OCIO 2.5 configs (26.5) missing; #546 / #547 viewer colour | Wrong colour in delivery is a client-visible failure | 15–30 h | G1 · [file-format-parity.md](file-format-parity.md) |
|
||||
| 10 | **Colour pipeline differences** | #494 32-bpc blend modes clamp and apply opacity differently; #495 Working Gamma 2.4 (in, also for float footage: #750); #340 ProRes 4444 tagged bt709 but sRGB-encoded; ACES 2.0 / OCIO 2.5 configs (26.5) missing; #546 / #547 viewer colour | Wrong colour in delivery is a client-visible failure | 15–30 h | G1 · [file-format-parity.md](file-format-parity.md) |
|
||||
| 11 | **Text rendering and layout** | #453 CJK text in comps, #316 paragraph alignment inverted, #483 squeezed at 4:3, #417 soft at Fit, #583 font search, #550 toolbar font options | Text is in almost every motion graphic | 10–20 h | G2 · [ui-parity.md](ui-parity.md) |
|
||||
| 12 | **3D interaction and depth** | No 3D transform gizmos (#392, #347); Z position (#489); camera aperture (#260); reflections (#261); bevel options (#315); 3D issue reopened (#307) | Advanced 3D is After Effects' growth area since 2023 | 20–35 h | G2 · [ui-parity.md](ui-parity.md) |
|
||||
| 13 | **3D model formats and materials** | After Effects 26 imports FBX, USD/USDZ, STL besides glTF and OBJ (`usd_plugins`), and Substance 3D materials with mesh displacement (26.0–26.2); we read glTF and OBJ | Product shots and 3D scenes come as FBX/USDZ | 25–45 h | — · [file-format-parity.md](file-format-parity.md) |
|
||||
| 12 | **3D interaction and depth** | No 3D transform gizmos (#392, #347); Z position (#489); camera aperture (#260); reflections (#261); extruded surface materials beyond Front / Bevel / Side / Back Color (#315); 3D issue reopened (#307) | Advanced 3D is After Effects' growth area since 2023 | 20–35 h | G2 · [ui-parity.md](ui-parity.md) |
|
||||
| 13 | **3D model formats and materials** | After Effects 26 imports FBX, USD/USDZ, STL besides glTF and OBJ (`usd_plugins`), and Substance 3D materials with mesh displacement (26.0–26.2); we read glTF, OBJ, STL (binary and ASCII, with facet colours) and FBX 7.x (binary and ASCII: meshes, hierarchy, Lambert/Phong materials and textures; no FBX animation or skinning yet) | Product shots and 3D scenes come as FBX/USDZ | 25–45 h | — · [file-format-parity.md](file-format-parity.md) |
|
||||
| 14 | **Object Matte** (26.2, disk cache in 26.5) | First slice (#783): the Object Matte effect (Effect ▸ Matte) and `objectMatte.apply` turn a point (and optional box) on a reference frame into a matte and follow the object up to 600 frames each way, or segment every frame on its own; Roto Brush's engine, cache and model (MobileSAM from Settings ▸ Roto Brush, classical graph cut without it). Since then: the Object Matte tool in the viewer (click / drag a box, hover crosshair), the box as the model's box prompt, background tracking with progress and cancel, Freeze, and segmentations kept in the disk cache (26.5). Missing: a comparison with After Effects ([plan](fidelity/object-matte.md)) | The new one-click roto | 10–20 h | G7 · [target-app-parity.md](target-app-parity.md) |
|
||||
| 15 | **Hardware video decode and encode** | No VideoToolbox, NVENC, Quick Sync or VA-API; #498 asks for it; FilmCraft has VideoToolbox / NVENC / VA-API paths to borrow | 4K playback and export speed | 25–45 h | G5/G6 · [hardware-parity.md](hardware-parity.md) |
|
||||
| 16 | **Localization depth** | Menus in 6 languages; panels in 4; effect names and ~1,650 effect parameter names untranslated; French, German, Korean, Italian, Russian (After Effects ships them) absent; #599 Hangul boxes on macOS | After Effects is used heavily in Japan, China, Korea, Brazil, Europe | 60–110 h + native review | G9 · [localization-parity.md](localization-parity.md) |
|
||||
| 17 | **Media Browser lists files import refuses** | `media_browser.rs` lists TGA, DPX, HDR, AVI, MXF; `media::is_importable` has none of them; #431 any image imports as a sequence; #324 MP3 goes silent | Confusing failures on common VFX formats (DPX, TGA) | 15–30 h | G6 · [file-format-parity.md](file-format-parity.md) |
|
||||
| 17 | **Media Browser lists files import refuses** | `media_browser.rs` lists AVI; `media::is_importable` has none of them (Targa and Radiance HDR import since #745; DPX and Cineon since #756, log shown as stored: no Cineon Settings conversion yet; MXF OP1a / OP-Atom since #767; FilmCraft has no AVI demuxer); #431 any image imports as a sequence; #324 MP3 goes silent | Confusing failures on common VFX formats | 15–30 h | G6 · [file-format-parity.md](file-format-parity.md) |
|
||||
| 18 | **Relative paths and relinking** | Projects store absolute footage paths; no relink when a project moves | Moving or sharing a project breaks it | 6–12 h | G4 · [file-format-parity.md](file-format-parity.md) |
|
||||
| 19 | **Plug-in ecosystem** | No After Effects SDK hosting (#600, #327 OpenFX, #334, #376 plug-in manager); our WebAssembly API has no third-party plug-ins | Many pro projects depend on Trapcode, Element, Saber… | 40–80 h for API growth; SDK hosting needs an owner decision | G8 · [scripting-parity.md](scripting-parity.md) |
|
||||
| 20 | **Multi-monitor and video output** | #486 multi-screen, floating panels on other screens, Mercury Transmit to video hardware (we have a second preview window only) | Two-screen setups are standard for professionals | 10–20 h | G2 · [hardware-parity.md](hardware-parity.md) |
|
||||
| 21 | **Small 26.x features** | Proportional Scrubbing (26.2), copy frame to clipboard and paste SVG/AI as shapes (26.3), variable-font filter (26.3), percentage guides and effect colour labels (26.5), the rebuilt Effect Controls (26.5) | Users of the current version expect them | 15–25 h | — · [ui-parity.md](ui-parity.md) |
|
||||
| 22 | **Encoder efficiency** | HEVC / AV1 have no B-frames, multi-reference or SAO / CDEF; Opus no FEC / DTX; #372 uncompressed single-file output; #325 render over existing file | Larger files than After Effects + Media Encoder | 20–40 h | G6 · [file-format-parity.md](file-format-parity.md) |
|
||||
| 20 | **Multi-monitor and video output** | #486: any panel can move into a native window of its own (panel menu ▸ Move Panel to New Window, `window.panelWindow`) and so onto another screen, restored with the workspace; still missing: dragging tabs between those windows, app shortcuts while one has the focus, named workspaces remembering them, Mercury Transmit to video hardware (we have a second preview window only) | Two-screen setups are standard for professionals | 10–20 h | G2 · [hardware-parity.md](hardware-parity.md) |
|
||||
| 21 | **Small 26.x features** | Proportional Scrubbing (26.2), pasting Illustrator's own clipboard data as shapes (26.3; SVG markup on the clipboard pastes as a shape layer, #738), variable-font filter (26.3), percentage guides and effect colour labels (26.5), the rebuilt Effect Controls (26.5) | Users of the current version expect them | 15–25 h | — · [ui-parity.md](ui-parity.md) |
|
||||
| 22 | **Encoder efficiency** | HEVC / AV1 have no B-frames, multi-reference or SAO / CDEF; Opus no FEC / DTX; single-file intermediates are 8-bit uncompressed QuickTime only (#372: no 16-bpc, AVI or lossless-compressed codec); #325 render over existing file | Larger files than After Effects + Media Encoder | 20–40 h | G6 · [file-format-parity.md](file-format-parity.md) |
|
||||
| 23 | **Essential Graphics interchange** | Templates are `.ectemplate`, not `.mogrt`; #338 Scale exposes X and Y; #611 FilmCraft rejects exported `.fcgt` | Premiere editors can't use our templates | 15–30 h | — · [file-format-parity.md](file-format-parity.md) |
|
||||
| 24 | **Timeline depth requests** | #601 expand precomps in place, #602 reorderable render stack, #604 guide-only effects, #355 bulk keyframes, #425 keyframe confusion, #428 more shortcuts | Power-user speed | 15–30 h | G2 · [ui-parity.md](ui-parity.md) |
|
||||
| 25 | **Accessibility** | AccessKit is enabled in eframe and tests read focus labels, but no screen-reader pass, keyboard navigation audit or contrast check | Excludes users; After Effects supports screen readers poorly too | 15–30 h | G9 · [ui-parity.md](ui-parity.md) |
|
||||
| 25 | **Accessibility** | AccessKit is enabled in eframe and tests read focus labels; the Project panel has After Effects' arrow-key navigation and named, stateful AccessKit nodes (#776), but the other panels have had no screen-reader pass or keyboard navigation audit, and there is no contrast check | Excludes users; After Effects supports screen readers poorly too | 15–30 h | G9 · [ui-parity.md](ui-parity.md) |
|
||||
|
||||
## Where we're going: workstreams in priority order
|
||||
|
||||
@@ -129,6 +129,27 @@ The most important missing piece: it turns every other estimate here into a meas
|
||||
the prompt, with their layers, in one undo step, for single items, multiple selections and
|
||||
folder contents. Nothing happens with an empty selection, in other panels, while typing or with
|
||||
a dialog open, and the next Delete still asks.
|
||||
- Regression evidence for [#612](https://github.com/storytold/effectcraft/issues/612): the
|
||||
`ui_gradient_value` and `ui_gradient_editor` input tests, checked headlessly on Windows, open
|
||||
the Gradient Editor from the Timeline's "Edit Gradient…" on a shape layer's Gradient Fill. They
|
||||
check that OK sets the edited stops (added, dragged, recoloured in the picker, down to a single
|
||||
colour stop) in one undo step, at the composition time the editor opened (also on offset and
|
||||
stretched layers), and that OK without a change, Cancel and Escape change nothing; Escape with
|
||||
the picker open closes only the picker. On an animated gradient only the keyframe at that time
|
||||
changes, with a warning when its stop counts no longer match a neighbour's. Delete never
|
||||
removes the last stop, a layer or a stop while typing; a stop moved past another by its
|
||||
Location keeps its selection and fields; a layer deleted while editing is reported; and
|
||||
`prop.editGradient` is an error for a target that isn't a gradient. Unit tests in `keyframe`
|
||||
and `gradient_editor` cover per-track sampling (no double opacity), the typed one-stop round
|
||||
trip, and stops staying in order, and selected, while they move. The `ui_gradient_handles`
|
||||
tests, checked headlessly on Windows, drag a selected Gradient Fill's start and end points in
|
||||
the Composition viewer: one undo step, the layer stays, a point inside a moved and scaled group
|
||||
converts to the group's space, and the handles show only for a selected gradient.
|
||||
- Regression evidence for the toolbar's gradient swatches (#612, reported on Discord): the
|
||||
`ui_toolbar_gradient` input tests, checked headlessly on Windows, click a Linear Fill swatch and
|
||||
a Radial Stroke swatch on a selected shape layer and get the Gradient Editor on its Gradient Fill
|
||||
/ Gradient Stroke Colors (OK saves); without such a gradient the swatch still opens the options,
|
||||
and the words, Solid swatches and Alt-click are unchanged.
|
||||
- Regression evidence for the reports of 6 October, checked headlessly on Windows: real pointer
|
||||
drags in `ui_drag_drop` (Project items into the Timeline between layers and at a time, and onto
|
||||
the viewer; an effect onto a layer in the viewer: #85, #88, #89), `ui_render_queue` (a template
|
||||
@@ -198,7 +219,12 @@ Issues #41–#47 (all from the Linux AppImage 0.1.1, 5 October): panning the vie
|
||||
gate is a P0.
|
||||
- Fuzz the inputs we don't control: project files, imported media and documents, expressions,
|
||||
scripts, control-channel and MCP requests. Every crash found becomes a regression test
|
||||
(AGENTS.md "Never crash").
|
||||
(AGENTS.md "Never crash"). Project files are fuzzed (#779): a seeded, dependency-free mutation
|
||||
fuzzer runs in `cargo test -p effectcraft-engine` (`fuzz_file_open_never_crashes`, `.ecproj`
|
||||
JSON and `.ecprojx` XML through File ▸ Open, the first queries and a thumbnail render; longer
|
||||
runs via `EFFECTCRAFT_FUZZ_ITERS` / `EFFECTCRAFT_FUZZ_SECS`). It found one crash, deeply nested
|
||||
XML overflowing the stack, now refused. Imported media and documents, expressions, scripts and
|
||||
control-channel / MCP requests are still to do.
|
||||
- Run the gate on every pull request in CI (gap 4): today no workflow runs the tests on PRs.
|
||||
- Fix the open crash reports first (gap 3).
|
||||
- Done when: the gate is green on stable, runs on every pull request, and the fuzzers run
|
||||
|
||||
@@ -22,7 +22,7 @@ monitors are missing, and two GPU start-up failures are open.
|
||||
| Video output devices | Mercury Transmit to AJA, Blackmagic, second display | second preview window only (Video Preview) | same | same | — | No SDI/HDMI device output |
|
||||
| HDR display | HDR monitoring on EDR / HDR displays | tone-mapped SDR view; no EDR output | no HDR output | no | no | Colour engine handles HDR maths (Rec. 2100 PQ/HLG output files) |
|
||||
| Pen tablets (pressure, tilt) | yes, for Paint and Roto | Brushes panel has pressure options, but no tablet pressure is read | same | same | same | Paint strokes store pressure per vertex; input never fills it |
|
||||
| Multiple monitors | panels and windows across screens | floating panels within one window only | same | same (#486) | — | gap 20 |
|
||||
| Multiple monitors | panels and windows across screens | panels move into their own native windows on any screen (Move Panel to New Window; desktop builds) | same | same (#486) | — | gap 20 |
|
||||
| Touch / trackpad gestures | pinch zoom in viewers | egui pointer and scroll; no pinch-to-zoom audited | — | — | — | — |
|
||||
| Audio hardware | Core Audio / ASIO / WASAPI, device choice, latency | cpal output; preview sound late on Linux (#554) and after a start offset (#504) | cpal | cpal (ALSA) | Web Audio | No input or device latency settings |
|
||||
| Machine learning acceleration | Apple Neural Engine / GPU for Object Matte, Roto Brush 3 | CPU inference (pure Rust, rayon) | CPU | CPU | CPU | No GPU inference for MobileSAM or MediaPipe |
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Localization parity
|
||||
|
||||
> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-10-10 · **Change:** major (first measurement of every catalog against the After Effects 2026 26.5 language set) · **Target:** Adobe After Effects 2026
|
||||
> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-10-11 · **Change:** minor (Ukrainian panel catalog recounted after it caught up with the Chinese ones) · **Target:** Adobe After Effects 2026
|
||||
|
||||
How much of EffectCraft's interface is translated, language by language, compared with After
|
||||
Effects. [gaps.md](gaps.md) gap 16 and workstream G9 hold the work;
|
||||
@@ -22,7 +22,7 @@ interface; Arabic and Hebrew text *in layers* is supported through its Middle Ea
|
||||
**618** fixed entries. The generated Effect menu (effect names) is deliberately left in English.
|
||||
- **Panels, dialogs, buttons, tooltips:** `crates/ui-egui/src/i18n/ui.rs`, keyed by the English
|
||||
source string, with English fallback. Catalogs exist for Japanese, Simplified and Traditional
|
||||
Chinese and Ukrainian.
|
||||
Chinese, Ukrainian and Czech.
|
||||
- **Not translated anywhere yet:** effect names and their ≈ 1,650 parameter names
|
||||
(`crates/effects`), engine-generated text (property names, errors, undo labels), the Home
|
||||
screen's unwrapped literals (#574), Learn tutorials and documentation.
|
||||
@@ -60,12 +60,13 @@ the true percentages are slightly lower.
|
||||
| Korean | `ko` | 0 | — | No Hangul fallback probe: boxes on macOS (#599) | no | none | 9–13 h + review |
|
||||
| Vietnamese | `vi` | 0 | — | Latin with stacked diacritics; untested | no | none (After Effects: none) | 8–12 h + review |
|
||||
|
||||
Other languages EffectCraft ships (2):
|
||||
Other languages EffectCraft ships (3):
|
||||
|
||||
| Language | Code | UI strings translated | Status | To `full` |
|
||||
|---|---|---|---|---|
|
||||
| Traditional Chinese | `zh-hant` | 1,081 (≈ 28%): menus 618/618, panels 463 | partial | 6–9 h + review |
|
||||
| Ukrainian | `uk` | 1,015 (≈ 26%): menus 618/618, panels 397 | partial | 6–9 h + review |
|
||||
| Ukrainian | `uk` | 1,113 (≈ 29%): menus 618/618, panels 495/496 | partial | 6–9 h + review |
|
||||
| Czech | `cs` | 1,114 catalog entries (≈ 29%): menus 618/618, panels 496/496 (current Chinese catalog); added after the measurement above | All existing catalog entries covered; unwrapped UI, effects and engine text still in English; AI-assisted, not yet native-speaker proofread | Remaining strings + independent native review |
|
||||
|
||||
After Effects also ships Italian and Russian, which EffectCraft does not (8–12 h each).
|
||||
|
||||
@@ -87,3 +88,4 @@ can give; none has had it.
|
||||
| Date | Change | Summary |
|
||||
|---|---|---|
|
||||
| 2026-10-10 | major | First localization parity document: catalog rows counted for all six languages, the twelve-language table, After Effects' 11 shipped languages from its bundle |
|
||||
| 2026-10-11 | minor | Ukrainian panel catalog brought level with the Chinese ones (495 of 496 rows, counted at this commit); its share rises to ≈ 29%. The other languages' panel counts are the 10 October measurement |
|
||||
+7
-4
@@ -14,7 +14,7 @@ Guide):
|
||||
| Effect plug-ins (C/C++ SDK, `.aex` / `.plugin`) | [Effect plug-ins](#effect-plug-ins): WebAssembly modules (plug-in API v1) or Rust; the `Plug-ins` folder next to the settings loads at start-up | Different ABI: After Effects SDK plug-ins can't run (G8) |
|
||||
| Scripts folder: its scripts are listed in File ▸ Scripts | `Scripts/` in the settings folder (File ▸ Scripts ▸ Install Script File… copies a script there), listed in File ▸ Scripts with the bundled samples | Same |
|
||||
| File ▸ Scripts ▸ Run Script File… (`.jsx`, `.jsxbin`) | `.jsx` / `.js` | Gap: `.jsxbin` (an undocumented binary encoding) |
|
||||
| ExtendScript preprocessor directives (`#include`, `#target`, `#targetengine`) | Not understood: a script that starts with one doesn't parse | Gap |
|
||||
| ExtendScript preprocessor directives (`#include`, `#target`, `#targetengine`) | `#include` / `//@include` / `#includepath` inline files relative to the script (once each, depth-limited, file gate applies); `#target`, `#targetengine`, `#strict` are ignored | Same |
|
||||
| `Scripts/Startup` and `Scripts/Shutdown`: run in alphabetical order when the app starts and quits | Not run | Gap |
|
||||
| `Scripts/ScriptUI Panels`: listed at the bottom of the Window menu, dockable like the app's own panels, `this` is the panel | `Scripts/ScriptUI Panels/` in the settings folder (File ▸ Scripts ▸ Install ScriptUI Panel… copies one there), listed at the bottom of the Window menu, docked like any panel, `this` is the panel; the panels open when the app quits open again at the next launch | Same. Where a panel was docked isn't kept: workspace layouts aren't saved between launches |
|
||||
| Keyboard shortcuts for scripts (the Keyboard Shortcuts editor lists the scripts of the Scripts folder) | Shortcuts bind to commands and menu entries; the File ▸ Scripts and Window menu entries of scripts aren't offered | Gap |
|
||||
@@ -84,9 +84,12 @@ Supported controls: `panel`, `group`, `button`, `iconbutton`, `statictext`, `edi
|
||||
`tabbedpanel` / `tab` and `image`, with ScriptUI's automatic layout (`orientation`,
|
||||
`alignChildren`, `alignment`, `margins`, `spacing`, `preferredSize`), resource strings, event
|
||||
handlers (`onClick`, `onChange`, `onChanging`, `onClose`, `addEventListener`) and `onDraw` with
|
||||
ScriptUIGraphics. Mouse events (`mousedown`, `mousemove`…) aren't sent to scripts yet. Agents use
|
||||
a panel like a user: `scriptui.list`, `scriptui.get` (its controls), `scriptui.click`,
|
||||
`scriptui.set` and `scriptui.close`; every control has the automation id
|
||||
ScriptUIGraphics. Mouse events (`addEventListener("mousedown" | "mouseup" | "mousemove" |
|
||||
"mouseover" | "mouseout" | "click", handler, capture?)`) reach the control under the pointer and
|
||||
its containers (capture, target, bubble; `stopPropagation()`), with a MouseEvent carrying
|
||||
`clientX`/`clientY` relative to the target, `button`, `detail` (click count) and the modifier
|
||||
keys. Agents use a panel like a user: `scriptui.list`, `scriptui.get` (its controls),
|
||||
`scriptui.click`, `scriptui.set`, `scriptui.mouse` and `scriptui.close`; every control has the automation id
|
||||
`scriptui.<window>.<control id or name>`. The bundled sample `Layer Tools.jsx`
|
||||
(`crates/engine/scripts/ScriptUI Panels/`) and the Ease Presets extension below are longer
|
||||
examples.
|
||||
|
||||
+21
-3
@@ -57,10 +57,12 @@ Commands (CLI, MCP, control channel):
|
||||
- `appearance.appearanceMode`: Appearance Mode (`auto` / `dark` / `light`). `auto` (Sync with System) follows the operating system's light or dark appearance while the app runs: on Linux the desktop app reads the XDG desktop portal (`org.freedesktop.appearance` `color-scheme`) once and then listens for its `SettingChanged` signal on a worker thread, repainting only when the value changes (nothing polls); `gsettings` runs at most once at start-up, by absolute path, when the portal gives no answer. Elsewhere it uses what the window system reports. With no answer it shows the dark theme. New installs stay `dark`; Sync with System is opt-in. The Tools bar's appearance button (a monitor, sun or moon) cycles Sync with System, Light and Dark (`view.theme.toggle`, Next Appearance Mode).
|
||||
- `appearance.darkTheme`: Dark Theme (`dark` / `darker`), shown in dark appearance
|
||||
- `appearance.lightTheme`: Light Theme (`light`), shown in light appearance. Settings ▸ Appearance shows the mode above a light and a dark theme card, each with a preview of the EffectCraft window in that theme.
|
||||
- `appearance.favoriteThemes`: a list of unique theme ids (`dark`, `darker`, `light`), empty by default. Hover a theme row to star it; saved favorites keep an accent-colored star. Right-click the appearance button for Appearance Settings and favorites grouped light first, then dark. Selecting a favorite fixes its appearance family and preserves the opposite family choice; left-click still cycles modes. Settings OK saves favorites and Cancel restores them. Unknown or duplicate ids are rejected by `prefs.set` and removed when loading old settings.
|
||||
- `appearance.theme`: the single theme from before appearance modes, kept for older settings files and automation. A saved file with only `theme` loads as a fixed Dark or Light mode showing it; setting it (`prefs.set`, `ui.set {"theme": …}`, `view.theme.dark|darker|light`) selects that theme and fixes the mode to its family. While the mode is Dark or Light it mirrors the theme in use.
|
||||
- `appearance.brightness`: Brightness
|
||||
- `appearance.uiScale`: UI Scale, the size of the whole interface (75–200 %, on top of the
|
||||
display's own scaling), applied as soon as it is chosen
|
||||
- `appearance.uiScale`: UI Scale, the size of the whole interface (any whole percentage from
|
||||
75 to 200, on top of the display's own scaling), dragged or typed; it applies as soon as it is
|
||||
dragged or entered
|
||||
- `appearance.useLabelColorForHandles`: Use Label Color for Layer Handles and Paths
|
||||
- `grids.gridColor`: Color
|
||||
- `grids.gridSpacing`: Gridline Every
|
||||
@@ -94,7 +96,9 @@ Commands (CLI, MCP, control channel):
|
||||
how much of a position motion path the viewer draws (all, none, N seconds or N keyframes
|
||||
around the current time)
|
||||
- `previews.showInternalWireframes`: outlines of the layers inside a selected collapsed precomp
|
||||
- `previews.zoomQuality`: Faster = nearest-neighbour viewer scaling, More Accurate = bilinear
|
||||
- `previews.zoomQuality`: Faster = nearest-neighbour viewer scaling, More Accurate = averaged
|
||||
(bilinear, mipmapped) when the frame is shown below 100 %; magnified frames show their pixels as
|
||||
blocks in both modes, and the frame sits on the physical pixel grid, so 100 % is exact
|
||||
- `previews.displayProfile`: the monitor's colour space for View ▸ Use Display Color Management
|
||||
- `appearance.useLabelColorForTabs`: Composition / Timeline tabs show the comp's label colour,
|
||||
Effect Controls / Properties the layer's
|
||||
@@ -223,3 +227,17 @@ checkpoint after a client restart.
|
||||
|
||||
Commands: `file.autoSave` (now), `file.recoveryInfo`, `file.openRecent {index? | path?}`,
|
||||
`file.clearRecent`, `file.revert`, `file.incrementAndSave`.
|
||||
|
||||
## Logs
|
||||
|
||||
The desktop app writes its log records to standard error and to `Logs/effectcraft.log` in the
|
||||
config directory. Each launch moves the previous log to `effectcraft.1.log` (and that one to
|
||||
`effectcraft.2.log`), so the log of a run that crashed survives the next start; a log stops
|
||||
growing at 16 MiB. A launch from the Dock, the Start menu or a launcher has no terminal, so
|
||||
attach these files to a bug report. Help ▸ Reveal Logging File shows this run's log (or Help ▸
|
||||
Enable Logging's `EffectCraft Log.txt` while that is on, which keeps every EffectCraft record
|
||||
across launches).
|
||||
|
||||
By default the log has `info` records from EffectCraft and warnings and errors from everything
|
||||
else. `RUST_LOG` replaces that with env_logger-style directives: `debug`,
|
||||
`warn,effectcraft_render=trace`, `wgpu_core=info`. The control-channel token is never logged.
|
||||
@@ -18,11 +18,13 @@ our own scripts; no real-world script library has been run against both apps.
|
||||
| Expression object model | `thisComp`, `thisLayer`, `wiggle`, `loopOut`, `valueAtTime`, `sampleImage`, `footage()`, text style API… | Same members, from the reference | good | `crates/expr/src/tests.rs`; behaviour of edge cases unmeasured (G1) |
|
||||
| Expression editing | Inline field, error bar, pick whip, Expression Language menu, external editors | Inline field that grows, error bar, pick whips (property and value), language menu | partial | External editor support (#364) |
|
||||
| Expression performance | Cached, multi-frame | Per-thread boa contexts | unknown | No benchmark |
|
||||
| Scripting object model | `app`, `Project`, items, layers, properties, keys, eases, render queue, `TextDocument`, `Shape`, markers, `File`/`Folder`, `Socket`, `app.settings` | Same classes, edits run through undoable engine commands; match names table | good | `crates/script` tests (≈ 10 test files) |
|
||||
| ScriptUI | Dialogs, palettes, dockable panels, resource strings, `onDraw` / ScriptUIGraphics | Same, dockable panels reopen at launch | good | `ui_scriptui`, `tests_ui*` |
|
||||
| Scripting object model | `app`, `Project`, items, layers, properties, keys, eases, render queue, `TextDocument`, `Shape`, markers, `File`/`Folder`, `Socket`, `app.settings` | Same classes, edits run through undoable engine commands; match names table; layers, groups and properties are callable (`layer("Effects")(1)` is `.property(...)`) | good | `crates/script` tests (≈ 10 test files) |
|
||||
| `$.evalFile`, `BridgeTalk` | Evaluate another script file; identify the host application and message other Adobe applications | `$.evalFile` evaluates a file relative to the calling file (nested at most 32 deep, under the scripts' file gate) and returns its last value; `BridgeTalk` names the host honestly (`appName` `effectcraft`, its version); messaging other applications throws "not supported" | partial | `tests_evalfile.rs` (#760); no inter-application messaging |
|
||||
| ScriptUI | Dialogs, palettes, dockable panels, resource strings, `onDraw` / ScriptUIGraphics, mouse events | Same, dockable panels reopen at launch | good | `ui_scriptui`, `tests_ui*` |
|
||||
| `app.scheduleTask` / `cancelTask` | One-shot and repeating tasks (polling, panel refresh) until `cancelTask` | Same: repeating tasks run every `delay` ms (at least 50 ms, at most 64 pending per script) until `cancelTask`, until they throw (reported once, then cancelled), or until their owner goes: a script's last window closing, or the project closing for scripts without windows; frontends tick them every frame, agents with `script.runTasks` | good | `tests_tasks.rs` (#773); one-shot tasks of a script file still run right after it, not after their delay |
|
||||
| Scripts menu, ScriptUI Panels folder | yes | yes | same | [plugins.md](plugins.md) |
|
||||
| Startup / Shutdown folders | yes | not run | missing | plugins.md |
|
||||
| `#include`, `#target` directives | yes | a script starting with one doesn't parse | missing | plugins.md; common in real scripts |
|
||||
| `#include`, `#target` directives | yes | `#include` / `//@include` / `#includepath` inline files relative to the including script (once each, nested at most 32 deep, under the scripts' file gate; errors name the included file and line); `#target`, `#targetengine`, `#strict` are ignored | good | `tests_include.rs` (#759); installed scripts and panels have no folder of their own, so they include from the project's folder or absolute paths |
|
||||
| `.jsxbin` | yes | no | out of scope | No public specification |
|
||||
| Keyboard shortcuts for scripts | yes | no | missing | plugins.md |
|
||||
| Command-line rendering `aerender` | yes | `effectcraft-cli render`, `script`, `exec` | same purpose | `apps/effectcraft-cli` |
|
||||
|
||||
@@ -681,8 +681,15 @@ Fixes from measured reports:
|
||||
too large (#390).
|
||||
- The viewer's Auto resolution renders the pixels the magnification needs (Full above 50 %), and
|
||||
frames shown below 100 % are averaged (GPU frames through mip levels, CPU frames by a whole
|
||||
factor) instead of minified bilinearly (#417). Not yet: the viewer resolution and magnification
|
||||
are not remembered between launches.
|
||||
factor) instead of minified bilinearly (#417).
|
||||
- Each composition keeps its Resolution (Auto, Full, Half, Third, Quarter or Custom) in the
|
||||
project, as in After Effects: switching to another comp and back, or saving and reopening the
|
||||
project, shows the same resolution. Changing it marks the project modified but adds no undo
|
||||
step (undo and redo keep it) and keeps the comp's cached frames; projects saved before open
|
||||
with Auto. View ▸ Resolution and the panel's popup run `view.res.full|half|third|quarter|auto`
|
||||
and `view.res.custom {factor}`, which now work headless too; `comp.info` reports `resolution`
|
||||
and `resolutionFactor` (#417). Not yet: the magnification is not saved per comp, and the
|
||||
Composition Settings dialog has no Resolution popup.
|
||||
|
||||
### Update: plug-ins and extensions as in After Effects; ease presets become a ScriptUI panel
|
||||
|
||||
@@ -889,7 +896,11 @@ saved warns that what this version doesn't know is lost on saving (`file.open` r
|
||||
`savedBy`). Saving checks that the file reads back first, so a value JSON can't hold (NaN)
|
||||
fails the save with a message instead of writing a project that can never be opened (the file
|
||||
on disk is left as it was). Increment and Save and Save a Copy keep an XML project (`.ecprojx`)
|
||||
XML; a file that isn't a project says so by name.
|
||||
XML; a file that isn't a project says so by name. A corrupt or hostile project opens within the
|
||||
limits the commands use (#788): compositions, solids and footage at most 30,000 × 30,000 px (as in
|
||||
After Effects), frame rates 0.001–1000 fps, pixel aspect 0.1–10, compositions at least one frame
|
||||
long and 2–64 motion-blur samples; `file.open` lists what it corrected (`repaired`) and a toast
|
||||
names it.
|
||||
|
||||
### Update: M3.13 menu bar
|
||||
|
||||
|
||||
+4
-4
@@ -17,8 +17,8 @@ feel and platform differences, and the 26.x interface changes are not in yet.
|
||||
|---|---|---:|---|
|
||||
| Menu bar | After Effects' menus, order, submenus and labels; native on macOS; keyboard-operable in-window bar | 95% | 587 entries in `crates/engine/src/menus.rs`; Adobe-service entries omitted by design; `ui_menus` tests (#279) |
|
||||
| Panels and workspaces | Every After Effects panel; all standard workspaces; drag-to-dock, tabs, floating panels, maximise | 75% | `ui_tabs`, `ui_panels`; dropping a panel on a stacked panel doesn't make a tab (#302); stacked-panel headers (#301); saved workspaces don't persist (#320); no panels on a second monitor (#486) |
|
||||
| Timeline | Switches, modes, parent & link, twirl-downs, reveal shortcuts (U, UU, P, S, R, T, A, E, M, F, Alt+Shift…), pick whips, graph editor, work area, markers | 75% | `ui_keyframes`, `ui_timeline_*`; Graph Editor jitter and hidden buttons (#456, #457); rotation can't go negative by dragging (#569); bulk keyframing (#355); expand precomps in place (#601); Proportional Scrubbing (26.2) missing |
|
||||
| Composition viewer | Selection, handles with direction-aware cursors, rulers, guides, grids, snapping, channels, exposure, region of interest, snapshots, 3D views, Spacebar hand | 70% | `ui_viewer`, `ui_viewers`; Cmd/Ctrl +/− doesn't zoom (#570); inaccurate snapping (#352); anchor point grab on Linux (#492); no 3D transform gizmos (#392, #347); percentage guides (26.5); copy frame to clipboard (26.3) |
|
||||
| Timeline | Switches, modes, parent & link, twirl-downs, reveal shortcuts (U, UU, P, S, R, T, A, E, M, F, Alt+Shift…), pick whips, graph editor, work area, markers | 75% | `ui_keyframes`, `ui_timeline_*`; Graph Editor jitter and hidden buttons (#456, #457); rotation can't go negative by dragging (#569); bulk keyframing (#355); expand precomps in place (#601); Proportional Scrubbing (26.2: Ctrl+Alt / Cmd+Opt scrub of hot text spreads the change over the selected layers by selection order, #770) matched for layers selected as a whole, not yet for individually selected properties |
|
||||
| Composition viewer | Selection, handles with direction-aware cursors, rulers, guides, grids, snapping, channels, exposure, region of interest, snapshots, 3D views, Spacebar hand | 70% | `ui_viewer`, `ui_viewers`; Cmd/Ctrl +/− doesn't zoom (#570); inaccurate snapping (#352); anchor point grab on Linux (#492); no 3D transform gizmos (#392, #347); percentage guides (26.5); Copy Frame to Clipboard (26.3) is in the Composition menu and the viewer's context menu |
|
||||
| Tools panel | All After Effects tools; long-press flyouts; Tool Creates Shape / Mask; Fill / Stroke options | 80% | #213, #227 fixed; pen and vertex tools on motion paths (#553) |
|
||||
| Nudging and modifiers | Arrow nudge (1 px, Shift 10 px), Alt/Option duplicates and slips, Shift constrains | 75% | #290 nudging fixed; Linux multi-layer edits (#491) |
|
||||
| Numeric entry | Scrubbable values, typed entry with Tab / Shift+Tab, angle revolutions, Escape cancels, non-finite rejected | 85% | `ui_angles`, `ui_inline_edit` (#93, #141, #361); rename arrows on Linux (#488) |
|
||||
@@ -26,11 +26,11 @@ feel and platform differences, and the 26.x interface changes are not in yet.
|
||||
| Context menus | Layer, property, Project, Timeline empty area, work area, labels with colours | 80% | `ui_blank_context_menus`; #227, #290, #407 fixed |
|
||||
| Keyboard shortcuts | After Effects' defaults; Keyboard Shortcuts editor that rebinds and saves sets | 75% | Shortcut editor in Settings; adding shortcuts fails on Linux (#467); requests for more (#428, #336); no shortcuts for scripts |
|
||||
| Drag and drop | Project → Timeline / viewer / New Comp / Render Queue; effects onto layers; files from the OS | 65% | `ui_drag_drop`; OS drops fail on Wayland (winit) and some Linux setups (#268); multi-file drops (#552, #351); crash dragging over the import dialog (#511) |
|
||||
| Text editing on canvas | Point and paragraph text, per-character styles, Character / Paragraph panels, OpenType and variable axes | 70% | `ui_text_edit`; paragraph alignment inverted (#316); font search by typing (#583); toolbar font options (#550); variable-font filter (26.3) |
|
||||
| Text editing on canvas | Point and paragraph text, per-character styles, Character / Paragraph panels, OpenType and variable axes | 70% | `ui_text_edit`, `ui_font_search`; paragraph alignment inverted (#316); font search by typing (#583); toolbar font options (#550); the font menus' variable-font filter (26.3) landed (#741) |
|
||||
| Preview feel | Spacebar / Numpad 0 previews, RAM preview, cache bars, adaptive resolution | 55% | `ui_ram_preview`, `ui_live_preview`; stutter (#595, #304), scrubbing lag (#329), Shift+Space default (#551) |
|
||||
| Home screen, Learn, templates | Home with recent projects, template gallery, interactive Learn tutorials | 70% | Layout nitpicks (#581); Home literals untranslated (#574) |
|
||||
| Quick Apply (26.2) | Search to apply effects, presets or commands | partial | A command palette exists; not After Effects' Quick Apply |
|
||||
| Accessibility | AccessKit enabled; focus labels tested | 20% | No screen-reader pass, keyboard-navigation audit or contrast check |
|
||||
| Accessibility | AccessKit enabled; focus labels tested; Project panel keyboard navigation and accessible names (#776) | 20% | No screen-reader pass or keyboard-navigation audit of the other panels; no contrast check |
|
||||
| UI scale | Settings ▸ Appearance ▸ UI Scale 75–200% | beyond | After Effects follows the system's scaling (#284) |
|
||||
|
||||
## Estimate
|
||||
|
||||
Reference in new issue
Block a user