@a-company/atelier 0.36.0 → 0.37.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (56) hide show
  1. package/package.json +13 -8
  2. package/university/content/notes/N-atel-001-first-render.md +114 -0
  3. package/university/content/notes/N-atel-001-install-and-launch.md +84 -0
  4. package/university/content/notes/N-atel-001-what-is-atelier.md +51 -0
  5. package/university/content/notes/N-atel-101-easings.md +97 -0
  6. package/university/content/notes/N-atel-101-layers.md +106 -0
  7. package/university/content/notes/N-atel-101-states-and-deltas.md +94 -0
  8. package/university/content/notes/N-atel-101-the-atelier-format.md +72 -0
  9. package/university/content/notes/N-atel-201-authoring-tools.md +141 -0
  10. package/university/content/notes/N-atel-201-mcp-overview.md +86 -0
  11. package/university/content/notes/N-atel-201-patterns.md +108 -0
  12. package/university/content/notes/N-atel-201-visual-and-effects.md +125 -0
  13. package/university/content/notes/N-atel-301-composition-and-overlays.md +141 -0
  14. package/university/content/notes/N-atel-301-effects.md +136 -0
  15. package/university/content/notes/N-atel-301-images-and-video.md +126 -0
  16. package/university/content/notes/N-atel-301-shapes-and-text.md +118 -0
  17. package/university/content/notes/N-atel-401-hierarchical-states.md +71 -0
  18. package/university/content/notes/N-atel-401-motion-deep-dive.md +106 -0
  19. package/university/content/notes/N-atel-401-presets-and-templates.md +98 -0
  20. package/university/content/notes/N-atel-401-transitions.md +94 -0
  21. package/university/content/notes/N-atel-501-detected-vs-user-edited.md +76 -0
  22. package/university/content/notes/N-atel-501-layer-tag-isolation.md +62 -0
  23. package/university/content/notes/N-atel-501-silence-trim.md +98 -0
  24. package/university/content/notes/N-atel-501-transcribe-and-captions.md +98 -0
  25. package/university/content/notes/N-atel-601-carousel.md +71 -0
  26. package/university/content/notes/N-atel-601-overlay-rules.md +96 -0
  27. package/university/content/notes/N-atel-601-recipe-tools-and-apply.md +84 -0
  28. package/university/content/notes/N-atel-601-studio-recipe.md +103 -0
  29. package/university/content/notes/N-atel-701-choosing-output.md +68 -0
  30. package/university/content/notes/N-atel-701-png-and-frames.md +84 -0
  31. package/university/content/notes/N-atel-701-vector.md +85 -0
  32. package/university/content/notes/N-atel-701-video.md +88 -0
  33. package/university/content/notes/N-atel-801-editing-surface.md +69 -0
  34. package/university/content/notes/N-atel-801-live-bridge.md +84 -0
  35. package/university/content/notes/N-atel-801-studio-app.md +72 -0
  36. package/university/content/notes/N-atel-801-symbiotic-loop.md +56 -0
  37. package/university/content/paths/LP-atel-001.yaml +21 -0
  38. package/university/content/paths/LP-atel-101.yaml +22 -0
  39. package/university/content/paths/LP-atel-201.yaml +23 -0
  40. package/university/content/paths/LP-atel-301.yaml +22 -0
  41. package/university/content/paths/LP-atel-401.yaml +22 -0
  42. package/university/content/paths/LP-atel-501.yaml +22 -0
  43. package/university/content/paths/LP-atel-601.yaml +22 -0
  44. package/university/content/paths/LP-atel-701.yaml +22 -0
  45. package/university/content/paths/LP-atel-801.yaml +22 -0
  46. package/university/content/quizzes/Q-atel-001-orientation.yaml +66 -0
  47. package/university/content/quizzes/Q-atel-101-document-model.yaml +66 -0
  48. package/university/content/quizzes/Q-atel-201-mcp-authoring.yaml +66 -0
  49. package/university/content/quizzes/Q-atel-301-visual-system.yaml +66 -0
  50. package/university/content/quizzes/Q-atel-401-state-machines.yaml +66 -0
  51. package/university/content/quizzes/Q-atel-501-video-pipeline.yaml +66 -0
  52. package/university/content/quizzes/Q-atel-601-recipes.yaml +66 -0
  53. package/university/content/quizzes/Q-atel-701-export.yaml +66 -0
  54. package/university/content/quizzes/Q-atel-801-studio-loop.yaml +66 -0
  55. package/university/index.yaml +720 -0
  56. package/university/pack.yaml +21 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@a-company/atelier",
3
- "version": "0.36.0",
3
+ "version": "0.37.0",
4
4
  "description": "CLI tool — validate, preview, render, info commands",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",
@@ -20,8 +20,12 @@
20
20
  "files": [
21
21
  "dist",
22
22
  "templates/**",
23
- "src/web/**"
23
+ "src/web/**",
24
+ "university/**"
24
25
  ],
