@a-company/atelier 0.29.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 (76) hide show
  1. package/dist/chunk-5QQESXI6.js +4432 -0
  2. package/dist/chunk-5QQESXI6.js.map +1 -0
  3. package/dist/cli.cjs +2391 -530
  4. package/dist/cli.cjs.map +1 -1
  5. package/dist/cli.js +301 -429
  6. package/dist/cli.js.map +1 -1
  7. package/dist/index.cjs +2233 -38
  8. package/dist/index.cjs.map +1 -1
  9. package/dist/index.d.cts +584 -2
  10. package/dist/index.d.ts +584 -2
  11. package/dist/index.js +111 -3
  12. package/dist/mcp.cjs +1215 -365
  13. package/dist/mcp.cjs.map +1 -1
  14. package/dist/mcp.js +1209 -365
  15. package/dist/mcp.js.map +1 -1
  16. package/package.json +20 -9
  17. package/src/web/inline-app.ts +867 -0
  18. package/src/web/tsconfig.json +9 -0
  19. package/templates/welcome.atelier +67 -0
  20. package/university/content/notes/N-atel-001-first-render.md +114 -0
  21. package/university/content/notes/N-atel-001-install-and-launch.md +84 -0
  22. package/university/content/notes/N-atel-001-what-is-atelier.md +51 -0
  23. package/university/content/notes/N-atel-101-easings.md +97 -0
  24. package/university/content/notes/N-atel-101-layers.md +106 -0
  25. package/university/content/notes/N-atel-101-states-and-deltas.md +94 -0
  26. package/university/content/notes/N-atel-101-the-atelier-format.md +72 -0
  27. package/university/content/notes/N-atel-201-authoring-tools.md +141 -0
  28. package/university/content/notes/N-atel-201-mcp-overview.md +86 -0
  29. package/university/content/notes/N-atel-201-patterns.md +108 -0
  30. package/university/content/notes/N-atel-201-visual-and-effects.md +125 -0
  31. package/university/content/notes/N-atel-301-composition-and-overlays.md +141 -0
  32. package/university/content/notes/N-atel-301-effects.md +136 -0
  33. package/university/content/notes/N-atel-301-images-and-video.md +126 -0
  34. package/university/content/notes/N-atel-301-shapes-and-text.md +118 -0
  35. package/university/content/notes/N-atel-401-hierarchical-states.md +71 -0
  36. package/university/content/notes/N-atel-401-motion-deep-dive.md +106 -0
  37. package/university/content/notes/N-atel-401-presets-and-templates.md +98 -0
  38. package/university/content/notes/N-atel-401-transitions.md +94 -0
  39. package/university/content/notes/N-atel-501-detected-vs-user-edited.md +76 -0
  40. package/university/content/notes/N-atel-501-layer-tag-isolation.md +62 -0
  41. package/university/content/notes/N-atel-501-silence-trim.md +98 -0
  42. package/university/content/notes/N-atel-501-transcribe-and-captions.md +98 -0
  43. package/university/content/notes/N-atel-601-carousel.md +71 -0
  44. package/university/content/notes/N-atel-601-overlay-rules.md +96 -0
  45. package/university/content/notes/N-atel-601-recipe-tools-and-apply.md +84 -0
  46. package/university/content/notes/N-atel-601-studio-recipe.md +103 -0
  47. package/university/content/notes/N-atel-701-choosing-output.md +68 -0
  48. package/university/content/notes/N-atel-701-png-and-frames.md +84 -0
  49. package/university/content/notes/N-atel-701-vector.md +85 -0
  50. package/university/content/notes/N-atel-701-video.md +88 -0
  51. package/university/content/notes/N-atel-801-editing-surface.md +69 -0
  52. package/university/content/notes/N-atel-801-live-bridge.md +84 -0
  53. package/university/content/notes/N-atel-801-studio-app.md +72 -0
  54. package/university/content/notes/N-atel-801-symbiotic-loop.md +56 -0
  55. package/university/content/paths/LP-atel-001.yaml +21 -0
  56. package/university/content/paths/LP-atel-101.yaml +22 -0
  57. package/university/content/paths/LP-atel-201.yaml +23 -0
  58. package/university/content/paths/LP-atel-301.yaml +22 -0
  59. package/university/content/paths/LP-atel-401.yaml +22 -0
  60. package/university/content/paths/LP-atel-501.yaml +22 -0
  61. package/university/content/paths/LP-atel-601.yaml +22 -0
  62. package/university/content/paths/LP-atel-701.yaml +22 -0
  63. package/university/content/paths/LP-atel-801.yaml +22 -0
  64. package/university/content/quizzes/Q-atel-001-orientation.yaml +66 -0
  65. package/university/content/quizzes/Q-atel-101-document-model.yaml +66 -0
  66. package/university/content/quizzes/Q-atel-201-mcp-authoring.yaml +66 -0
  67. package/university/content/quizzes/Q-atel-301-visual-system.yaml +66 -0
  68. package/university/content/quizzes/Q-atel-401-state-machines.yaml +66 -0
  69. package/university/content/quizzes/Q-atel-501-video-pipeline.yaml +66 -0
  70. package/university/content/quizzes/Q-atel-601-recipes.yaml +66 -0
  71. package/university/content/quizzes/Q-atel-701-export.yaml +66 -0
  72. package/university/content/quizzes/Q-atel-801-studio-loop.yaml +66 -0
  73. package/university/index.yaml +720 -0
  74. package/university/pack.yaml +21 -0
  75. package/dist/chunk-JV7RGETS.js +0 -2292
  76. package/dist/chunk-JV7RGETS.js.map +0 -1
