mirror of
https://github.com/storytold/effectcraft.git
synced 2026-11-07 02:51:24 +00:00
The blocks come from craft-contrib at dde09ea31e2e457f5b4653a6e76f7cdf55944bdf. CLAUDE.md imports AGENTS.md. The house-rules workflow checks the copy.
211 lines
18 KiB
Markdown
211 lines
18 KiB
Markdown
<!-- craft-house-rules:start core source=dde09ea31e2e457f5b4653a6e76f7cdf55944bdf sha256=540e6cea75d12d0710c3dca89658328e81e508ecef102446ca5bb95b7c0b92bb -->
|
||
## House rules
|
||
|
||
These apply in every Craft repository. A later rule may be stricter, not weaker. The source is `standards/house-rules-core.md` in `storytold/craft-contrib`. Propose changes there, not in a copy.
|
||
|
||
1. **A person is accountable.** Whoever runs an agent answers for what it opens and for its review comments.
|
||
2. **Check, then claim.** Before writing code, read the issue comments, search pull requests for `#N` and the keywords, and check recent commits on `main`. Comment on the issue first. Release a claim you will not finish.
|
||
3. **Verify, don't guess.** Open a definition before using it. Confirm the cause in the code, even when someone names a location.
|
||
4. **Keep fixes narrow and tested.** Fix what the issue describes, where the bug is. Add a test that fails without the fix.
|
||
5. **Review the diff before opening a pull request.** Identifiers exist as used, the test fails without the fix, nothing unrelated changed, and the description is true.
|
||
6. **Look for a better pull request.** If another fixes the same thing, close yours when it is better or equal, and say why.
|
||
7. **Report only what ran.** Say what you tested and what you could not run. Without a local build or test, say so and rely on CI before marking ready.
|
||
8. **`main` changes through a pull request.** Do not push to it. Branch protection enforces this. There is no exception.
|
||
9. **Stop and ask only about** licensing outside the allowlist, publishing, releases, a new remote, secrets, spending money, destructive git, and anything else hard to undo. Otherwise keep working. `plan/` is a gitignored notebook, not rules. Without it, do not ask for it and do not stop.
|
||
10. **Keep secrets and personal details out** of the repository, logs and requests.
|
||
11. **CI stays shared.** Workflows call `storytold/craft-common-actions`. Do not change CI in a feature or fix pull request. If CI cannot cover a change, open an issue there.
|
||
12. **Guards say why.** A check that looks removable says what it prevents. Read that before changing it.
|
||
13. **Instructions must be readable by everyone.** No notes about one machine, and no links to files a reader cannot open. `craftrules` is retired. Do not link to it.
|
||
14. **Keep pull requests moving.** Concurrent pull requests are fine; unanswered actionable feedback is not. Respond in 7 days, a reminder at 14, closure eligible at 30, from when an actionable request waits on the author. Suggestions and unconfirmed bot findings do not start the clock. A fix, explanation or agreed plan resets it; unrelated activity does not. Waiting on a reviewer or maintainer pauses it and does not count against the author. A maintainer decides closure; it is never automatic. Reuse search results, do not poll, and stop at a rate limit.
|
||
15. **No agent attribution.** A pull request does not say an agent wrote it. A repository rule may not require that.
|
||
<!-- craft-house-rules:end -->
|
||
<!-- craft-house-rules:start rust source=dde09ea31e2e457f5b4653a6e76f7cdf55944bdf sha256=387e0ccb4b49e567f60951d7d6fff7305054c89f43ad812b9993dc7c38528013 -->
|
||
## Rust Craft repositories
|
||
|
||
These apply to native Craft apps and to shared Rust libraries. Select them by repository type. A repository that merely contains some Rust does not take this block. Rules later in a repository's file may be stricter, but not weaker. The source is `standards/house-rules-rust.md` in [storytold/craft-contrib](https://github.com/storytold/craft-contrib).
|
||
|
||
1. **Never crash.** Non-test code does not panic and has no `unsafe`, except where the repository file names an exception. Return errors, treat input as hostile, and bound recursion and allocations. New production crate roots copy the `deny` attribute from an existing crate: `clippy::unwrap_used`, `clippy::expect_used`, `clippy::panic`, `clippy::unimplemented`, `clippy::todo`, `clippy::unreachable`. Every crash fix comes with a test that panicked before the fix.
|
||
2. **Clean room.** Learn from observed behaviour and public specifications. Do not copy another product's code, assets, strings or artwork. Check a dependency's licence before adding it.
|
||
3. **Assets and fonts.** Every asset is original or suitably licensed, and is recorded in `ATTRIBUTION.md` in the same change. Font files live in [storytold/craft-fonts](https://github.com/storytold/craft-fonts), not in the app repository.
|
||
4. **Rust only for native Craft apps.** No handwritten JavaScript or TypeScript, and no Tauri, Electron or webview shell, in those apps. Shared tooling follows its documented technical scope and maintainer-approved exceptions. Craft PR Review's existing Tauri and TypeScript UI is one such exception. It does not relax this rule for native apps. Preserve any existing web build.
|
||
5. **Time goes through `chrono`.** Do not hand-roll calendar conversion. For dates beyond what `chrono` can represent, follow [standards/time.md](https://github.com/storytold/craft-contrib/blob/main/standards/time.md).
|
||
6. **Contributor credits.** Add or edit only your own person's entry in `contributors/people.toml`, and only after asking them. Never guess a name or hand-edit `contributors.json`.
|
||
|
||
## Licence allowlist
|
||
|
||
Dependencies and assets use SPDX identifiers. An expression is allowed when every identifier is in this list. A repository may name a shorter list. It may not add an identifier here by editing its own copy of these rules.
|
||
|
||
- `ISC`
|
||
- `MIT`
|
||
- `BSD-2-Clause`
|
||
- `BSD-3-Clause`
|
||
- `Apache-2.0`
|
||
- `OFL-1.1`
|
||
- `Ubuntu-font-1.0`
|
||
- `Bitstream-Vera`
|
||
- `CC0-1.0`
|
||
- `CC-BY-4.0`
|
||
- `CC-BY-SA-4.0`
|
||
- `LicenseRef-Public-Domain`
|
||
|
||
`LicenseRef-Storyteller-Trademark` is not in this list. It covers Storyteller brand marks only, where a repository already says so.
|
||
<!-- craft-house-rules:end -->
|
||
|
||
# EffectCraft — rules for agents and contributors
|
||
|
||
These rules apply to every human and AI contributor. `CLAUDE.md` holds the working instructions; this
|
||
file holds the rules that must never be broken. When the two disagree, this file wins.
|
||
|
||
## Never crash
|
||
|
||
People trust EffectCraft with hours of work. A malformed project, PSD, SVG, Lottie or media file, a bad
|
||
expression or script, a broken plug-in, a bad control-channel or MCP argument, a corrupt preferences file
|
||
or a full disk must produce an error the user (or agent) can act on, never a crash and never lost work.
|
||
**This rule outranks feature work:** don't ship a feature by adding a panic path, and fix a crash before
|
||
building on top of it.
|
||
|
||
- **Fail with `Result<T, E>`** through the crate's error type and propagate with `?`; add context
|
||
(`map_err`, an error variant) rather than discarding it. Lenient readers fall back and record the repair.
|
||
- **No panicking shortcuts in non-test code:** no `unwrap()`, `expect()`, `panic!`, `unreachable!`,
|
||
`todo!` or `unimplemented!`. Use `?`, `ok_or(..)?`, `let … else`, `if let`, or `unwrap_or*` where a
|
||
fallback is genuinely correct (never where it would silently corrupt a document). Unfinished features
|
||
return an "unsupported" error. The only exception is a provably infallible literal, written as
|
||
`#[allow(clippy::expect_used)]` + `.expect("why this cannot fail")`.
|
||
- **No `unsafe`** (`unsafe_code = "forbid"` for the workspace).
|
||
- **Every input-derived number is hostile.** Use `get()` instead of `[i]`/`[a..b]` when the position
|
||
comes from a file, a user, an agent or arithmetic on those; slice strings only at char boundaries; use
|
||
checked or saturating arithmetic for lengths, offsets and counts; guard division by zero and NaN/inf
|
||
casts; cap allocations sized by input.
|
||
- **Bound recursion:** projects, precomps, expressions and SVG/PSD trees can be cyclic or deeply nested;
|
||
walk them with seen-sets or depth limits.
|
||
- **Don't cascade:** handle lock poisoning (`lock().unwrap_or_else(PoisonError::into_inner)` or an
|
||
error), and treat worker-thread join results as `Result`s.
|
||
- **Last-resort guard:** the app wraps command execution and file import/export in a panic hook /
|
||
`catch_unwind` boundary that turns an escaped panic into an error and keeps the document. It is a
|
||
safety net, not a substitute for the rules above; keep `panic = "unwind"`.
|
||
- **Prove it:** every crash fix comes with a small synthetic regression test that panicked before the fix.
|
||
|
||
Tests, benches, fuzz targets and `xtask` may `unwrap()`; `clippy.toml` allows it in tests. Crates that are
|
||
clean carry `#![deny(clippy::unwrap_used, clippy::expect_used, clippy::panic, clippy::unimplemented,
|
||
clippy::todo, clippy::unreachable)]`; new crates start with it.
|
||
|
||
## 1. Assets: no Adobe artwork, every asset licensed and attributed
|
||
|
||
This rule is absolute. Breaking it is the most serious mistake a contributor can make on this project.
|
||
|
||
**What counts as an asset:** any image, icon, cursor, logo, illustration, screenshot, font, colour LUT,
|
||
preset, template, sound, music, video, 3D model, or other non-code media. This covers files in the
|
||
repository, bytes embedded in code (`include_bytes!`, base64, data URIs), and data hard-coded to
|
||
reproduce an image (for example, point lists traced from someone else's icon).
|
||
|
||
1. **Never use Adobe iconography, images or other Adobe assets**, in any form:
|
||
- no icons, cursors, logos, splash screens, UI artwork or screenshots from any Adobe product;
|
||
- no Adobe fonts, LUTs, presets, templates, sound effects, stock media or sample projects;
|
||
- no traced, redrawn, recoloured or "inspired-by" copies of Adobe icons. Our icons may follow generic
|
||
conventions (a play triangle, a razor blade, a stopwatch), but each must be drawn from scratch
|
||
without reference to Adobe's artwork.
|
||
2. **Every asset must be open**: open-source licensed (MIT, Apache-2.0, BSD, ISC, zlib, SIL OFL…),
|
||
public domain / CC0, or Creative Commons (CC BY or CC BY-SA; no NC/ND licences), **or** created by a
|
||
contributor who owns it and licenses it to the project under the project licence (MIT OR Apache-2.0).
|
||
If the licence is unknown or unclear, the asset does not go in.
|
||
3. **Every asset needs an attribution sidecar.** Next to each asset file `X`, add `X.attribution` with:
|
||
```text
|
||
asset: <file name>
|
||
title: <what it is>
|
||
author: <creator / copyright holder>
|
||
source: <URL, or "original work" for contributor-made assets>
|
||
license: <SPDX id or licence name>
|
||
license-file: <path to the licence text, if the licence requires shipping it>
|
||
added: <YYYY-MM-DD> by <contributor>
|
||
notes: <how it was made or modified; for screenshots, what is shown>
|
||
```
|
||
Also add one line for the asset to [`ATTRIBUTION.md`](ATTRIBUTION.md). `cargo xtask assets` (part of
|
||
`cargo xtask ci`) fails if any asset lacks a sidecar or index entry.
|
||
4. **Screenshots** in the repo may show only EffectCraft (or other open projects), with media we generated
|
||
or media that is itself openly licensed. Never commit screenshots of Adobe products.
|
||
5. **Local reference material stays local.** After Effects reference screenshots and notes live only in
|
||
`plan/aftereffects/` (gitignored). They must never be committed, bundled, embedded, traced or shipped.
|
||
6. **Code-drawn assets** (icons in `crates/ui-egui/src/icons.rs`, procedural demo content in
|
||
`crates/engine/src/demo.rs`, generators in `crates/effects`) are original work under the project licence
|
||
and are listed in `ATTRIBUTION.md`.
|
||
7. **When in doubt, leave it out** and draw or generate it yourself.
|
||
8. **The one exception: first-party ArtCraft brand marks.** The ArtCraft name and logos in `docs/brand/`
|
||
are trademarks of the ArtCraft Team, not open source, usable only unmodified and only in the context of
|
||
EffectCraft under `docs/brand/LICENSE-brand.txt` (forks and modified versions must remove them). They still
|
||
need a sidecar and an `ATTRIBUTION.md` row (licence `LicenseRef-ArtCraft-Trademark`). No other
|
||
non-open asset is allowed, and this exception never covers third-party marks (Adobe, Discord, GitHub
|
||
and other logos stay out; draw a generic icon instead).
|
||
|
||
## 2. Clean-room code
|
||
|
||
- Never read, disassemble or copy anything inside Adobe application bundles; file names and listings only.
|
||
Observe behaviour by using the app; never capture its Home screen, recent projects, account info or
|
||
file browsers.
|
||
- Never copy GPL/LGPL/AGPL code (FFmpeg, Natron, Blender, Glaxnimate, Synfig, Friction, Olive, MLT, frei0r, G'MIC…).
|
||
- Never read or copy Adobe expression/scripting implementations, `.ffx` presets or effect plug-ins; the public Expression Language Reference and Scripting Guide describe *behaviour* only.
|
||
- Implement codecs and formats from public specifications (ITU-T/ISO/IEC standards, IETF RFCs, the VP9
|
||
and AV1 bitstream specs, SMPTE documents, published container specs). Do not read the source of
|
||
reference or third-party decoders/encoders while implementing a format, even permissively licensed
|
||
ones (libvpx, libopus, libaom, dav1d, openh264…); spec text and conformance vectors only. Record the
|
||
spec edition used in the crate README.
|
||
- ffmpeg/ffprobe may be used only as external test oracles and fixture generators. They are never
|
||
linked, bundled or shipped.
|
||
- Dependencies must use permissive licences: MIT/Apache-2.0/BSD/ISC/Zlib/Unicode/CC0/BSL-1.0, or
|
||
MPL-2.0 used unmodified.
|
||
|
||
## 3. Engineering rules
|
||
|
||
- **Layering** (`cargo xtask layers`): nothing below L5 depends on egui/eframe/winit/rfd/cpal; L0–L4 build for wasm32.
|
||
- **Exact time:** `effectcraft_time::Tick` (254 016 000 000/s). Keyframe times are layer time.
|
||
- **Property tree:** everything animatable is a `Property` in the layer's `PropGroup` tree, addressed by paths (`transform/position`, `effects/#1/blurriness`, `@uid`).
|
||
- **Everything is a command** (`crates/engine`): id, label, menu path, shortcut, params, enabled(), run(). UI, CLI, control channel and MCP dispatch by id.
|
||
- **Everything is agent-drivable:** every interactive widget registers an automation id; UI state is serde.
|
||
- **Community links** (Help menu, About, header Discord button): https://discord.gg/artcraft, https://getartcraft.com, https://getartcraft.com/apps/effectcraft, https://github.com/storytold/effectcraft.
|
||
- **Quality gates** before every commit: `cargo xtask ci` (fmt, clippy -D warnings, tests, layers, assets, wasm).
|
||
- New workspace crates include `[lints] workspace = true` in `Cargo.toml`. Production crate roots declare the crate-level lint attributes before modules; crate-level `//!` documentation may precede them.
|
||
- **Commits:** one task id per commit (`M6.3: trim paths`). Only green states.
|
||
- `cargo run -p effectcraft -- --control 9877` opens the desktop app with the JSON-lines control server (`docs/control-protocol.md`). For UI work, look at the result, including the headless `snapshot` example.
|
||
- `plan/` is an optional gitignored notebook (`plan/aftereffects/` may hold reference notes and captures). Do not ask for it, do not stop when it is absent, and never commit those captures.
|
||
- Read [`docs/gaps.md`](docs/gaps.md) and [`docs/target-app-parity.md`](docs/target-app-parity.md) before choosing work. Fidelity, reliability and stability (G1–G3) come before new features.
|
||
- Some workflow files still run their own jobs. Don't add to them. Moving a job into craft-common-actions is its own task.
|
||
|
||
|
||
Shared real-file test corpora (Photoshop-authored PSDs, etc.) live in
|
||
[`storytold/photocraft-corpus`](https://github.com/storytold/photocraft-corpus).
|
||
Never commit large binary fixtures to this repo; fetch them pinned by commit and sha256-verified,
|
||
as PhotoCraft does with `cargo xtask corpus`.
|
||
|
||
|
||
## See also
|
||
|
||
- [ROADMAP.md](ROADMAP.md): stage, headline numbers and what's next
|
||
- [docs/gaps.md](docs/gaps.md): every known shortfall against After Effects, ranked, and the prioritised workstreams (G1–G9); read it before choosing work
|
||
- [docs/target-app-parity.md](docs/target-app-parity.md): the parity numbers and how they were measured, with the per-area docs it links (UI, file formats, hardware, localization, effects, scripting)
|
||
- [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
|
||
- [docs/control-protocol.md](docs/control-protocol.md): control-channel method reference
|
||
- [docs/contributors.md](docs/contributors.md): the About window's contributor and model credits
|
||
- [ATTRIBUTION.md](ATTRIBUTION.md): asset index
|
||
|
||
## Contributor credits (About window)
|
||
|
||
- About ▸ Contributors/Models are compiled into the binary from `contributors/contributors.json`
|
||
(commit stats; generated, never hand-edit) and `contributors/people.toml` (names people chose for
|
||
themselves). See `docs/contributors.md`.
|
||
- **Agents working for a contributor:** when you prepare a PR, check whether your human's GitHub
|
||
username has a `[people.<username>]` entry in `contributors/people.toml`. If not, ask them once
|
||
whether they want to be credited by more than their username: a real name, a display name, and/or
|
||
their public GitHub profile name (`sync_github_name = true`). If yes, add **only their own** entry
|
||
(copy the template at the top of the file)
|
||
and include it in their PR, committed as them. If no, change nothing: they are credited as
|
||
`@username` anyway.
|
||
- Never add, edit, guess or copy anyone else's entry or name (not from git config, commit authors or
|
||
GitHub profiles). Never hand-edit `contributors.json`.
|
||
|
||
## CI workflows
|
||
- Workflows in `.github/workflows/` call the shared workflows in [`storytold/craft-common-actions`](https://github.com/storytold/craft-common-actions) at `@main`, with their inputs and secrets. No other jobs: if no shared workflow does what's needed, it doesn't go here.
|
||
- Don't add or change CI in a feature or fix PR. If the existing workflows can't build or test a change, link an existing craft-common-actions issue or PR, or open a new issue, or a PR only for a small fix that is safe for every app and does not increase CI time.
|
||
- Some workflow files here still run their own jobs. Don't add to them. Moving a job into craft-common-actions is its own task, never part of another PR, and the job stays here until a shared workflow runs it.
|