26
+ "paradigm": {
27
+ "universityPack": "university/"
28
+ },
25
29
  "dependencies": {
26
30
  "@a-company/atelier-studio": ">=0.25.1",
27
31
  "@modelcontextprotocol/sdk": "^1.0.0",
@@ -31,7 +35,7 @@
31
35
  "ws": "^8.20.1",
32
36
  "yaml": "^2.7.0",
33
37
  "zod": "^3.25.0",
34
- "@a-company/atelier-mcp": "0.27.1"
38
+ "@a-company/atelier-mcp": "0.27.2"
35
39
  },
36
40
  "peerDependencies": {
37
41
  "canvas": ">=2.0.0"
@@ -50,17 +54,18 @@
50
54
  "tsup": "^8.4.0",
51
55
  "typescript": "^5.7.0",
52
56
  "vitest": "^3.0.0",
53
- "@a-company/atelier-core": "0.26.0",
54
57
  "@a-company/atelier-lottie": "0.25.1",
55
- "@a-company/atelier-canvas": "0.26.0",
56
- "@a-company/atelier-types": "0.31.0",
57
58
  "@a-company/atelier-schema": "0.28.0",
58
- "@a-company/atelier-svg": "0.25.1"
59
+ "@a-company/atelier-canvas": "0.26.0",
60
+ "@a-company/atelier-svg": "0.25.1",
61
+ "@a-company/atelier-core": "0.26.0",
62
+ "@a-company/atelier-types": "0.31.0"
59
63
  },
60
64
  "scripts": {
61
65
  "build": "tsup",
66
+ "bundle-university": "node scripts/bundle-university.mjs",
62
67
  "typecheck": "tsc --noEmit && tsc --noEmit -p src/web/tsconfig.json",
63
68
  "test": "vitest run",
64
- "clean": "rm -rf dist"
69
+ "clean": "rm -rf dist university"
65
70
  }
66
71
  }
