# Authoring rules

> The numbered rules that prevent most broken framefields renders. Read before writing a composition.

1. **Register fonts first.** Call `FontManager.register({ family, source })` for every family before building any text layer. There are no system fonts. Emoji need `FontManager.registerEmojiFont(...)` with a CBDT/CBLC color font.
2. **Keyframes are local.** Frame 0 is the layer's first frame. Never add the parent's `startFrame`.
3. **Frames are integers.** Keyframe frames, `startFrame`, `durationFrames` — whole numbers only.
4. **Animating `x`/`y` overrides layout.** Animate to the placed value: placed at `y: 400` → `fromTo("y", 440, 400)`.
5. **`x`/`y` make a layer absolute** unless `position: "relative"` is set.
6. **Borders are `borderColor` + `borderWidth`.** CSS `border` strings are ignored.
7. **Give text a width** when it can wrap; otherwise it may clip.
8. **Every `Layer.audio()` needs `durationFrames`.**
9. **Images are raster.** `.png/.jpg/.webp` → `Layer.image`; `.json/.lottie` → `Layer.lottie`.
10. **Effect strengths are often 0–100**, not 0–1 (`Vignette`, `FilmGrain`, `Blur`). Check the [Effects reference](/docs/reference/effects/).
11. **Grade, then optics, then grain.** `FilmGrain` is the outermost pass.
12. **PBR needs an environment.** `roughness`/`metallic` do nothing without `Layer.environment()` or a `Lighting` rig.
13. **One shadow light**, directional or spot.
14. **Signals sample the composition frame**, not the layer's local frame.
15. **Vision trails by one frame.** Verify vision with the MP4 or consecutive frames, never with a frame grid.
16. **Resolve assets from `import.meta.url`** so the browser preview can load them.
17. **Assets live in `assets/`, in Git LFS.** `git lfs pull` before rendering in a fresh clone; confirm new media appear in `git lfs ls-files` before committing; never commit `output/`.
18. **Verify cheapest first:** typecheck → `lint()` → `renderFrame` → `renderFrameGrid` → `renderVideo({ qa: true })`. Look at every image you render.
19. **End render scripts with `process.exit()`.**
20. **Tokens live in `theme.ts`.** No magic colors, sizes or timings in scenes.
21. **Ease with intent.** `back.out(1.4–1.7)` entrances, `expo.out`/`spring` decelerations, `power2.in` exits, `linear` only for loops and counters.
22. **Custom shaders output premultiplied alpha** and blend with `srcFactor: "one"`, never `"src-alpha"`.