@@ -0,0 +1,84 @@
1
+ ---
2
+ id: N-atel-801-live-bridge
3
+ title: The live bridge — WebSocket, MCP-over-WS, and source-tagged mutations
4
+ type: note
5
+ track: ATEL-801
6
+ author: atelier
7
+ created: '2026-05-20'
8
+ updated: '2026-05-20'
9
+ tags:
10
+ - course
11
+ - atel-801
12
+ - bridge
13
+ - mcp
14
+ - aspects
15
+ difficulty: advanced
16
+ estimatedMinutes: 6
17
+ prerequisites:
18
+ - N-atel-201-mcp-overview
19
+ summary: How an agent mutates the open studio document in real time — the /bridge WebSocket and /mcp MCP-over-WS transport, DocumentStore.onChange → broadcast, AtelierStudio.applyMutation, and the ~source-tagged-mutation aspect (human|llm|system; only llm broadcasts) that prevents echo loops and false attribution. Plus toast attribution and Cmd-Z undo of an agent edit.
20
+ ---
21
+
22
+ ## Two endpoints on one server
23
+
24
+ `atelier studio` mounts two WebSocket endpoints on Vite's HTTP server:
25
+
26
+ - **`/mcp`** — an MCP-over-WebSocket transport. An external MCP client (e.g. Claude Desktop running `atelier-mcp`) connects here and drives the same 61 tools it would over stdio. Each connection gets its own `McpServer`, but they all share **one** `DocumentStore`. The transport (`WebSocketServerTransport`) wraps a single `ws` socket as an MCP `Transport`: inbound frames parse to JSON-RPC and surface via `onmessage`; outbound SDK messages stringify and `ws.send`. A malformed inbound frame surfaces via `onerror` but does NOT close the connection.
27
+ - **`/bridge`** — a thin broadcast channel to the browser. It carries typed envelopes (`hello`, `doc:loaded`, `doc:patch`, `llm:mutation`, `error`) at `BRIDGE_PROTOCOL_VERSION = 1`. v1 ships whole-document replacement so the envelope stays trivial; a JSON-patch op shape is v1.1, once the byte cost is measured on real docs.
28
+
29
+ ## The Origin asymmetry
30
+
31
+ WS upgrades bypass Vite's connect middleware (Node fires `upgrade` before connect runs), so the bridge re-runs the Origin check itself on every upgrade — otherwise either endpoint would be cross-origin-reachable from any tab. The check is asymmetric:
32
+
33
+ - **`/bridge`** demands a strict same-origin match (`isAllowedOrigin`) — it's a real browser origin, your own studio tab.
34
+ - **`/mcp`** tolerates a **missing** Origin (`isAllowedMcpOrigin`) but still rejects a present-but-foreign one. Non-browser MCP clients send NO Origin header; under the strict check they'd all 403 and MCP-over-WS would be unreachable. A browser tab on evil.com still can't reach `/mcp` (it sends a foreign Origin). The loopback bind to `127.0.0.1` remains the primary protection.
35
+
36
+ ## The mutation loop
37
+
38
+ The full agent→human loop:
39
+
40
+ ```
41
+ LLM tool call ──► McpServer (per /mcp conn) ──► DocumentStore.set(source:"llm")
42
+
43
+ onChange fires (source = "llm")
44
+
45
+ bridge broadcasts `llm:mutation` envelope
46
+
47
+ browser studio.applyMutation({ type:"doc:replace", doc, source })
48
+
49
+ canvas re-renders + toast attribution (Cmd-Z still works)
50
+ ```
51
+
52
+ And the human→agent direction:
53
+
54
+ ```
55
+ human edit ──► AtelierStudio.onDocumentChange ──► `doc:patch` envelope
56
+
57
+ bridge writes DocumentStore.set(source:"human")
58
+
59
+ onChange fires (source = "human") → NOT broadcast
60
+ ```
61
+
62
+ `applyMutation` is whole-document replacement only in v1 — the op shape is exactly `{ type: "doc:replace", doc, source }`. It snapshots the current state into undo history first (so an agent edit is undoable from your seat), preserves the current state name and selected layer when they still exist in the new doc, and sets a one-tick `suppressNotify` flag so the resulting re-render doesn't echo the change back out as a "human" edit.
63
+
64
+ ## ~source-tagged-mutation — the aspect that makes the loop safe
65
+
66
+ Every `DocumentStore` mutation carries a **source tag**: `"human" | "llm" | "system"`. This is the load-bearing convention behind the live bridge, and it answers one question: *which changes should the browser be told about?*
67
+
68
+ The rule, expressed in code as `shouldBroadcastMutation(source)`, is: **broadcast only when `source === "llm"`.**
69
+
70
+ | Source | Where it comes from | Broadcast? | Why |
71
+ |---|---|---|---|
72
+ | `llm` | An MCP tool call over `/mcp` | **Yes** | A genuine agent edit — show it, persist it, toast it |
73
+ | `human` | The browser's own edit via `doc:patch` (or `POST /api/file`) | No | The browser is already current — broadcasting would echo the edit back to the tab that made it |
74
+ | `system` | File-read hydration (a file the user just opened) | No | The bytes are already on disk and in the browser — broadcasting would fire a phantom "agent edited document" toast and a bogus undo entry on a plain file-open |
75
+
76
+ Without this filter you'd get two failure modes: an **echo loop** (the browser's edit bounces back and re-applies) and **false attribution** (opening a file looks like an agent edited it). The tag travels end-to-end — the MCP-side `MutationSource`, the bridge envelope, and the studio-side `MutationSource` are the same three strings, so no translation happens between processes.
77
+
78
+ It also pairs with **~copy-on-write-doc**: any code that mutates a document builds a NEW document object before calling `DocumentStore.set`, never mutating the stored object in place. That guarantees the bridge — a concurrent reader broadcasting to the browser — can never observe a half-mutated document mid-update.
79
+
80
+ ## Toast attribution and Cmd-Z
81
+
82
+ When an `llm:mutation` lands and matches the file you're viewing, the studio applies it and shows a bottom-right toast: *"agent edited document (`<tool>`) — Cmd-Z to undo"*. Because `applyMutation` snapshotted before replacing, **Cmd-Z returns the prior state** — an agent's edit is just another entry in your undo history. The agent and you share one timeline.
83
+
84
+ That shared, attributable, undoable timeline is the whole point. The next note ties it into a complete workflow.
@@ -0,0 +1,72 @@
1
+ ---
2
+ id: N-atel-801-studio-app
3
+ title: '`atelier studio` — the local-first editor'
4
+ type: note
5
+ track: ATEL-801
6
+ author: atelier
7
+ created: '2026-05-20'
8
+ updated: '2026-05-20'
9
+ tags:
10
+ - course
11
+ - atel-801
12
+ - studio
13
+ - cli
14
+ difficulty: advanced
15
+ estimatedMinutes: 5
16
+ prerequisites:
17
+ - N-atel-201-mcp-overview
18
+ summary: What `atelier studio` launches — a Vite-backed browser editor bound to 127.0.0.1, the welcome.atelier scaffold on an empty directory, the sidebar file list + "+ New", and the autosave coordinator whose flush-on-switch prevents .atelier corruption. Flags — --port, --no-open.
19
+ ---
20
+
21
+ ## What the command does
22
+
23
+ `atelier studio [file]` spins up a local Vite dev server, writes a tiny entry shim into a temp directory that imports the browser client (`bootStudioApp`), and opens your browser. The client is a real, typechecked TypeScript module — `src/web/inline-app.ts` — not a string. (It used to be a ~700-LOC template-literal string with no typecheck, no lint, no tests; two real bugs hid there precisely because the compiler never saw it. More on both below.)
24
+
25
+ The server reads and writes `.atelier` files from your current working directory. There is no project file, no auth token, no cloud round-trip. You point it at a folder and edit.
26
+
27
+ ```
28
+ atelier studio → browse all .atelier files in CWD
29
+ atelier studio my-animation.atelier → open a specific file
30
+ atelier studio --port 8080 → custom port (default 4321)
31
+ atelier studio --no-open → don't auto-open the browser
32
+ ```
33
+
34
+ Those are the flags the command actually registers: `-p, --port <number>` and `--no-open`. Nothing else.
35
+
36
+ ## ^localhost-only
37
+
38
+ The server binds explicitly to `127.0.0.1` — not the string `"localhost"`. Vite's default already resolves to loopback, but pinning the literal IP makes the invariant intentional and auditable, and it defeats any future change in Vite's defaults. The dev server cannot be reached from another machine on the network.
39
+
40
+ This matters because the studio exposes mutating endpoints (`POST /api/file` writes `.atelier` files into your CWD) and two WebSocket endpoints (`/bridge` and `/mcp`). Two layers protect them:
41
+
42
+ 1. **The loopback bind** — the primary protection. Off-machine traffic never arrives.
43
+ 2. **An Origin check** on every mutating REST request and on every WS upgrade. Without it, any browser tab on any site could `fetch('http://localhost:4321/api/file', { method: 'POST', ... })` and write files into your project. (The WS Origin check has a subtlety covered in the live-bridge note.)
44
+
45
+ ## The welcome scaffold
46
+
47
+ Run `atelier studio` in an empty directory and you don't land on a dead-end empty-state. If CWD contains zero `.atelier` files, the command copies the bundled `welcome.atelier` template into the folder so you open onto something real. It skips files that already exist, so re-running never overwrites your work.
48
+
49
+ The welcome scaffold ships a placeholder layer whose **id is `background`** — a specific id contract, not a fuzzy description. The first image you drop replaces that layer in place (see the editing-surface note). The scaffold is a 1080×1080 social-square so you start at the most common authoring size.
50
+
51
+ ## The sidebar and "+ New"
52
+
53
+ The left sidebar lists every `.atelier` file under CWD (recursively, grouped by folder), fetched from `/api/files`. Click an entry to load it. The `+ New` button prompts for a name, writes a minimal-but-non-empty starter document (one centered text layer on a 1080×1080 canvas so the canvas isn't a confusing void), refreshes the list, and selects the new file. A "new file" is just a `POST /api/file` of a fresh starter doc followed by a list refresh — there's no special server-side create path.
54
+
55
+ ## Autosave and the save-race that corrupted files
56
+
57
+ The studio autosaves on every document change with an **800ms debounce**. The status bar flips to "saving…" the instant you edit, then "✓ saved" once the write lands (with a click-to-retry affordance if the write fails).
58
+
59
+ The debounce hides a bug that was real and nasty (`#cli-studio` autosave corruption):
60
+
61
+ > Edit file A → switch to file B within the 800ms window. The pending timer closed over A's *doc* but read the GLOBAL current file at fire time — which by then was B — so A's bytes were written to B's path. Real `.atelier` corruption.
62
+
63
+ The fix is twofold, and both halves matter:
64
+
65
+ 1. **Capture the target path AND serialized bytes in the timer closure.** A fired timer always writes the bytes it was given to the file it was scheduled for — never whatever the "current" file later becomes.
66
+ 2. **Flush the pending save before switching files.** `loadFile` calls `flushPendingSave()` at its very top, writing any in-flight edit to its OWN path, then clears the timer. No edit is dropped and no cross-file write can occur.
67
+
68
+ This logic is extracted into a real, unit-testable class — `SaveCoordinator` (`schedule`, `flushPending`, `cancel`) — so the save-race can be reasoned about in isolation. The inline browser app embeds the **same manual debounce pattern** (it does not import the class); the path/bytes capture and the flush-on-switch are preserved verbatim so there's exactly one behavior to trust.
69
+
70
+ ## What you've got after boot
71
+
72
+ A browser window bound to loopback, a file sidebar, an editing canvas, autosave you can trust across file switches, and — quietly — a WebSocket bridge already connected and waiting for an agent. The next note covers what you can do on the canvas; the one after covers the agent.
@@ -0,0 +1,56 @@
1
+ ---
2
+ id: N-atel-801-symbiotic-loop
3
+ title: The symbiotic loop — ingest, compose, co-edit, export
4
+ type: note
5
+ track: ATEL-801
6
+ author: atelier
7
+ created: '2026-05-20'
8
+ updated: '2026-05-20'
9
+ tags:
10
+ - course
11
+ - atel-801
12
+ - workflow
13
+ - import
14
+ - vision
15
+ difficulty: advanced
16
+ estimatedMinutes: 6
17
+ prerequisites:
18
+ - N-atel-201-mcp-overview
19
+ summary: The whole vision in one workflow — an agent runs an external generator in chat, atelier_import_images brings the results into the open doc, the human watches them appear live and keeps or undoes them, recipes and overlays compose the set, and atelier carousel exports it. Atelier owns no generation; it ingests, composes, and lets the human and agent co-edit one document.
20
+ ---
21
+
22
+ ## Atelier owns no generation
23
+
24
+ This is the thesis of the whole track: **Atelier does not generate images, video, audio, or text.** It has no diffusion model, no text-to-image tool, no in-process generator. What it owns is the part that's hard and durable — a declarative document model, a renderer, a recipe/overlay composition layer, and a live editing loop shared between a human and an agent.
25
+
26
+ Generation lives outside Atelier, in whatever tool the agent chooses to shell out to. Atelier's job begins when the bytes exist: it **ingests** them, **composes** them, and lets you and the agent **co-edit** the result.
27
+
28
+ ## The loop, end to end
29
+
30
+ Picture a single chat session with the studio open in your browser:
31
+
32
+ 1. **The agent generates — outside Atelier.** You ask for a set of images. The agent runs an external generator from chat — for example a Higgsfield CLI — and writes the results to a folder. None of this touches Atelier; it's the agent driving a separate tool.
33
+
34
+ 2. **`atelier_import_images` ingests.** The agent calls the import tool. Each image becomes an ImageVisual layer with a matching `doc.assets` entry, added to the open document via a source-tagged-`llm` mutation. (Like every document-mutating tool, import builds a new document before calling `DocumentStore.set` — ~copy-on-write-doc — so the bridge never reads a half-built doc.)
35
+
36
+ 3. **You watch them appear — live.** Because the mutation is `source: "llm"`, the bridge broadcasts it. The layers materialize on your canvas as the agent imports them, each with a toast: *"agent edited document — Cmd-Z to undo"*. You're not waiting for a render-and-refresh cycle; you're watching the document fill in real time.
37
+
38
+ 4. **You keep or undo — per edit.** This is the symbiosis. A generated image that lands wrong? Cmd-Z, and it's gone — the agent's import was just an undo entry. The ones you like, you keep. You're curating the agent's output as it arrives, not after a batch finishes.
39
+
40
+ 5. **Recipes and overlays compose.** Apply a recipe to lay out the kept images; add a handle and page-number via the overlay namespace. The layer-tag isolation invariant (ATEL-301) means re-running a recipe drops only its own tagged layers — your imported images and any manual tweaks survive. You and the agent can both restyle without erasing each other's work.
41
+
42
+ 6. **`atelier carousel` exports the set.** The composed, multi-page result exports as a carousel — the page-number overlay threads `currentIndex` / `totalCount` per page during the batch.
43
+
44
+ ## Why both editors at one canvas
45
+
46
+ The agent is good at the mechanical breadth — running the generator, importing a dozen results, applying a recipe across all of them, threading per-page overlays. You're good at the judgment — *that* crop, *not* that one, nudge the handle two pixels. The live bridge and the source-tagged-mutation aspect exist so neither steps on the other:
47
+
48
+ - Every change is **attributed** (`human` vs `llm`) so the UI never lies about who did what.
49
+ - Every change is **undoable** from your seat, so the agent never makes an edit you can't take back.
50
+ - Every change flows through **one document store**, so there's a single source of truth — no merge, no divergence, last-write-wins.
51
+
52
+ ## The shape of the thing
53
+
54
+ Atelier is not a generator with an editor bolted on. It's a **composition surface** where a human and an agent edit the same document at the same time, with generation pushed to the edges. The agent brings breadth and the external tools; you bring taste and the veto; the document — declarative, rendered, source-tagged — is the contract between you.
55
+
56
+ That closes ATEL-801. You now understand `atelier studio` from the loopback bind up through the live bridge, and why the whole stack is built so an agent and a human can sit at one canvas without getting in each other's way.
@@ -0,0 +1,21 @@
1
+ id: LP-atel-001
2
+ title: 'ATEL-001: Hello Atelier'
3
+ description: Orientation track. What Atelier is, how to install it, how to launch the studio, and how to render a first animation from a hand-written `.atelier` document. ~12 minutes.
4
+ author: atelier
5
+ created: '2026-05-18'
6
+ updated: '2026-05-18'
7
+ tags:
8
+ - course
9
+ - atel-001
10
+ - orientation
11
+ ordered: true
12
+ steps:
13
+ - content: N-atel-001-what-is-atelier
14
+ required: true
15
+ - content: N-atel-001-install-and-launch
16
+ required: true
17
+ - content: N-atel-001-first-render
18
+ required: true
19
+ - content: Q-atel-001-orientation
20
+ required: true
21
+ passRequired: true
@@ -0,0 +1,22 @@
1
+ id: LP-atel-101
2
+ title: 'ATEL-101: Document Model Fundamentals'
3
+ description: The vocabulary every Atelier user needs. The `.atelier` format, layer anatomy, states/deltas/resolveFrame, easings. After this track you can read any Atelier document and predict what it renders. ~18 minutes.
4
+ author: atelier
5
+ created: '2026-05-18'
6
+ updated: '2026-05-18'
7
+ tags:
8
+ - course
9
+ - atel-101
10
+ ordered: true
11
+ steps:
12
+ - content: N-atel-101-the-atelier-format
13
+ required: true
14
+ - content: N-atel-101-layers
15
+ required: true
16
+ - content: N-atel-101-states-and-deltas
17
+ required: true
18
+ - content: N-atel-101-easings
19
+ required: true
20
+ - content: Q-atel-101-document-model
21
+ required: true
22
+ passRequired: true
@@ -0,0 +1,23 @@
1
+ id: LP-atel-201
2
+ title: 'ATEL-201: Authoring via MCP'
3
+ description: How an AI agent (or any MCP scripter) builds, edits, and inspects Atelier documents through the 51-tool surface. Covers the single-store invariant, the 16 tool groups, common authoring patterns, and the four most common agent mistakes. ~20 minutes.
4
+ author: atelier
5
+ created: '2026-05-18'
6
+ updated: '2026-05-18'
7
+ tags:
8
+ - course
9
+ - atel-201
10
+ - mcp
11
+ ordered: true
12
+ steps:
13
+ - content: N-atel-201-mcp-overview
14
+ required: true
15
+ - content: N-atel-201-authoring-tools
16
+ required: true
17
+ - content: N-atel-201-visual-and-effects
18
+ required: true
19
+ - content: N-atel-201-patterns
20
+ required: true
21
+ - content: Q-atel-201-mcp-authoring
22
+ required: true
23
+ passRequired: true
@@ -0,0 +1,22 @@
1
+ id: LP-atel-301
2
+ title: 'ATEL-301: Visual System'
3
+ description: The non-motion visual surface — shapes, text, images, video, effects, composition, and the overlay namespace. After this track you can compose any static scene in Atelier and understand how recipes and the layer-tag isolation invariant make overlays safe across re-runs. ~20 minutes.
4
+ author: atelier
5
+ created: '2026-05-18'
6
+ updated: '2026-05-18'
7
+ tags:
8
+ - course
9
+ - atel-301
10
+ ordered: true
11
+ steps:
12
+ - content: N-atel-301-shapes-and-text
13
+ required: true
14
+ - content: N-atel-301-images-and-video
15
+ required: true
16
+ - content: N-atel-301-effects
17
+ required: true
18
+ - content: N-atel-301-composition-and-overlays
19
+ required: true
20
+ - content: Q-atel-301-visual-system
21
+ required: true
22
+ passRequired: true
@@ -0,0 +1,22 @@
1
+ id: LP-atel-401
2
+ title: 'ATEL-401: State Machines & Motion'
3
+ description: 'From states-as-data to interactive, physically-tuned, reusable motion. Hierarchical states and their merge rule, transitions and the interaction layer, the motion deep dive (springs, expression-valued deltas, motion paths), and the preset-vs-template distinction. After this track you can build and package interactive UI motion in Atelier. ~27 minutes.'
4
+ author: atelier
5
+ created: '2026-05-20'
6
+ updated: '2026-05-20'
7
+ tags:
8
+ - course
9
+ - atel-401
10
+ ordered: true
11
+ steps:
12
+ - content: N-atel-401-hierarchical-states
13
+ required: true
14
+ - content: N-atel-401-transitions
15
+ required: true
16
+ - content: N-atel-401-motion-deep-dive
17
+ required: true
18
+ - content: N-atel-401-presets-and-templates
19
+ required: true
20
+ - content: Q-atel-401-state-machines
21
+ required: true
22
+ passRequired: true
@@ -0,0 +1,22 @@
1
+ id: LP-atel-501
2
+ title: 'ATEL-501: Video Project Pipeline'
3
+ description: 'The video pipeline — silence trimming with parametric cuts, Whisper transcription, the transcript edit family, and caption generation. Two aspects make the loop safe: detections are immutable while your overrides survive every re-run, and each pipeline touches only its own tagged layers. After this track you can drive a VideoProject end to end and re-run any stage without losing human work. ~24 minutes.'
4
+ author: atelier
5
+ created: '2026-05-20'
6
+ updated: '2026-05-20'
7
+ tags:
8
+ - course
9
+ - atel-501
10
+ ordered: true
11
+ steps:
12
+ - content: N-atel-501-silence-trim
13
+ required: true
14
+ - content: N-atel-501-transcribe-and-captions
15
+ required: true
16
+ - content: N-atel-501-detected-vs-user-edited
17
+ required: true
18
+ - content: N-atel-501-layer-tag-isolation
19
+ required: true
20
+ - content: Q-atel-501-video-pipeline
21
+ required: true
22
+ passRequired: true
@@ -0,0 +1,22 @@
1
+ id: LP-atel-601
2
+ title: 'ATEL-601: Recipes, Overlays & Carousel'
3
+ description: 'Style as a reusable preset — the Studio Recipe, anchored handle and page-number overlays, the CLI/MCP tooling and precedence, and the carousel batch driver that turns a folder of images into a numbered, branded post deck. After this track you can author a recipe, apply it through the CLI and MCP, and batch-compose a carousel. ~22 minutes.'
4
+ author: atelier
5
+ created: '2026-05-20'
6
+ updated: '2026-05-20'
7
+ tags:
8
+ - course
9
+ - atel-601
10
+ ordered: true
11
+ steps:
12
+ - content: N-atel-601-studio-recipe
13
+ required: true
14
+ - content: N-atel-601-overlay-rules
15
+ required: true
16
+ - content: N-atel-601-recipe-tools-and-apply
17
+ required: true
18
+ - content: N-atel-601-carousel
19
+ required: true
20
+ - content: Q-atel-601-recipes
21
+ required: true
22
+ passRequired: true
@@ -0,0 +1,22 @@
1
+ id: LP-atel-701
2
+ title: 'ATEL-701: Export & Delivery'
3
+ description: Getting work out of Atelier — single-frame raster (PNG), vector (SVG and Lottie), and video (MP4/GIF via FFmpeg, WebM via the studio), then a decision guide that picks a format by destination. After this track you can choose the right exporter for any target and know which paths need extra dependencies. ~25 minutes.
4
+ author: atelier
5
+ created: '2026-05-20'
6
+ updated: '2026-05-20'
7
+ tags:
8
+ - course
9
+ - atel-701
10
+ ordered: true
11
+ steps:
12
+ - content: N-atel-701-png-and-frames
13
+ required: true
14
+ - content: N-atel-701-vector
15
+ required: true
16
+ - content: N-atel-701-video
17
+ required: true
18
+ - content: N-atel-701-choosing-output
19
+ required: true
20
+ - content: Q-atel-701-export
21
+ required: true
22
+ passRequired: true
@@ -0,0 +1,22 @@
1
+ id: LP-atel-801
2
+ title: 'ATEL-801: Studio & the Live Agent Loop'
3
+ description: 'The live editing loop — `atelier studio` as a local-first browser editor, the editing surface (layer-type picker, image drop, slider commit-gating), the WebSocket bridge + MCP-over-WS transport that lets an agent mutate the open document in real time, and the symbiotic pattern where the human and agent co-edit the same single-store doc. After this track you understand how Atelier turns a chat conversation into a live, undoable canvas. ~22 minutes.'
4
+ author: atelier
5
+ created: '2026-05-20'
6
+ updated: '2026-05-20'
7
+ tags:
8
+ - course
9
+ - atel-801
10
+ ordered: true
11
+ steps:
12
+ - content: N-atel-801-studio-app
13
+ required: true
14
+ - content: N-atel-801-editing-surface
15
+ required: true
16
+ - content: N-atel-801-live-bridge
17
+ required: true
18
+ - content: N-atel-801-symbiotic-loop
19
+ required: true
20
+ - content: Q-atel-801-studio-loop
21
+ required: true
22
+ passRequired: true
@@ -0,0 +1,66 @@
1
+ id: Q-atel-001-orientation
2
+ title: 'ATEL-001: Hello Atelier — Orientation'
3
+ description: Verify the foundations from ATEL-001 — what Atelier is, how the three commands relate, and the shape of a minimal document.
4
+ author: atelier
5
+ created: '2026-05-18'
6
+ updated: '2026-05-18'
7
+ tags:
8
+ - course
9
+ - atel-001
10
+ difficulty: beginner
11
+ passThreshold: 0.7
12
+ questions:
13
+ - id: q1
14
+ question: Which of the following best describes what makes Atelier "AI-native"?
15
+ choices:
16
+ A: It uses an LLM at render time to generate frames procedurally
17
+ B: It ships with a chat interface bolted onto a traditional editor
18
+ C: Its document format and 52 MCP tools are designed for an agent to author directly, with typed mutations and schema-validated errors
19
+ D: It runs only when an AI assistant is connected, refusing programmatic CLI use
20
+ correct: C
21
+ explanation: Atelier is AI-native because the document format and the MCP tool surface were designed for an agent to author. Mutations go through typed tools (atelier_add_layer, atelier_add_state, etc.) that validate against a Zod schema with readable errors. The engine itself is deterministic — no LLM is involved at render time, and the CLI and Builder API are first-class for programmatic use.
22
+ - id: q2
23
+ question: After running `npm i -g @a-company/atelier`, which three commands are on your PATH and what is each one's primary role?
24
+ choices:
25
+ A: '`atelier` (CLI), `atelier-mcp` (MCP server for AI agents), `atelier studio` (local browser editor) — all share one engine and document store'
26
+ B: '`atelier` (only CLI) — the MCP server and studio require separate npm packages'
27
+ C: '`atelier` (CLI), `atelier-cloud` (sync to SaaS), `atelier-render` (rendering daemon)'
28
+ D: '`atelier-cli`, `atelier-server`, `atelier-gui` — three independent binaries that do not share state'
29
+ correct: A
30
+ explanation: One install provides three executables that share `@atelier/core`. The CLI is for scripts and inspection, the MCP server is what an AI agent connects to, and `atelier studio` boots a local browser editor. They all read and write the same `.atelier` files and, with the live bridge enabled, observe each other's mutations.
31
+ - id: q3
32
+ question: In a minimal `.atelier` document, what is the relationship between a layer, a state, and a delta?
33
+ choices:
34
+ A: 'A layer is a keyframe; a state is a property; a delta is a layer parented to another layer'
35
+ B: 'A layer describes what exists; a state names a duration; a delta interpolates one property of one layer over a frame range with an easing'
36
+ C: 'A layer is an export format; a state is a render preset; a delta is a diff between two documents'
37
+ D: 'They are interchangeable names for the same concept — pick whichever reads best'
38
+ correct: B
39
+ explanation: Layers describe what exists in the scene (shape/text/image/video). States are named keyframes with a duration in frames. Deltas animate one property of one layer from a `from` value to a `to` value across `startFrame`–`endFrame` with an easing. Everything else in Atelier — easings, presets, templates, interactions, refs — extends these three primitives.
40
+ - id: q4
41
+ question: 'The "detected-vs-user-edited" convention in Atelier is a design pattern that solves which problem?'
42
+ choices:
43
+ A: 'How to compress YAML files so they download faster'
44
+ B: 'How to let an AI agent and a human edit the same document repeatedly without one erasing the other'
45
+ C: 'How to detect whether a user is logged in to Atelier Cloud'
46
+ D: 'How to choose between Canvas 2D and WebGL at render time'
47
+ correct: B
48
+ explanation: 'When an Atelier pipeline (silence-trim, captions, agent mutations) generates layers, those layers carry a tag identifying their source. User edits set `userEdited` / `userAdded` / `hidden` flags. When the pipeline re-runs (re-transcribe, re-detect silence, re-propose layout), it matches existing entries by timing tolerance and preserves the user''s edits. The same idea generalizes to any source — human, agent, or pipeline — so the symbiotic loop never destroys authorship.'
49
+ - id: q5
50
+ question: What does `atelier studio` bind to by default, and why?
51
+ choices:
52
+ A: '0.0.0.0 — to let teammates connect from the same WiFi network'
53
+ B: '127.0.0.1 — to keep the editor local-only and prevent drive-by writes from any browser tab'
54
+ C: 'A randomized public IP — for cloud sync'
55
+ D: 'It does not bind to a port; it uses raw IPC'
56
+ correct: B
57
+ explanation: '`atelier studio` binds to 127.0.0.1 (loopback) so the server is only reachable from the same machine. Mutating endpoints additionally check the Origin header to reject cross-origin POSTs from random browser tabs. There is no LAN or cloud exposure by default — Atelier is a local-first tool.'
58
+ - id: q6
59
+ question: You ran `atelier preview hello.atelier --frame 15`. What did it output, and what is it equivalent to inside the engine?
60
+ choices:
61
+ A: 'A rendered PNG of frame 15 saved to disk — equivalent to `atelier export --frame 15`'
62
+ B: 'The resolved layer state at frame 15 (interpolated property values), the same as what the renderer calls `resolveFrame(doc, "default", 15)` produces'
63
+ C: 'A live video stream starting from frame 15'
64
+ D: 'Nothing — `preview` requires the studio to be running'
65
+ correct: B
66
+ explanation: '`atelier preview` calls the same `resolveFrame` function the renderer uses. It returns the interpolated layer state at that frame — every animatable property resolved through its delta and easing. Use it to inspect what the renderer would draw without actually rasterizing. For PNG output, use `atelier export --frame N --out file.png`.'
@@ -0,0 +1,66 @@
1
+ id: Q-atel-101-document-model
2
+ title: 'ATEL-101: Document Model Fundamentals'
3
+ description: Verify the document model — format shape, layer anatomy, states/deltas/resolveFrame, easings.
4
+ author: atelier
5
+ created: '2026-05-18'
6
+ updated: '2026-05-18'
7
+ tags:
8
+ - course
9
+ - atel-101
10
+ difficulty: beginner
11
+ passThreshold: 0.7
12
+ questions:
13
+ - id: q1
14
+ question: What are the five mandatory top-level keys in every `.atelier` document?
15
+ choices:
16
+ A: '`name`, `canvas`, `assets`, `variables`, `presets`'
17
+ B: '`name`, `canvas`, `layers`, `states`, plus at least one state with a `duration`'
18
+ C: '`title`, `description`, `frames`, `tracks`, `outputs`'
19
+ D: '`document`, `scene`, `keyframes`, `easings`, `version`'
20
+ correct: B
21
+ explanation: The minimum valid document has `name`, `canvas` (width/height/fps), `layers` array, and `states` with at least one named state containing a `duration`. `assets`, `variables`, `presets`, `templates`, `audio`, `meta` are all optional and added only when needed.
22
+ - id: q2
23
+ question: 'A layer has `frame: {x: 400, y: 300}`, `bounds: {width: 600, height: 80}`, and `anchorPoint: {x: 0.5, y: 0.5}`. Where on the canvas does the center of the layer sit?'
24
+ choices:
25
+ A: At canvas pixel (0, 0)
26
+ B: At canvas pixel (400, 300) — the anchor is the pivot, and `frame` positions the anchor
27
+ C: At canvas pixel (700, 380) — bottom-right of the layer
28
+ D: At canvas pixel (100, 260) — top-left of the layer
29
+ correct: B
30
+ explanation: '`anchorPoint` is normalized 0–1 inside the layer''s `bounds`. `{0.5, 0.5}` puts the anchor at the layer''s center. `frame` then positions that anchor on the canvas. So the layer''s center sits exactly at the `frame` coordinates (400, 300). The anchor is also the pivot for `rotation` and `scale`.'
31
+ - id: q3
32
+ question: Two deltas in the same state target the same layer and property, with overlapping `startFrame`/`endFrame` ranges. What happens?
33
+ choices:
34
+ A: The engine merges them by averaging the values
35
+ B: The second delta silently wins over the first
36
+ C: The schema rejects the document — the no-overlap gate blocks overlapping motion at validate time
37
+ D: Both deltas play simultaneously and the renderer additively combines them
38
+ correct: C
39
+ explanation: Atelier's `no-overlap` gate (in the document-builder) rejects overlapping deltas on the same layer+property because the result is almost always a bug. If you need composed motion, use two layers or a group. The error message names the conflicting deltas so you can fix them quickly.
40
+ - id: q4
41
+ question: 'What does `resolveFrame(doc, stateName, frameNumber)` return?'
42
+ choices:
43
+ A: A rendered PNG buffer
44
+ B: 'A ResolvedLayer array — every layer with all animatable properties interpolated through their deltas and easings to concrete values for that frame, ready for any renderer'
45
+ C: The list of deltas active at that frame
46
+ D: A diff against the previous frame
47
+ correct: B
48
+ explanation: '`resolveFrame` is the engine''s core: it returns a fully-resolved scene where every animatable property has a concrete value. Canvas 2D, SVG export, Lottie export, and the video exporter all consume this same array. Adding a new renderer is "consume ResolvedLayer[] one frame at a time."'
49
+ - id: q5
50
+ question: You want a UI element to slide in from the right and feel natural. Which easing is the right default?
51
+ choices:
52
+ A: '`linear` — constant rate is the cleanest'
53
+ B: '`ease-out` — decelerating motion is how organic things arrive (entrance animation convention across the industry)'
54
+ C: '`step(4)` — discrete jumps look modern'
55
+ D: '`ease-in` — acceleration into the final position'
56
+ correct: B
57
+ explanation: '`ease-out` (CSS cubic-bezier(0, 0, 0.2, 1)) is the de facto standard for UI entrance animation. The element decelerates as it arrives, mimicking a physical object losing momentum. `ease-in` is correct for exits, `linear` is correct for scrubbing/progress bars, and `step()` is for sprite-frame indexing or digital-readout feel. The general rule: if a physical object would do it, use spring or ease-out.'
58
+ - id: q6
59
+ question: Why do pipeline-generated layers carry tags like `silence-trim`, `caption`, or `overlay`?
60
+ choices:
61
+ A: 'Cosmetic — the tags only affect what color the layer appears as in the layer panel'
62
+ B: 'For pricing — each tag corresponds to a separately billed feature'
63
+ C: 'To enforce the layer-tag isolation invariant — re-running a pipeline drops only its own tagged layers; user-authored layers and other pipelines'' outputs are never touched'
64
+ D: 'For sorting alphabetically'
65
+ correct: C
66
+ explanation: Tags are how the pipelines (silence-trim, captions, overlays, future agent-driven pipelines) find layers they own. When `atelier captions regenerate` runs, it drops layers tagged `caption` and `caption-word` and writes fresh ones — but never touches layers tagged `silence-trim` or `overlay`, and never touches user-authored untagged layers. This is the load-bearing invariant that makes the human↔agent symbiotic loop safe.
@@ -0,0 +1,66 @@
1
+ id: Q-atel-201-mcp-authoring
2
+ title: 'ATEL-201: Authoring via MCP'
3
+ description: Verify the MCP tool surface — the single-store invariant, tool naming conventions, common authoring patterns, and the most-common agent mistakes.
4
+ author: atelier
5
+ created: '2026-05-18'
6
+ updated: '2026-05-18'
7
+ tags:
8
+ - course
9
+ - atel-201
10
+ difficulty: intermediate
11
+ passThreshold: 0.7
12
+ questions:
13
+ - id: q1
14
+ question: An AI agent calls `atelier_add_layer` while a human is editing the same document in `atelier studio`. The Studio's canvas re-renders within a frame. What architectural pattern makes this work?
15
+ choices:
16
+ A: The Studio polls the MCP server every 100ms for changes
17
+ B: 'There is one DocumentStore shared by both the MCP tool handlers and the Studio; mutations fire onChange, the WebSocket bridge broadcasts to Studio, Studio applies via applyMutation(op) with a suppress-notify flag'
18
+ C: The agent and the human edit separate copies that are merged by an operational-transform algorithm
19
+ D: 'The Studio receives a full document diff via HTTP long-poll on every keystroke'
20
+ correct: B
21
+ explanation: 'Atelier is single-author with an AI collaborator, not a multiplayer canvas. One in-memory DocumentStore is shared; mutations fire onChange; the bridge broadcasts to any connected Studio; the Studio applies via applyMutation(op) with a one-tick suppress-notify flag so the change does not echo back as a human edit. Conflict policy is last-write-wins, tagged source: "human" | "llm" so the UI can attribute changes.'
22
+ - id: q2
23
+ question: 'You are an agent. You call `atelier_add_delta` to animate `style.borderRadius` on a TextVisual layer. The tool returns an error. What is the correct response?'
24
+ choices:
25
+ A: 'Retry the same call — transient errors are common'
26
+ B: 'Read the error verbatim, recognize that borderRadius is not animatable on a text layer, choose a real text property (style.fontSize, style.color, opacity) and call again'
27
+ C: 'Edit the document file directly with `fs.writeFile` to bypass the validator'
28
+ D: 'Suppress the error and continue — the schema validation is advisory'
29
+ correct: B
30
+ explanation: 'The schema rejects animatable-property mismatches with AI-readable errors naming the exact field. The correct flow is read the error, fix the request, retry. Bypassing the validator is not possible (every tool call validates); editing files directly defeats the LLM↔Studio bridge and produces drift. The four most common agent mistakes are documented in the patterns note — this is mistake #1.'
31
+ - id: q3
32
+ question: 'Which two-tool pairing covers "I want this fade-in pattern on every title layer in three different states"?'
33
+ choices:
34
+ A: '`atelier_add_delta` called 9 times, once per (layer, state) pair — there is no other way'
35
+ B: '`atelier_define_preset` once to bundle the deltas, then `atelier_apply_preset` per layer per state with an optional offset for staggering'
36
+ C: '`atelier_instantiate_template` — templates are how repeated motion is expressed'
37
+ D: '`atelier_set_motion_path` once on each layer — motion paths handle all repetition'
38
+ correct: B
39
+ explanation: 'Presets bundle deltas; templates bundle layer subtrees. For "same motion on N layers" the right tool is `atelier_define_preset` + `atelier_apply_preset` with the `offset` parameter for staggering. Templates are for "same layer subtree" (group + children with variable substitution). One-of-a-kind motion should be hand-authored.'
40
+ - id: q4
41
+ question: How are layers in the overlay namespace (handle, page-number) protected from being destroyed when a recipe is re-applied?
42
+ choices:
43
+ A: They are stored in a separate file outside the document
44
+ B: 'They are tagged `overlay`; the `applyRecipeToOverlay` translator drops only overlay-tagged layers before re-adding, leaving user-authored layers and other pipelines'' outputs untouched'
45
+ C: A locking mechanism prevents re-application unless the user confirms
46
+ D: They are recreated identically every time; user edits are discarded by design
47
+ correct: B
48
+ explanation: 'Layer-tag isolation is the load-bearing invariant. Each pipeline owns a tag namespace (`silence-trim`, `caption`, `caption-word`, `overlay`) and re-running a pipeline drops only its own tagged layers. User-authored layers (untagged) and other pipelines'' outputs (different tag) are never touched. The same idea generalizes to agent mutations via the `source: "human" | "llm"` op tagging.'
49
+ - id: q5
50
+ question: 'Two `atelier_add_delta` calls target the same layer and the same property, with overlapping `startFrame`–`endFrame` ranges. What happens?'
51
+ choices:
52
+ A: The second call replaces the first silently
53
+ B: The values are averaged
54
+ C: 'The no-overlap gate rejects the second call with a field-level error naming both deltas; the agent must split into adjacent ranges or use two layers'
55
+ D: Both run additively at render time
56
+ correct: C
57
+ explanation: 'The no-overlap gate lives in the document builder and rejects overlapping deltas on the same layer + property. Overlapping motion is almost always a bug. The error message names both conflicting deltas so the fix is obvious — split into adjacent ranges, or compose by adding a second layer or a group.'
58
+ - id: q6
59
+ question: An agent is configuring a Claude Desktop client. The MCP config entry needed to connect to atelier-mcp is which of the following?
60
+ choices:
61
+ A: '`{ "mcpServers": { "atelier": { "command": "atelier-mcp" }}}` — that is the full config'
62
+ B: 'Requires an API token from atelier.dev'
63
+ C: 'Requires running `atelier login` first to provision credentials'
64
+ D: 'Requires manually starting `atelier-mcp serve` as a background process; the config points to its port'
65
+ correct: A
66
+ explanation: 'Atelier is local-first. The MCP config entry is one line — Claude Desktop spawns the `atelier-mcp` stdio process on demand. No tokens, no login, no separate daemon. To pin the project root, set `ATELIER_PROJECT_ROOT` in the env. To pair with `atelier studio` for live mutation, just run the studio — the bridge connection is auto-detected.'