@@ -0,0 +1,114 @@
1
+ ---
2
+ id: N-atel-001-first-render
3
+ title: Render your first animation
4
+ type: note
5
+ track: ATEL-001
6
+ author: atelier
7
+ created: '2026-05-18'
8
+ updated: '2026-05-18'
9
+ tags:
10
+ - course
11
+ - atel-001
12
+ - first-render
13
+ - cli
14
+ difficulty: beginner
15
+ estimatedMinutes: 5
16
+ prerequisites:
17
+ - N-atel-001-install-and-launch
18
+ summary: Create a minimal `.atelier` document by hand, preview a frame, and export to PNG — three CLI calls, no studio needed. Demystifies the document format before the visual surfaces hide it.
19
+ ---
20
+
21
+ ## The smallest possible document
22
+
23
+ Save this as `hello.atelier` in any directory:
24
+
25
+ ```yaml
26
+ name: Hello
27
+ canvas:
28
+ width: 800
29
+ height: 600
30
+ fps: 60
31
+ background: "#0F1115"
32
+ layers:
33
+ - id: title
34
+ visual:
35
+ type: text
36
+ content: Hello, Atelier
37
+ style:
38
+ fontFamily: Inter, system-ui, sans-serif
39
+ fontSize: 64
40
+ fontWeight: 600
41
+ color: "#F5F5F7"
42
+ frame:
43
+ x: 400
44
+ y: 300
45
+ bounds:
46
+ width: 600
47
+ height: 100
48
+ anchorPoint:
49
+ x: 0.5
50
+ y: 0.5
51
+ opacity: 0
52
+ states:
53
+ default:
54
+ duration: 60
55
+ deltas:
56
+ - layer: title
57
+ property: opacity
58
+ from: 0
59
+ to: 1
60
+ startFrame: 0
61
+ endFrame: 30
62
+ easing: ease-out
63
+ ```
64
+
65
+ That's a full Atelier document. One text layer, one state, one delta that fades the title in over 30 frames.
66
+
67
+ ## Validate it
68
+
69
+ ```bash
70
+ atelier validate hello.atelier
71
+ ```
72
+
73
+ The schema catches malformed easings, references to nonexistent layers, out-of-range frame numbers, missing required fields. Validation runs against a Zod schema with AI-readable error messages — if you ever ship a corrupt document, the validator will point at the field, not just say "invalid YAML."
74
+
75
+ ## Preview a frame
76
+
77
+ ```bash
78
+ atelier preview hello.atelier --frame 15
79
+ ```
80
+
81
+ Outputs the resolved layer state at frame 15: the title at 50% opacity, mid-fade. This is the same `resolveFrame` call the renderer makes; `preview` lets you inspect it without rendering.
82
+
83
+ ## Export
84
+
85
+ ```bash
86
+ atelier export-image hello.atelier --frame 30 --out hello.png
87
+ ```
88
+
89
+ PNG export from a single frame, via the `@napi-rs/canvas` rasterizer (prebuilt binaries — no native build, works on a plain `npm install`). For video, use `atelier render`:
90
+
91
+ ```bash
92
+ atelier render hello.atelier --format mp4 --out hello.mp4
93
+ ```
94
+
95
+ The CLI's `render` uses FFmpeg (must be on `$PATH`) and outputs MP4 or GIF. The browser studio exports via WebCodecs (MP4 / WebM / GIF, no FFmpeg dependency). Vector output is `atelier export-svg` and `atelier export-lottie` — see ATEL-701.
96
+
97
+ ## What you just learned about the format
98
+
99
+ - **Canvas** sets dimensions, frame rate, background — the global render context.
100
+ - **Layers** are visual elements with an ID, a `visual` (shape/text/image/video/group/ref), a `frame` (position), `bounds` (size), `anchorPoint`, and animatable properties (opacity, rotation, scale).
101
+ - **States** are named keyframes. Each has a `duration` (in frames) and `deltas` (interpolations).
102
+ - **Deltas** animate one property of one layer from a `from` value to a `to` value across `startFrame`–`endFrame`, with an `easing`.
103
+
104
+ That's the mental model. Layers describe what exists. States describe how long. Deltas describe how things change. Everything else — easings, presets, templates, interactions, refs — extends these primitives.
105
+
106
+ ## Where to go next
107
+
108
+ - **ATEL-101**: Document Model Fundamentals — every layer type, every easing, the resolveFrame interpolation model
109
+ - **ATEL-201**: Authoring via MCP — the 61 tools an agent uses to build documents like this without touching YAML
110
+ - **ATEL-301**: Visual System — shapes, typography, images, video; fills, strokes, shadows, blend modes, motion paths
111
+ - **ATEL-501**: Video Project Pipeline — silence-trim, transcribe, captions, parametric cuts
112
+ - **ATEL-601**: Studio Recipes — bundle silence policy + caption style + overlay rules + palette into a reusable preset
113
+
114
+ You can also just run `atelier studio hello.atelier` and edit this document in the browser. Anything you change in the studio writes back to the same file.
@@ -0,0 +1,84 @@
1
+ ---
2
+ id: N-atel-001-install-and-launch
3
+ title: Install Atelier and launch the studio
4
+ type: note
5
+ track: ATEL-001
6
+ author: atelier
7
+ created: '2026-05-18'
8
+ updated: '2026-05-18'
9
+ tags:
10
+ - course
11
+ - atel-001
12
+ - install
13
+ - cli
14
+ difficulty: beginner
15
+ estimatedMinutes: 4
16
+ prerequisites:
17
+ - N-atel-001-what-is-atelier
18
+ summary: One npm install gives you three commands — `atelier` (CLI), `atelier-mcp` (MCP server for AI agents), and `atelier studio` (local browser editor). Walks through install, what each command does, and how the three relate.
19
+ ---
20
+
21
+ ## Install
22
+
23
+ ```bash
24
+ npm i -g @a-company/atelier
25
+ ```
26
+
27
+ That single install gives you three executables on your `$PATH`:
28
+
29
+ | Command | What it does | When you use it |
30
+ |---|---|---|
31
+ | `atelier` | CLI for validating, inspecting, rendering, and processing `.atelier` files | Scripts, CI, Makefiles, ad-hoc inspection |
32
+ | `atelier-mcp` | MCP server an AI agent can connect to for authoring | Configure once in Claude Desktop or any MCP-aware client |
33
+ | `atelier studio` | Boots a local browser editor on `localhost` | Hands-on editing; image overlays; watching an agent mutate live |
34
+
35
+ You only need Node 20+ and a modern browser. No native build, no cloud account, no signup.
36
+
37
+ ## Launch the studio
38
+
39
+ ```bash
40
+ atelier studio
41
+ ```
42
+
43
+ That command:
44
+
45
+ 1. Probes a free port starting at `4321` (override with `--port 5000` or `--port-range 4321-4340`)
46
+ 2. Boots a local HTTP server bound to `127.0.0.1` (never `0.0.0.0`)
47
+ 3. Opens your default browser to `http://localhost:<port>` (suppress with `--no-open`)
48
+ 4. Watches the current working directory for `.atelier` files and lists them in the sidebar
49
+ 5. If the directory is empty, scaffolds a `welcome.atelier` so you land in a real document instead of an empty shell
50
+
51
+ The studio runs entirely on your machine. Nothing is sent anywhere.
52
+
53
+ ## Configure the MCP server (for AI agents)
54
+
55
+ In your Claude Desktop config (or any MCP client):
56
+
57
+ ```json
58
+ {
59
+ "mcpServers": {
60
+ "atelier": {
61
+ "command": "atelier-mcp"
62
+ }
63
+ }
64
+ }
65
+ ```
66
+
67
+ The agent now has 61 tools across 15 groups — document/layer/state/delta operations, visual configuration, asset and variable management, presets, templates, exports, and more. ATEL-201 covers the full tool surface and when to use which.
68
+
69
+ ## How the three commands relate
70
+
71
+ They share a single underlying engine (`@atelier/core`) and document store. Mutations made by `atelier-mcp` are observable by `atelier studio` running in the same project — when you wire the live-mutation bridge (the WebSocket transport between the MCP store and the studio), an agent's tool calls appear in the studio canvas in real time, with a toast attributing each change to its source.
72
+
73
+ This is the symbiotic loop Atelier is built for: the agent proposes, you tweak, the agent re-proposes, your tweaks survive. The detected-vs-user-edited convention from ATEL-501 (video pipelines) is the same idea generalized — every channel (silence-trim, captions, overlays, agent mutations) carries a source tag, and re-runs preserve human authorship.
74
+
75
+ ## Sanity-check your install
76
+
77
+ ```bash
78
+ atelier --version
79
+ atelier list
80
+ ```
81
+
82
+ `atelier list` enumerates the `.atelier` files in CWD. If there are none and you haven't launched the studio yet, that's expected — the welcome scaffold only happens on `atelier studio` first run.
83
+
84
+ Next: render your first animation.
@@ -0,0 +1,51 @@
1
+ ---
2
+ id: N-atel-001-what-is-atelier
3
+ title: What is Atelier?
4
+ type: note
5
+ track: ATEL-001
6
+ author: atelier
7
+ created: '2026-05-18'
8
+ updated: '2026-05-18'
9
+ tags:
10
+ - course
11
+ - atel-001
12
+ - orientation
13
+ difficulty: beginner
14
+ estimatedMinutes: 3
15
+ prerequisites: []
16
+ summary: Atelier is an AI-native animation engine — a declarative YAML format authored through MCP tools, runnable from a CLI, embeddable as a widget, and now bootable as a local browser editor with `atelier studio`.
17
+ ---
18
+
19
+ ## The short version
20
+
21
+ Atelier is an **animation engine that an AI agent can author through tool calls**. A `.atelier` document is plain YAML describing layers (shapes, text, images, video, groups), states, and deltas (per-frame interpolations). An agent calling `atelier_create`, `atelier_add_layer`, `atelier_add_state`, `atelier_add_delta` builds a document the same way a human would in a GUI — except every step is structured, validated, and reproducible.
22
+
23
+ Once a document exists, Atelier can:
24
+
25
+ - **Resolve** any frame by interpolating delta values through easings (linear, cubic-bezier, ease presets, spring physics, step)
26
+ - **Render** to Canvas 2D, SVG strings, or Lottie JSON
27
+ - **Export** to PNG, MP4, WebM, GIF — from a browser (WebCodecs) or the CLI (FFmpeg)
28
+ - **Edit** in a browser studio with a canvas preview, layer panel, property panel, and YAML view
29
+ - **Trim, transcribe, caption** video projects with the silence-detect + Whisper + caption pipelines
30
+
31
+ ## What makes it "AI-native"
32
+
33
+ Three things, in order of importance:
34
+
35
+ 1. **The document format was designed for an agent to write.** Layers have descriptive IDs, deltas reference layers by ID, states reference each other by name. There is no "drag this onto the canvas" — there is `atelier_add_layer({ id: "title", visual: { type: "text", content: "Hello", style: {...} } })`. The schema gives AI-readable validation errors when the agent gets it wrong.
36
+ 2. **61 MCP tools cover the full authoring surface.** An agent doesn't compose YAML by hand and pray it parses. It calls typed tools that mutate a document store, validate after each mutation, and return the updated document. Mistakes are caught at the tool boundary, not at render time.
37
+ 3. **The detected-vs-user-edited convention.** When a pipeline (silence-trim, captions) generates layers from analysis, those layers are tagged. User edits set `userEdited` / `userAdded` / `hidden` flags. Re-running the pipeline preserves user fixes by matching on timing tolerance. The human and the agent can both edit the same document forever without one erasing the other.
38
+
39
+ ## What it is not
40
+
41
+ - **Not a code framework.** It does not ship React components, runtime hooks, or HTTP handlers.
42
+ - **Not a cloud product.** Everything runs locally. There is no signup, no SaaS, no telemetry by default.
43
+ - **Not a replacement for After Effects.** It is a programmable, AI-author-first format. You will not draw bezier paths with a mouse here (yet). You will describe them in YAML or generate them via tool calls.
44
+
45
+ ## Who uses Atelier today
46
+
47
+ - **AI agents** authoring social-media-ready motion graphics, explainer animations, and short-form video composition
48
+ - **Developers** scripting animations via the Builder API (`@atelier/core`) or driving the CLI from a Makefile
49
+ - **Content creators** in `atelier studio` for hands-on layer editing with AI assistance live in the loop
50
+
51
+ The rest of this track shows you how to install Atelier and render your first animation in under two minutes.
@@ -0,0 +1,97 @@
1
+ ---
2
+ id: N-atel-101-easings
3
+ title: Easings — linear, cubic-bezier, presets, spring, step
4
+ type: note
5
+ track: ATEL-101
6
+ author: atelier
7
+ created: '2026-05-18'
8
+ updated: '2026-05-18'
9
+ tags:
10
+ - course
11
+ - atel-101
12
+ - easings
13
+ - motion
14
+ difficulty: beginner
15
+ estimatedMinutes: 4
16
+ prerequisites:
17
+ - N-atel-101-states-and-deltas
18
+ summary: Five easing kinds in Atelier. What each is, when to use it, and the one rule that prevents 90% of bad motion (don't use `linear` for organic movement).
19
+ ---
20
+
21
+ ## What an easing does
22
+
23
+ An easing is a function `f(t: 0..1) → 0..1` that maps "fraction of time elapsed" to "fraction of value progress." `f(0) = 0`, `f(1) = 1`. What happens in between is the personality of the motion.
24
+
25
+ Atelier supports five kinds:
26
+
27
+ ## 1. `linear`
28
+
29
+ `f(t) = t`. Constant rate. Use for: progress bars, scrubbing, opacity crossfades where the perceived speed matters. **Do not use** for object motion — it looks robotic. Most "feels wrong" motion in the wild is `linear` doing the wrong job.
30
+
31
+ ```yaml
32
+ easing: linear
33
+ ```
34
+
35
+ ## 2. Cubic-Bezier — `cubic-bezier(x1, y1, x2, y2)`
36
+
37
+ The CSS-style four-control-point bezier. Full control over the shape. This is what every preset below desugars to.
38
+
39
+ ```yaml
40
+ easing: cubic-bezier(0.4, 0.0, 0.2, 1.0) # Material "standard"
41
+ ```
42
+
43
+ If you've used CSS transitions, this is the same function.
44
+
45
+ ## 3. Ease presets
46
+
47
+ Named shortcuts to common bezier curves. Use these instead of memorizing coefficients.
48
+
49
+ | Preset | Bezier | Use for |
50
+ |---|---|---|
51
+ | `ease-in` | `(0.4, 0, 1, 1)` | Object accelerating off-screen |
52
+ | `ease-out` | `(0, 0, 0.2, 1)` | Object decelerating on entrance (most UI entrance animation) |
53
+ | `ease-in-out` | `(0.4, 0, 0.2, 1)` | Crossfades, value-to-value transitions where both endpoints are visible |
54
+ | `ease` | `(0.25, 0.1, 0.25, 1)` | The CSS default — generic "feels OK" |
55
+
56
+ Default for most UI motion: `ease-out` for entrances, `ease-in` for exits.
57
+
58
+ ## 4. Spring physics — `spring({ stiffness, damping, mass? })`
59
+
60
+ Physics-based. Produces overshoot and oscillation that no bezier can match. Use for: anything that should feel tactile — toggles, drag-release, dismissals.
61
+
62
+ ```yaml
63
+ easing:
64
+ type: spring
65
+ stiffness: 170
66
+ damping: 20
67
+ mass: 1
68
+ ```
69
+
70
+ Stiffness controls how aggressively the spring pulls toward the target. Damping controls how quickly oscillation dies out. Atelier solves the spring numerically per-frame; the same `startFrame`–`endFrame` window still applies (the spring is clipped at `endFrame` and held at the resolved value after).
71
+
72
+ When in doubt: `stiffness: 170, damping: 26` for a clean snap; `stiffness: 100, damping: 10` for visible oscillation.
73
+
74
+ ## 5. Step — `step(count)` or `step(count, position)`
75
+
76
+ Discrete jumps. `step(4)` produces four equal jumps from `from` to `to`. Use for: spritesheet frame indexing (jump through frames at 12fps inside a 60fps composition), digital-readout counters, deliberate stop-motion feel.
77
+
78
+ ```yaml
79
+ easing:
80
+ type: step
81
+ count: 4
82
+ position: start # 'start' | 'end' | 'jump-none' | 'jump-both'
83
+ ```
84
+
85
+ ## The rule that prevents most bad motion
86
+
87
+ > If a real physical object would do it, use spring or ease-out.
88
+ > If a UI element is reporting progress, use linear.
89
+ > Almost nothing else should be linear.
90
+
91
+ Easings are why motion feels "designed" or "wrong." The engine doesn't care which you pick — the renderer interpolates whatever `f(t)` returns. But your viewer does care, every time.
92
+
93
+ ## Inspecting an easing
94
+
95
+ The studio's easing-curve-editor (in PropertyPanel when you select a delta) shows the bezier curve, lets you drag control points, and previews the shape against the timeline. For springs, it samples the solver and plots the actual oscillation. There is no "easings preview file" — every delta you author can be inspected and tuned in place.
96
+
97
+ That closes ATEL-101. You now know enough to read any `.atelier` document and predict what it will render. ATEL-201 covers the MCP tool surface — how an agent builds documents like this without ever touching YAML.
@@ -0,0 +1,106 @@
1
+ ---
2
+ id: N-atel-101-layers
3
+ title: Layer anatomy
4
+ type: note
5
+ track: ATEL-101
6
+ author: atelier
7
+ created: '2026-05-18'
8
+ updated: '2026-05-18'
9
+ tags:
10
+ - course
11
+ - atel-101
12
+ - layers
13
+ - format
14
+ difficulty: beginner
15
+ estimatedMinutes: 5
16
+ prerequisites:
17
+ - N-atel-101-the-atelier-format
18
+ summary: Every field on the `Layer` type, what it does, what's required vs optional, and which fields are animatable through deltas.
19
+ ---
20
+
21
+ ## The minimum layer
22
+
23
+ ```yaml
24
+ - id: title
25
+ visual:
26
+ type: text
27
+ content: Hello
28
+ style:
29
+ fontFamily: Inter, system-ui, sans-serif
30
+ fontSize: 48
31
+ frame:
32
+ x: 400
33
+ y: 300
34
+ bounds:
35
+ width: 600
36
+ height: 80
37
+ ```
38
+
39
+ Four required fields: `id`, `visual`, `frame`, `bounds`. The rest are optional and default to sensible values.
40
+
41
+ ## The six visual types
42
+
43
+ The `visual` field is a discriminated union on `type`:
44
+
45
+ | `type` | Renders | Required sub-fields |
46
+ |---|---|---|
47
+ | `shape` | A geometric shape — rect, ellipse, polygon, path | `shape`, optional `fill` and `stroke` |
48
+ | `text` | A string with typography | `content`, `style` (fontFamily required) |
49
+ | `image` | A static image asset | `assetId` (and optional `src`, `sourceRect`, `spritesheet`) |
50
+ | `video` | A video clip | `assetId`, optional `sourceOffset`, `sourceEnd`, `playbackRate` |
51
+ | `group` | A container for child layers (via `parentId`) | none — just a container |
52
+ | `ref` | A reference to another `.atelier` file rendered as a sub-document | `src`, optional `state` and `frame` |
53
+
54
+ ## Position, size, and anchor
55
+
56
+ - **`frame: { x, y }`** — position of the anchor point in canvas pixels.
57
+ - **`bounds: { width, height }`** — the layer's box.
58
+ - **`anchorPoint: { x, y }`** — normalized 0–1 coordinate inside the bounds that `frame` positions. `{x: 0.5, y: 0.5}` centers the layer on `frame`. `{x: 0, y: 0}` puts the top-left at `frame`. Default is `{x: 0, y: 0}`.
59
+
60
+ The anchor also defines the pivot for `rotation` and `scale`.
61
+
62
+ ## Animatable layer properties
63
+
64
+ These can appear in deltas (`property: <name>`):
65
+
66
+ | Property | Type | Default |
67
+ |---|---|---|
68
+ | `opacity` | number 0–1 | 1 |
69
+ | `rotation` | degrees | 0 |
70
+ | `scale` | `{ x, y }` | `{1, 1}` |
71
+ | `frame.x`, `frame.y` | number | as authored |
72
+ | `bounds.width`, `bounds.height` | number | as authored |
73
+ | `tint.amount` | 0–1 (color tint strength) | 0 |
74
+ | Any color, gradient stop, stroke width, shadow blur on the visual or its style | various | — |
75
+
76
+ The full animatable list is 27 properties. The schema enforces that a delta's `property` path is reachable on the named layer's visual.
77
+
78
+ ## Non-animatable structural fields
79
+
80
+ | Field | Purpose |
81
+ |---|---|
82
+ | `id` | Unique identifier |
83
+ | `tags` | Namespace markers (used by pipelines for layer-tag isolation) |
84
+ | `description` | Human-readable note, kept out of render |
85
+ | `parentId` | Parents this layer to another for transform inheritance |
86
+ | `visible` | Hard on/off (rendered if `true` or absent) |
87
+ | `blendMode` | Canvas composite operation |
88
+ | `clipPath` | A Shape that restricts rendering to its interior |
89
+ | `motionPath` | A path the layer follows over time, with optional auto-rotate |
90
+ | `interactions` | Event-driven trigger-action bindings (e.g. hover → state transition) |
91
+
92
+ ## Parent-child and transform inheritance
93
+
94
+ Setting `parentId` on a layer makes its `frame`, `rotation`, and `scale` relative to the parent's transformed coordinate space. A `group` visual has no rendered output of its own — it exists purely to provide a parent transform. Use groups when you want to translate or rotate a cluster of layers as one unit.
95
+
96
+ ## Tags: the pipeline contract
97
+
98
+ Tags are how the silence-trim, caption, and overlay pipelines find layers they own. Each pipeline writes a tag namespace:
99
+
100
+ - `silence-trim` — clip layers produced by `atelier trim`
101
+ - `caption`, `caption-word` — text layers produced by `atelier captions regenerate`
102
+ - `overlay` — handle / page-number / recipe-driven decorative layers
103
+
104
+ The invariant: re-running a pipeline drops only its own tagged layers and replaces them. Layers without that tag (user-authored, or owned by another pipeline) are never touched. This is what makes the human↔agent symbiotic loop safe (ATEL-501 covers this in depth).
105
+
106
+ Next: states and deltas.
@@ -0,0 +1,94 @@
1
+ ---
2
+ id: N-atel-101-states-and-deltas
3
+ title: States, deltas, and `resolveFrame`
4
+ type: note
5
+ track: ATEL-101
6
+ author: atelier
7
+ created: '2026-05-18'
8
+ updated: '2026-05-18'
9
+ tags:
10
+ - course
11
+ - atel-101
12
+ - states
13
+ - deltas
14
+ - resolve-frame
15
+ difficulty: beginner
16
+ estimatedMinutes: 5
17
+ prerequisites:
18
+ - N-atel-101-layers
19
+ summary: A state is a named span of frames. A delta animates one property of one layer over a sub-range of that span. `resolveFrame(doc, stateName, frame)` is the function the renderer calls — knowing its shape demystifies everything else.
20
+ ---
21
+
22
+ ## A state is a named span
23
+
24
+ ```yaml
25
+ states:
26
+ default:
27
+ duration: 60
28
+ deltas:
29
+ - layer: title
30
+ property: opacity
31
+ from: 0
32
+ to: 1
33
+ startFrame: 0
34
+ endFrame: 30
35
+ easing: ease-out
36
+ ```
37
+
38
+ `default` is the state name. `duration: 60` means this state runs for 60 frames (one second at 60fps). Frames are 0-indexed, so this state spans `0..59` inclusive. The renderer plays through the state and either loops, transitions to another state, or stops, depending on configuration.
39
+
40
+ A document always has at least one state. Most documents have only one. Multi-state documents are the foundation of interactive UI motion (`hover`, `active`, `pressed`) and segmented narratives.
41
+
42
+ ## A delta animates one property
43
+
44
+ Every field on a delta exists for a reason:
45
+
46
+ | Field | Meaning |
47
+ |---|---|
48
+ | `layer` | Which layer (by id) this delta animates |
49
+ | `property` | Which animatable property (e.g. `opacity`, `frame.x`, `style.color`) |
50
+ | `from` | Starting value at `startFrame` |
51
+ | `to` | Ending value at `endFrame` |
52
+ | `startFrame` | Frame within the state where this delta begins |
53
+ | `endFrame` | Frame within the state where this delta ends |
54
+ | `easing` | How the value interpolates between `from` and `to` |
55
+ | `expression` | Optional override — a function of `t` (0..1) returning the interpolated value, for non-trivial animations |
56
+
57
+ Outside `[startFrame, endFrame]`, the property holds its boundary value (clamped). Multiple deltas on the same `layer` + `property` are rejected by the schema's no-overlap gate — overlapping motion is almost always a bug; if you need composition, use two layers or a `group`.
58
+
59
+ ## `resolveFrame` is the whole engine in one function
60
+
61
+ ```ts
62
+ const scene = resolveFrame(doc, stateName, frameNumber);
63
+ // scene is { layers: ResolvedLayer[] } — every property concrete, no deltas
64
+ ```
65
+
66
+ What it does, in order:
67
+
68
+ 1. Look up the state by name. If it doesn't exist, throw.
69
+ 2. For each layer in `doc.layers`, start with its authored values.
70
+ 3. For each delta in `state.deltas`:
71
+ - If `frameNumber < startFrame`, the layer's property stays at `from`.
72
+ - If `frameNumber > endFrame`, the layer's property stays at `to`.
73
+ - If between: compute `t = (frameNumber - startFrame) / (endFrame - startFrame)`, run `t` through the easing function (returning `t'`), then interpolate `from + (to - from) * t'`.
74
+ 4. Apply parent transforms (if a layer has `parentId`), motion paths, clip paths, tints.
75
+ 5. Return the resolved scene — every layer now has concrete property values ready for the renderer.
76
+
77
+ The renderer (canvas, SVG export, Lottie export, video exporter) all consume the same `ResolvedLayer[]` output. Adding a new renderer is "consume one frame at a time"; adding a new animatable property is "add to the interpolation switch."
78
+
79
+ ## Hierarchical states and transitions
80
+
81
+ States can declare a `parent` (extending another state's deltas) and a `transitions` block (named transitions from one state to another with their own duration, easing, and target deltas). This is the foundation of interactive UI motion — `hover` extends `default` with extra deltas, `pressed` transitions from `hover` with a 200ms ease-out. Full coverage in ATEL-401 (State Machines & Motion).
82
+
83
+ ## Inspecting a frame from the CLI
84
+
85
+ ```bash
86
+ atelier preview hello.atelier --frame 15
87
+ atelier preview hello.atelier --frame 15 --state hover
88
+ ```
89
+
90
+ The output is the same `ResolvedLayer[]` array `resolveFrame` produces — perfect for debugging "what does the engine actually think this scene looks like at frame N?"
91
+
92
+ For multi-frame inspection, `atelier_batch_preview` (MCP) or `atelier diff_frames` (CLI) compare two frames side by side.
93
+
94
+ Next: easings.
@@ -0,0 +1,72 @@
1
+ ---
2
+ id: N-atel-101-the-atelier-format
3
+ title: The `.atelier` document format
4
+ type: note
5
+ track: ATEL-101
6
+ author: atelier
7
+ created: '2026-05-18'
8
+ updated: '2026-05-18'
9
+ tags:
10
+ - course
11
+ - atel-101
12
+ - format
13
+ - schema
14
+ difficulty: beginner
15
+ estimatedMinutes: 4
16
+ prerequisites:
17
+ - N-atel-001-first-render
18
+ summary: The top-level shape of an `.atelier` YAML document — canvas, layers, states, assets, variables, presets, templates. Every field exists for one reason, named for what it means.
19
+ ---
20
+
21
+ ## The five required parts
22
+
23
+ Every `.atelier` document is YAML with five mandatory top-level keys:
24
+
25
+ ```yaml
26
+ name: My Animation # human-readable label
27
+ canvas: # global render context
28
+ width: 800
29
+ height: 600
30
+ fps: 60
31
+ background: "#0F1115" # optional, defaults to transparent
32
+ layers: [ ... ] # ordered array of visual elements
33
+ states: # named keyframes (always at least one)
34
+ default:
35
+ duration: 60 # in frames
36
+ deltas: [ ... ]
37
+ ```
38
+
39
+ That is the minimum. Validators accept it. The renderer can resolve any frame in the `default` state.
40
+
41
+ ## The optional parts
42
+
43
+ Any of these can be absent. Add them when you need them.
44
+
45
+ | Key | What it holds | When you need it |
46
+ |---|---|---|
47
+ | `assets` | External resources (images, videos, audio) referenced by `assetId` from layers | The moment you add an image or video layer |
48
+ | `variables` | Named values referenced by `${name}` in templates and expression-driven deltas | When you want to parametrize a document or template |
49
+ | `presets` | Reusable delta bundles applied by name | When the same animation pattern repeats across layers |
50
+ | `templates` | Reusable layer subtrees instantiated by name with variable substitution | Carousels, lower-thirds, repeating motifs |
51
+ | `audio` | Audio track + sync metadata | Video projects with sound |
52
+ | `meta` | Free-form metadata (author, tags, source notes) | Anything you want a downstream tool to read |
53
+
54
+ ## The order of keys is not meaningful (to the engine)
55
+
56
+ YAML is unordered for objects. The schema doesn't care whether `states` comes before `layers`. Conventionally we write them top-down — `name`, `canvas`, `assets`, `variables`, `presets`, `templates`, `layers`, `states`, `audio`, `meta` — because that order roughly matches "global setup → reusable bits → scene → motion → output."
57
+
58
+ ## The order of `layers` IS meaningful
59
+
60
+ Layers render back-to-front. Index 0 is drawn first (background); the last layer is on top. This is also the order the layer panel shows them in the studio (top of the list = top of the stack, matching most design-tool conventions — the array is rendered bottom-up for display).
61
+
62
+ ## Layer IDs and references
63
+
64
+ Every layer needs an `id` that is unique within the document. Deltas reference layers by id (`layer: title`). Parent-child relationships use `parentId`. Templates reference instance ids. The schema enforces uniqueness and rejects dangling references at validate time — you don't have to track them by hand.
65
+
66
+ Conventionally, layer ids are kebab-case (`title`, `subtitle`, `clip-trim-1`, `caption-word-7`). Pipeline-generated layers carry a tag namespace prefix in the id: `silence-trim-N`, `caption-N`, `caption-word-N`, `overlay-N`. The tags drive the layer-tag isolation invariant (ATEL-501).
67
+
68
+ ## Reading order for the rest of ATEL-101
69
+
70
+ 1. **Layers** — anatomy of a single layer: visual, frame, bounds, anchor, opacity, rotation, scale, parent, visible, motion path, clip path, blend mode, shadow, tint, interactions
71
+ 2. **States and deltas** — what a state is, what a delta is, how `resolveFrame(doc, stateName, frame)` produces a renderable scene
72
+ 3. **Easings** — linear / cubic-bezier / ease presets / spring / step; the math you don't have to remember but should recognize