M0.11: ROADMAP, CONTRIBUTING, docs/architecture and docs/testing
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
1e8768ad18
commit
c9f6f9e3be
|
|
@ -73,7 +73,7 @@ a command, everything is agent-drivable, and the quality gates (`cargo xtask ci`
|
|||
|
||||
## See also
|
||||
|
||||
- [CONTRIBUTING.md](CONTRIBUTING.md) and [docs/contributing.md](docs/contributing.md): setup, gates, commits, how to add things
|
||||
- [CONTRIBUTING.md](CONTRIBUTING.md): setup, gates, commits, how to add things
|
||||
- [docs/architecture.md](docs/architecture.md): layers, data model, commands, pipeline
|
||||
- [docs/testing.md](docs/testing.md): oracle tests, criteria, benchmarks
|
||||
- [docs/agents.md](docs/agents.md): driving EffectCraft over MCP / the control channel, and the agent work loop
|
||||
|
|
|
|||
|
|
@ -0,0 +1,42 @@
|
|||
# Contributing to EffectCraft
|
||||
|
||||
Thanks for helping. Please read [AGENTS.md](AGENTS.md) first: its rules on assets and clean-room
|
||||
work apply to everyone, people and AI agents alike, and they are not negotiable.
|
||||
|
||||
## Setup
|
||||
|
||||
You need [Rust](https://rustup.rs/) 1.95 or newer.
|
||||
|
||||
```sh
|
||||
cargo run -p effectcraft # the desktop app, with the demo project
|
||||
cargo test --workspace
|
||||
cargo xtask ci # what every commit must pass
|
||||
```
|
||||
|
||||
## Ground rules
|
||||
|
||||
- **Clean room.** Work from After Effects' public documentation and its observable behaviour only.
|
||||
Never use Adobe artwork, presets or code, and never copy GPL/LGPL/AGPL code.
|
||||
- **Every asset is attributed.** Add a `.attribution` sidecar and an [ATTRIBUTION.md](ATTRIBUTION.md)
|
||||
row; `cargo xtask assets` checks it.
|
||||
- **Layering.** Nothing below the interface layer depends on UI or OS crates; see
|
||||
[docs/architecture.md](docs/architecture.md).
|
||||
- **Everything is a command.** New features are engine commands with an id, label, menu path,
|
||||
shortcut and parameters, so the UI, the CLI and the MCP server get them at once. Interactive
|
||||
widgets register an automation id.
|
||||
- **Tests with every change**, and green `cargo xtask ci` before every commit. One task per commit.
|
||||
|
||||
## How to add…
|
||||
|
||||
- **An effect:** add an `EffectSpec` in `crates/effects` (AE display name, category, parameters
|
||||
with AE's names, defaults and ranges) and its render function, with a determinism test and a
|
||||
behaviour test. If it reads the clock directly, add it to `TIME_DEPENDENT`.
|
||||
- **A command:** register it with `cmd!` in `crates/engine/src/commands/`, place it in the menu
|
||||
tree in `crates/engine/src/menus.rs`, and test it including undo.
|
||||
- **A panel or dialog:** `crates/ui-egui/src/panels/`; look at the result with the headless
|
||||
snapshot tool described in [docs/testing.md](docs/testing.md).
|
||||
|
||||
## Talk to us
|
||||
|
||||
Questions, ideas and bug reports are welcome on [Discord](https://discord.gg/artcraft) and in
|
||||
GitHub issues.
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
# Roadmap
|
||||
|
||||
EffectCraft aims to do what After Effects does, with the same panels, menus and behaviour, written
|
||||
from scratch in Rust. This is where it stands. The milestones overlap; several are worked on at
|
||||
once.
|
||||
|
||||
| | Milestone | State |
|
||||
|---|---|---|
|
||||
| M0 | Skeleton: crates, compositor, the After Effects style shell, control channel, `cargo xtask` | Done (web build pending) |
|
||||
| M1 | Keyframes: temporal and spatial interpolation, Easy Ease, roving, velocity | Done |
|
||||
| M2 | Compositing: 38 blend modes, track mattes, parenting, adjustment layers | Done |
|
||||
| M3 | Project operations: settings dialogs, layer commands, `.ecproj`, undo, After Effects menu bar | Mostly done |
|
||||
| M4 | Preview: precomps, motion blur, cached playback | Mostly done |
|
||||
| M5 | Timeline depth: graph editor, keyframe clipboard and dialogs, time remapping, pick-whips, expression editor | Done |
|
||||
| M6 | Shapes, masks and footage: shape operators, masks and the pen tool, video and image import | Done |
|
||||
| M7 | 3D: 3D layers, cameras, lights, shadows, depth of field, 3D views and camera tools | In review |
|
||||
| M8 | Expressions with the After Effects object model | Done |
|
||||
| M9 | Text and effects: text animators, 241 effects | In progress (layer styles, more selectors) |
|
||||
| M10 | Export: render queue, H.264, ProRes, image sequences, GIF, audio | Done |
|
||||
| M11 | Animation tools: presets, Motion Sketch, Wiggler, Lottie, audio playback | Next |
|
||||
| M12 | Performance: layer cache and parallel compositing (done), GPU compositing, disk cache, motion tracking | In progress |
|
||||
| M13+ | Time effects, puppet, paint, roto, preferences and shortcut editor, the web app, a plugin API | Planned |
|
||||
| M14 | Built for agents: MCP server, command-line tool, control channel | Done |
|
||||
|
||||
Come tell us what matters most to you on [Discord](https://discord.gg/artcraft).
|
||||
|
|
@ -0,0 +1,89 @@
|
|||
# Architecture
|
||||
|
||||
EffectCraft is a stack of small Rust crates. The engine knows nothing about the user interface;
|
||||
the egui frontend, the command-line tool and the MCP server all sit on top of the same `Session`
|
||||
and drive it through the same command registry.
|
||||
|
||||
## 1. Crates and layering
|
||||
|
||||
Dependencies only point downward (or along the few same-layer edges listed below). `cargo xtask
|
||||
layers` enforces this, and fails the build if a crate below L5 depends on egui, eframe, winit, rfd,
|
||||
cpal or muda. Everything in L0 to L4 also builds for `wasm32-unknown-unknown` (`cargo xtask wasm`).
|
||||
|
||||
| Layer | Crate (`effectcraft-…`) | Responsibility |
|
||||
|---|---|---|
|
||||
| L0 | `time` | `Tick` (254 016 000 000 per second), rational frame rates incl. NTSC, SMPTE and drop-frame timecode |
|
||||
| L0 | `geom` | Vectors, matrices, quaternions, the layer transform (anchor, position, scale, orientation, rotation) |
|
||||
| L0 | `color` | sRGB and linear, HSL/HSV, luminance, the 38 blend modes, label colors |
|
||||
| L1 | `raster` | Premultiplied float images, sampling, affine and projective warps, blurs, compositing (parallel with rayon) |
|
||||
| L1 | `keyframe` | Animated values, keyframes with temporal ease and spatial Bezier, roving, hold, velocity |
|
||||
| L1 | `path` | Bezier paths, path operators (trim, offset, round corners, zig zag, twist, merge…), stroking, coverage masks |
|
||||
| L2 | `project` | The document: items, compositions, layers, the property tree, render queue model, `.ecproj` serde |
|
||||
| L2 | `text` | Fonts, shaping, layout, per-glyph geometry, text animators and selectors |
|
||||
| L2 | `effects` | The effect registry (241 effects) and their CPU implementations |
|
||||
| L3 | `render` | Evaluation and compositing: sources, masks, effects, transforms, 3D, motion blur, mattes, blending, layer cache, audio mixdown |
|
||||
| L3 | `media` | Footage decoding (FilmCraft's pure-Rust codecs), image sequences, frame cache |
|
||||
| L3 | `expr` | The expression engine (JavaScript via boa) with the After Effects object model |
|
||||
| L3 | `export` | Render queue encoding: H.264, ProRes, PNG/JPEG/TIFF/EXR sequences, GIF, audio |
|
||||
| L4 | `engine` | `Session`: project, undo history, editor state, the command registry and menus |
|
||||
| L4 | `host` | A fully wired `Session` (media, expressions, exporter) for the frontends |
|
||||
| L5 | `ui-egui` | The desktop interface: docking, panels, viewer, timeline, graph editor, dialogs, control channel |
|
||||
| L5 | `automation` | The MCP server, headless or bridged to the running app |
|
||||
| L6 | apps `effectcraft`, `effectcraft-cli` | Desktop app; command-line tool (render, exec, get/set, MCP) |
|
||||
|
||||
Allowed same-layer edges: `path → keyframe, raster`, `text → path`, `effects → project, text, path`,
|
||||
`media / expr / export → render`, `export → media`, `host → engine`.
|
||||
|
||||
## 2. Time
|
||||
|
||||
All time is an integer `Tick`, 254 016 000 000 per second, the least common multiple of every
|
||||
broadcast frame rate (×1001) and audio sample rate, so frame and sample positions are exact.
|
||||
Keyframe times are in **layer time**; `layer_time = (comp_time - start_time) / stretch`, and a
|
||||
Time Remap property overrides the source time. Commands snap layer times, keyframe times and
|
||||
comp durations to whole frames, as After Effects does. Timecode is only a display.
|
||||
|
||||
## 3. Document model
|
||||
|
||||
```
|
||||
Project { settings, items, render_queue }
|
||||
Item { id, name, label, parent folder, kind: Folder | Comp | Footage | Solid }
|
||||
Comp { size, pixel aspect, frame rate, duration, start timecode, background, work area,
|
||||
layers (index 0 = layer #1), markers, motion blur shutter, renderer }
|
||||
Layer { id, name, source (footage | comp | solid | text | shape | null | camera | light),
|
||||
in/out/start, stretch, switches, blend mode, track matte, parent, props }
|
||||
```
|
||||
|
||||
Everything animatable is a `Property` in the layer's `PropGroup` tree, addressed by a path such as
|
||||
`transform/position`, `effects/#1/blurriness`, `masks/#1/feather`, or by `@uid`. Effects, masks,
|
||||
text animators and shape contents are groups in the same tree.
|
||||
|
||||
## 4. Rendering
|
||||
|
||||
`Renderer::comp_frame(comp, t)` walks the layers bottom to top. For each visible layer it renders
|
||||
the **source** (solid, footage frame, text, shape contents, or a nested comp), applies **masks**,
|
||||
then **effects** in order, then the **transform** into comp space (with motion blur sub-samples
|
||||
when enabled), the **track matte**, and finally **blends** into the accumulator. Adjustment layers
|
||||
apply their effects to the accumulator. Runs of 3D layers are composited per pixel through the
|
||||
active camera, with lights, shadows and depth of field.
|
||||
|
||||
A **layer cache** keeps each layer's finished pixels (source, masks and effects) keyed by a hash of
|
||||
its evaluated inputs, excluding the transform. Static and transform-only layers render once;
|
||||
editing one layer re-renders only that layer. Effects that read the clock directly are declared in
|
||||
`effects::TIME_DEPENDENT`, and a test checks every registered effect against that list.
|
||||
|
||||
Half, Third and Quarter resolution render proportionally fewer pixels end to end.
|
||||
|
||||
## 5. Expressions
|
||||
|
||||
Expressions are JavaScript, run by boa, with After Effects' object model (`thisComp`, `thisLayer`,
|
||||
`time`, `value`, `wiggle`, `loopOut`, vector maths on arrays, and so on). A syntax error keeps the
|
||||
text, disables the expression and shows a warning, like After Effects.
|
||||
|
||||
## 6. Commands, the UI seam and automation
|
||||
|
||||
Every action is a command: an id, a label, a menu path, a shortcut, a parameter description,
|
||||
`enabled()` and `run()`. The menu bar is a tree of command ids. The desktop UI, the command line,
|
||||
the JSON control channel and the MCP server all dispatch by id, so anything a person can do from a
|
||||
menu, an agent can do too. Every interactive widget registers an automation id, so agents can also
|
||||
inspect and click the interface. See [agents.md](agents.md) and
|
||||
[control-protocol.md](control-protocol.md).
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
# Testing
|
||||
|
||||
```sh
|
||||
cargo test --workspace # everything
|
||||
cargo xtask ci # fmt, clippy -D warnings, tests, layers, assets, wasm
|
||||
```
|
||||
|
||||
## What the tests cover
|
||||
|
||||
- **Engine commands** (`crates/engine/src/tests*.rs`): every command family, including undo and
|
||||
redo, and that every menu entry resolves to a registered command.
|
||||
- **Rendering** (`crates/render`): pixel checks on small compositions, for blend modes, masks,
|
||||
mattes, time remapping, 3D projection, lighting and shadows. Fast paths (the layer cache, the
|
||||
affine compositor, blurs, motion blur accumulation) are checked against their reference
|
||||
implementations.
|
||||
- **Effects** (`crates/effects`): each effect has a determinism test and at least one behaviour
|
||||
test (identity at neutral settings, known pixel results, or simulations giving the same frame
|
||||
whether you seek straight to it or play up to it). A registry-wide test checks that effects
|
||||
which read the clock are declared time-dependent.
|
||||
- **Export** (`crates/export/tests`): every format is encoded and decoded back, checking frame
|
||||
count, size and pixels. When `ffmpeg`/`ffprobe` are installed they are used as an outside
|
||||
check; they are never linked or shipped.
|
||||
- **Automation** (`crates/automation`, `apps/effectcraft-cli/tests`): MCP protocol round trips and
|
||||
the command-line tool's JSON output.
|
||||
- **Interface** (`crates/ui-egui`): headless egui_kittest tests for panels and dialogs.
|
||||
|
||||
## Looking at the interface without a window
|
||||
|
||||
```sh
|
||||
cargo run -p effectcraft-ui-egui --example snapshot -- --out ui.png \
|
||||
--step '{"method":"engine.execute","params":{"command":"layer.select","params":{"layers":["#2"]}}}'
|
||||
```
|
||||
|
||||
Each `--step` is a control-channel request; `{"method":"snap","params":{"path":"x.png"}}` writes an
|
||||
intermediate image.
|
||||
|
||||
## Benchmarks
|
||||
|
||||
```sh
|
||||
cargo run --release -p effectcraft-cli -- bench --n 10 --play 30
|
||||
```
|
||||
|
||||
prints per-layer and per-effect timings for one frame, and playback timings with and without the
|
||||
layer cache.
|
||||
Loading…
Reference in New Issue