@a-company/atelier 0.36.0 → 0.38.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.
- package/dist/{chunk-JPZ4F4PW.js → chunk-3ARBOSWY.js} +64 -5
- package/dist/chunk-3ARBOSWY.js.map +1 -0
- package/dist/cli.js +11469 -413
- package/dist/cli.js.map +1 -1
- package/dist/{dist-M67UZGFQ.js → dist-3YQK6PI6.js} +2 -2
- package/dist/index.cjs +3193 -227
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +701 -8
- package/dist/index.d.ts +701 -8
- package/dist/index.js +7237 -72
- package/dist/index.js.map +1 -1
- package/dist/mcp.js +2898 -507
- package/dist/mcp.js.map +1 -1
- package/package.json +14 -9
- package/src/web/inline-app.ts +55 -4
- package/src/web/timeline-state-types.ts +28 -0
- package/src/web/timeline-view.test.ts +99 -0
- package/src/web/timeline-view.ts +339 -0
- package/src/web/workspace-app.ts +3146 -0
- package/templates/workspace/.claude/agents/atelier-iris.md +75 -0
- package/templates/workspace/.claude/agents/atelier-lux.md +67 -0
- package/templates/workspace/.claude/agents/atelier-quill.md +61 -0
- package/templates/workspace/.gitignore +30 -0
- package/templates/workspace/.paradigm/personas/_shared/cascade-merge.md +172 -0
- package/templates/workspace/CLAUDE.md +93 -0
- package/templates/workspace/README.md +75 -0
- package/templates/workspace/SETUP.md +127 -0
- package/templates/workspace/_brand/.atelier-brand.yaml +34 -0
- package/templates/workspace/_brand/DESIGN.md +56 -0
- package/templates/workspace/_brand/SCRIPT.md +41 -0
- package/templates/workspace/_brand/STORYBOARD.md +33 -0
- package/templates/workspace/_packs/README.md +54 -0
- package/templates/workspace/projects/README.md +49 -0
- package/templates/workspace/workspace.atelier +22 -0
- package/university/content/notes/N-atel-001-first-render.md +114 -0
- package/university/content/notes/N-atel-001-install-and-launch.md +84 -0
- package/university/content/notes/N-atel-001-what-is-atelier.md +51 -0
- package/university/content/notes/N-atel-101-easings.md +97 -0
- package/university/content/notes/N-atel-101-layers.md +106 -0
- package/university/content/notes/N-atel-101-states-and-deltas.md +94 -0
- package/university/content/notes/N-atel-101-the-atelier-format.md +72 -0
- package/university/content/notes/N-atel-201-authoring-tools.md +141 -0
- package/university/content/notes/N-atel-201-mcp-overview.md +86 -0
- package/university/content/notes/N-atel-201-patterns.md +108 -0
- package/university/content/notes/N-atel-201-visual-and-effects.md +125 -0
- package/university/content/notes/N-atel-301-composition-and-overlays.md +141 -0
- package/university/content/notes/N-atel-301-effects.md +136 -0
- package/university/content/notes/N-atel-301-images-and-video.md +126 -0
- package/university/content/notes/N-atel-301-shapes-and-text.md +118 -0
- package/university/content/notes/N-atel-401-hierarchical-states.md +71 -0
- package/university/content/notes/N-atel-401-motion-deep-dive.md +106 -0
- package/university/content/notes/N-atel-401-presets-and-templates.md +98 -0
- package/university/content/notes/N-atel-401-transitions.md +94 -0
- package/university/content/notes/N-atel-501-detected-vs-user-edited.md +76 -0
- package/university/content/notes/N-atel-501-layer-tag-isolation.md +62 -0
- package/university/content/notes/N-atel-501-silence-trim.md +98 -0
- package/university/content/notes/N-atel-501-transcribe-and-captions.md +98 -0
- package/university/content/notes/N-atel-601-carousel.md +71 -0
- package/university/content/notes/N-atel-601-overlay-rules.md +96 -0
- package/university/content/notes/N-atel-601-recipe-tools-and-apply.md +84 -0
- package/university/content/notes/N-atel-601-studio-recipe.md +103 -0
- package/university/content/notes/N-atel-701-choosing-output.md +68 -0
- package/university/content/notes/N-atel-701-png-and-frames.md +84 -0
- package/university/content/notes/N-atel-701-vector.md +85 -0
- package/university/content/notes/N-atel-701-video.md +88 -0
- package/university/content/notes/N-atel-801-editing-surface.md +69 -0
- package/university/content/notes/N-atel-801-live-bridge.md +84 -0
- package/university/content/notes/N-atel-801-studio-app.md +72 -0
- package/university/content/notes/N-atel-801-symbiotic-loop.md +56 -0
- package/university/content/paths/LP-atel-001.yaml +21 -0
- package/university/content/paths/LP-atel-101.yaml +22 -0
- package/university/content/paths/LP-atel-201.yaml +23 -0
- package/university/content/paths/LP-atel-301.yaml +22 -0
- package/university/content/paths/LP-atel-401.yaml +22 -0
- package/university/content/paths/LP-atel-501.yaml +22 -0
- package/university/content/paths/LP-atel-601.yaml +22 -0
- package/university/content/paths/LP-atel-701.yaml +22 -0
- package/university/content/paths/LP-atel-801.yaml +22 -0
- package/university/content/quizzes/Q-atel-001-orientation.yaml +66 -0
- package/university/content/quizzes/Q-atel-101-document-model.yaml +66 -0
- package/university/content/quizzes/Q-atel-201-mcp-authoring.yaml +66 -0
- package/university/content/quizzes/Q-atel-301-visual-system.yaml +66 -0
- package/university/content/quizzes/Q-atel-401-state-machines.yaml +66 -0
- package/university/content/quizzes/Q-atel-501-video-pipeline.yaml +66 -0
- package/university/content/quizzes/Q-atel-601-recipes.yaml +66 -0
- package/university/content/quizzes/Q-atel-701-export.yaml +66 -0
- package/university/content/quizzes/Q-atel-801-studio-loop.yaml +66 -0
- package/university/index.yaml +720 -0
- package/university/pack.yaml +21 -0
- package/dist/chunk-5QQESXI6.js +0 -4432
- package/dist/chunk-5QQESXI6.js.map +0 -1
- package/dist/chunk-JPZ4F4PW.js.map +0 -1
- package/dist/cli.cjs +0 -6313
- package/dist/cli.cjs.map +0 -1
- package/dist/cli.d.cts +0 -1
- package/dist/cli.d.ts +0 -1
- package/dist/mcp.cjs +0 -5462
- package/dist/mcp.cjs.map +0 -1
- /package/dist/{dist-M67UZGFQ.js.map → dist-3YQK6PI6.js.map} +0 -0
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
id: Q-atel-701-export
|
|
2
|
+
title: 'ATEL-701: Export & Delivery'
|
|
3
|
+
description: Verify the export surface — single-frame raster (export-image / still), vector (export-svg / export-lottie), video (render via FFmpeg, studio via WebCodecs), the two canvas backends, and choosing a format by destination.
|
|
4
|
+
author: atelier
|
|
5
|
+
created: '2026-05-20'
|
|
6
|
+
updated: '2026-05-20'
|
|
7
|
+
tags:
|
|
8
|
+
- course
|
|
9
|
+
- atel-701
|
|
10
|
+
difficulty: intermediate
|
|
11
|
+
passThreshold: 0.7
|
|
12
|
+
questions:
|
|
13
|
+
- id: q1
|
|
14
|
+
question: 'You run `atelier export-image hero.atelier --out card.png --width 400` on a 1920×1080 document. What dimensions is `card.png`?'
|
|
15
|
+
choices:
|
|
16
|
+
A: '400×400 — the missing dimension defaults to match the width'
|
|
17
|
+
B: '400×225 — the height is derived to preserve the document''s aspect ratio'
|
|
18
|
+
C: '1920×1080 — --width is ignored without a matching --height'
|
|
19
|
+
D: '400×1080 — width is overridden, height stays at the document value'
|
|
20
|
+
correct: B
|
|
21
|
+
explanation: 'When only one of --width/--height is set, the other is derived to preserve the document aspect ratio. 1920×1080 is 16:9, so a width of 400 gives a height of 225. Override both and the renderer uses both verbatim (which can squash); override one and the aspect ratio carries the other.'
|
|
22
|
+
- id: q2
|
|
23
|
+
question: 'A teammate says "PNG export needs cairo, so I have to run brew install before I can export a thumbnail." Are they right?'
|
|
24
|
+
choices:
|
|
25
|
+
A: 'Yes — all Atelier rendering goes through node-canvas, which needs cairo/pango'
|
|
26
|
+
B: 'No — the single-frame raster path uses @napi-rs/canvas, which ships prebuilt binaries and works on a plain npm install'
|
|
27
|
+
C: 'Only on Linux; macOS bundles cairo with the OS'
|
|
28
|
+
D: 'Yes, but only the first time — the binary is cached afterward'
|
|
29
|
+
correct: B
|
|
30
|
+
explanation: 'The raster path (export-image, still --format png, carousel) uses @napi-rs/canvas — prebuilt platform binaries, no node-gyp, no system libraries. PNG export works the moment npm install finishes. The cairo/pango requirement belongs to the separate node-canvas package used by the video render path, not to single-frame raster.'
|
|
31
|
+
- id: q3
|
|
32
|
+
question: 'Why does `atelier export-lottie` have no `--frame` flag when `atelier export-svg` does?'
|
|
33
|
+
choices:
|
|
34
|
+
A: 'An oversight — both should accept --frame'
|
|
35
|
+
B: 'Lottie exports the whole animated document (the entire timeline as keyframes); SVG exports a single resolved frame'
|
|
36
|
+
C: 'Lottie always exports frame 0 and ignores everything else'
|
|
37
|
+
D: 'Lottie requires the document to have exactly one frame'
|
|
38
|
+
correct: B
|
|
39
|
+
explanation: 'Scope is the difference. export-svg serializes one resolved frame as an SVG snapshot, so it needs a frame. export-lottie walks the whole document''s deltas and writes them as Lottie keyframes — it is the animation, not a still — so a single frame would make no sense.'
|
|
40
|
+
- id: q4
|
|
41
|
+
question: 'You run `atelier render intro.atelier -f webm` to get a WebM file. What happens?'
|
|
42
|
+
choices:
|
|
43
|
+
A: 'It renders a WebM via FFmpeg'
|
|
44
|
+
B: 'The CLI render command only supports mp4 and gif; webm is rejected. WebM comes from the studio Export button (WebCodecs)'
|
|
45
|
+
C: 'It silently falls back to MP4'
|
|
46
|
+
D: 'It renders WebM but warns that quality may be reduced'
|
|
47
|
+
correct: B
|
|
48
|
+
explanation: 'The CLI render path supports mp4 and gif only — its format type is literally "mp4" | "gif". WebM is a studio-only output, produced in the browser via WebCodecs. The two video surfaces have different format reach: CLI via FFmpeg (mp4/gif), studio via WebCodecs (commonly mp4 and webm).'
|
|
49
|
+
- id: q5
|
|
50
|
+
question: 'A user can export a PNG from a fresh `npm install` but `atelier render clip.atelier` fails. Which two things does the video path need that the raster path does not?'
|
|
51
|
+
choices:
|
|
52
|
+
A: 'A GPU and a license key'
|
|
53
|
+
B: 'FFmpeg on $PATH and the node-canvas (`canvas`) package with its cairo/pango system libraries'
|
|
54
|
+
C: 'A newer Node version and more RAM'
|
|
55
|
+
D: 'An internet connection and a registered asset'
|
|
56
|
+
correct: B
|
|
57
|
+
explanation: 'Video from the CLI asks for two things stills never do: FFmpeg on $PATH (render shells out to ffmpeg -version first) and the optional native `canvas` package with cairo/pango/etc. The raster path uses prebuilt @napi-rs/canvas and no encoder. A clean PNG install does not imply a clean MP4 install.'
|
|
58
|
+
- id: q6
|
|
59
|
+
question: 'You are handing an animation to a front-end team to drop into a product screen, and they want a small, scalable file they can play in a runtime. Which export fits best?'
|
|
60
|
+
choices:
|
|
61
|
+
A: 'A folder of PNG frames'
|
|
62
|
+
B: 'Lottie JSON via `atelier export-lottie`'
|
|
63
|
+
C: 'An MP4 via `atelier render`'
|
|
64
|
+
D: 'An SVG via `atelier export-svg`'
|
|
65
|
+
correct: B
|
|
66
|
+
explanation: 'Lottie is the motion-design / runtime handoff format — vector-crisp, tiny, and playable in every major runtime with a few lines of code. SVG is a single still (no motion); MP4 is heavier and not vector; PNG frames are neither animation nor small. Watch export-lottie''s stderr warnings, though — an unsupported feature is reported there, not silently dropped.'
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
id: Q-atel-801-studio-loop
|
|
2
|
+
title: 'ATEL-801: Studio & the Live Agent Loop'
|
|
3
|
+
description: 'Verify the live agent loop — `atelier studio` as a local-first editor, the autosave save-race fix, image drop and the layer-type picker, the WebSocket bridge + MCP-over-WS transport, the source-tagged-mutation aspect, and the symbiotic human-agent editing pattern.'
|
|
4
|
+
author: atelier
|
|
5
|
+
created: '2026-05-20'
|
|
6
|
+
updated: '2026-05-20'
|
|
7
|
+
tags:
|
|
8
|
+
- course
|
|
9
|
+
- atel-801
|
|
10
|
+
difficulty: advanced
|
|
11
|
+
passThreshold: 0.7
|
|
12
|
+
questions:
|
|
13
|
+
- id: q1
|
|
14
|
+
question: 'When you switch files in the studio sidebar while an autosave is still pending in the 800ms debounce window, what stops the outgoing file''s bytes from being written to the newly-loaded file''s path?'
|
|
15
|
+
choices:
|
|
16
|
+
A: 'The save is dropped — switching files cancels the pending timer with no write'
|
|
17
|
+
B: 'The pending timer closure captures the target path AND serialized bytes, and `loadFile` flushes the pending save to its OWN path before switching'
|
|
18
|
+
C: 'The server rejects any write whose path differs from the currently-open file'
|
|
19
|
+
D: 'A CRDT merges the two files so neither is corrupted'
|
|
20
|
+
correct: B
|
|
21
|
+
explanation: 'This is the #cli-studio autosave-corruption bug. The original timer closed over the *doc* but read the GLOBAL current file at fire time — so editing A then opening B within 800ms wrote A''s bytes to B''s path. The fix is twofold: the timer captures both `pendingSavePath` and `pendingSaveContent` so a fired timer writes the bytes it was given to the file it was given; and `loadFile` calls `flushPendingSave()` at its very top to write any in-flight edit to its own path before switching. The extracted, testable version of this logic is the `SaveCoordinator` class; the inline browser app embeds the same manual debounce pattern.'
|
|
22
|
+
- id: q2
|
|
23
|
+
question: 'You drag two images from Finder onto the studio canvas of a freshly-scaffolded `welcome.atelier`. What happens to the welcome scaffold''s placeholder layer?'
|
|
24
|
+
choices:
|
|
25
|
+
A: 'Both images append on top of it; the placeholder stays visible underneath'
|
|
26
|
+
B: 'The FIRST dropped image replaces the layer whose id is `background` in-place; the second is unshifted onto the layers array (behind any overlays)'
|
|
27
|
+
C: 'Both images replace the placeholder, leaving only the second image'
|
|
28
|
+
D: 'The drop is rejected until you delete the placeholder manually'
|
|
29
|
+
correct: B
|
|
30
|
+
explanation: '`createImageLayerFromFile` is called with `replaceBackground: true` only for the FIRST image in a drop batch (`firstDrop` flips to false after the first). `buildImageLayer` swaps in-place only when `doc.layers[0]?.id === "background"` — a specific id contract, the welcome scaffold''s placeholder. Subsequent images are `unshift`-ed onto the layers array, which puts them at the bottom of the z-stack (the renderer paints index 0 first) so they sit behind any handle / page-number overlays.'
|
|
31
|
+
- id: q3
|
|
32
|
+
question: 'A property slider in the studio fires `onInput` continuously during a drag and `onChange` once on release. Why is the commit (undo snapshot) gated to `onChange` rather than `onInput`?'
|
|
33
|
+
choices:
|
|
34
|
+
A: '`onInput` is unreliable across browsers, so commits must wait for `onChange`'
|
|
35
|
+
B: 'So one slider drag produces exactly one undo entry — `onInput` does a cheap live-preview re-render with no snapshot, `onChange` commits and notifies the host'
|
|
36
|
+
C: 'Because `onInput` cannot read the slider''s value mid-drag'
|
|
37
|
+
D: 'To throttle autosave to once per second'
|
|
38
|
+
correct: B
|
|
39
|
+
explanation: 'The PropertyPanel splits the two events. `onPropertyPreview` (fired on `input`) does a cheap canvas re-render only — no undo snapshot, no host notification — so dragging gives live feedback. `onPropertyChange` (fired on `change`) snapshots undo history and notifies the host (which triggers autosave). The result: one drag = one undo, not one undo per pixel of slider travel. This was the slider-commit-flood bug, hidden while the client lived as an un-typechecked string.'
|
|
40
|
+
- id: q4
|
|
41
|
+
question: 'The studio binds the dev server to `127.0.0.1` and the WS upgrade handler re-runs an Origin check on `/bridge` and `/mcp`. Why does `/mcp` tolerate a MISSING Origin header while `/bridge` requires a strict same-origin match?'
|
|
42
|
+
choices:
|
|
43
|
+
A: '`/mcp` is unauthenticated by design and accepts any connection'
|
|
44
|
+
B: 'Non-browser MCP clients (e.g. Claude Desktop) send NO Origin header; rejecting them would make MCP-over-WS unreachable, so `/mcp` allows a missing Origin but still rejects a present-but-foreign one'
|
|
45
|
+
C: '`/bridge` carries secrets and `/mcp` does not'
|
|
46
|
+
D: 'The Origin check on `/mcp` is a bug that has not been fixed yet'
|
|
47
|
+
correct: B
|
|
48
|
+
explanation: 'WS upgrades bypass the connect middleware (Node fires `upgrade` before connect), so the bridge re-runs the Origin check itself via `isAllowedOrigin` / `isAllowedMcpOrigin`. `/bridge` is a real browser origin, so it demands strict same-origin. `/mcp` serves non-browser MCP clients that send no Origin — `isAllowedMcpOrigin` returns true for `undefined` but still rejects a present-but-foreign Origin (a tab on evil.com still cannot reach `/mcp`). The loopback bind to `127.0.0.1` remains the primary protection (^localhost-only).'
|
|
49
|
+
- id: q5
|
|
50
|
+
question: 'An MCP tool call mutates the shared `DocumentStore`, firing `onChange` with a source tag. Under the ~source-tagged-mutation aspect, which sources cause the bridge to broadcast an `llm:mutation` envelope to the browser?'
|
|
51
|
+
choices:
|
|
52
|
+
A: 'All three — human, llm, and system — so the browser always stays current'
|
|
53
|
+
B: 'Only `llm` — `human` (the browser is already current) and `system` (file-read hydration) stay silent to avoid echo loops and false attribution'
|
|
54
|
+
C: 'Only `human`, since human edits are the ones worth showing'
|
|
55
|
+
D: 'Only `system`, because that is the default tag'
|
|
56
|
+
correct: B
|
|
57
|
+
explanation: '`shouldBroadcastMutation(source)` returns true only for `source === "llm"`. Human edits arrive via `doc:patch` and are written with `source: "human"` so the filter skips them (otherwise the browser would echo its own edit back to itself). File-read hydration writes `source: "system"` — broadcasting it would fire a phantom "agent edited document" toast and a bogus undo entry on a plain file-open. Only genuine agent mutations broadcast, get persisted to disk, and surface a toast with a Cmd-Z undo affordance.'
|
|
58
|
+
- id: q6
|
|
59
|
+
question: 'In the symbiotic loop, an agent generates a batch of images by shelling out to an external generator (e.g. a Higgsfield CLI) and brings them into the open document. Which statement correctly describes Atelier''s role?'
|
|
60
|
+
choices:
|
|
61
|
+
A: 'Atelier runs the image generator in-process as one of its MCP tools'
|
|
62
|
+
B: 'Atelier owns no generation — the agent runs the external generator, then `atelier_import_images` ingests the results into the doc as ImageVisual layers + asset entries, which the human watches appear live and keeps or undoes'
|
|
63
|
+
C: 'The human must manually copy each generated file into the project before Atelier sees it'
|
|
64
|
+
D: 'Atelier regenerates the images itself to guarantee consistency'
|
|
65
|
+
correct: B
|
|
66
|
+
explanation: 'Atelier is an ingest-and-compose tool, not a generator. The agent runs the generation step in chat; `atelier_import_images` brings the results into the open document; the live bridge broadcasts the mutation so the human watches the layers appear and keeps or Cmd-Z-undoes each one; recipes and overlays compose the set; and `atelier carousel` exports it. Generation lives outside Atelier — the human and agent co-edit the same single-store document.'
|