@pinepaper.studio/mcp-server 1.6.15 → 1.6.16

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 (50) hide show
  1. package/README.de.md +1 -1
  2. package/README.es.md +1 -1
  3. package/README.fr.md +1 -1
  4. package/README.hi.md +1 -1
  5. package/README.ja.md +1 -1
  6. package/README.ko.md +1 -1
  7. package/README.md +64 -4
  8. package/README.pt-BR.md +1 -1
  9. package/README.zh-CN.md +1 -1
  10. package/dist/build-info.json +2 -2
  11. package/dist/ontology/upstream-vocabulary.d.ts +2 -2
  12. package/dist/ontology/upstream-vocabulary.js +2 -2
  13. package/dist/tools/definitions.d.ts.map +1 -1
  14. package/dist/tools/definitions.js +105 -8
  15. package/dist/tools/definitions.js.map +1 -1
  16. package/dist/tools/engine-surface.d.ts +1 -1
  17. package/dist/tools/engine-surface.d.ts.map +1 -1
  18. package/dist/tools/engine-surface.js +30 -9
  19. package/dist/tools/engine-surface.js.map +1 -1
  20. package/dist/tools/handlers/camera.d.ts.map +1 -1
  21. package/dist/tools/handlers/camera.js +11 -0
  22. package/dist/tools/handlers/camera.js.map +1 -1
  23. package/dist/tools/handlers/generate.d.ts +324 -0
  24. package/dist/tools/handlers/generate.d.ts.map +1 -0
  25. package/dist/tools/handlers/generate.js +264 -0
  26. package/dist/tools/handlers/generate.js.map +1 -0
  27. package/dist/tools/handlers.d.ts.map +1 -1
  28. package/dist/tools/handlers.js +39 -4
  29. package/dist/tools/handlers.js.map +1 -1
  30. package/dist/tools/minimal-descriptions.d.ts.map +1 -1
  31. package/dist/tools/minimal-descriptions.js +3 -0
  32. package/dist/tools/minimal-descriptions.js.map +1 -1
  33. package/dist/tools/shape-params.d.ts +2 -2
  34. package/dist/tools/shape-params.js +2 -2
  35. package/dist/tools/stick-vocabulary.d.ts +1 -1
  36. package/dist/tools/stick-vocabulary.js +1 -1
  37. package/dist/tools/toolkits.d.ts.map +1 -1
  38. package/dist/tools/toolkits.js +3 -0
  39. package/dist/tools/toolkits.js.map +1 -1
  40. package/dist/types/code-generator.d.ts +15 -0
  41. package/dist/types/code-generator.d.ts.map +1 -1
  42. package/dist/types/code-generator.js +279 -21
  43. package/dist/types/code-generator.js.map +1 -1
  44. package/dist/types/schemas.d.ts +527 -82
  45. package/dist/types/schemas.d.ts.map +1 -1
  46. package/dist/types/schemas.js +19 -7
  47. package/dist/types/schemas.js.map +1 -1
  48. package/dist/vendor/design/design-style.js +1 -1
  49. package/manifest.json +13 -1
  50. package/package.json +1 -1
package/README.de.md CHANGED
@@ -19,7 +19,7 @@
19
19
 
20
20
  Der PinePaper MCP-Server lässt KI-Assistenten über das Model Context Protocol Grafiken in [PinePaper Studio](https://pinepaper.studio) erstellen und animieren. Funktioniert mit jeder KI, die MCP-Tool-Aufrufe unterstützt (Claude, GPT, Gemini, lokale Modelle usw.).
21
21
 
22
- Der Server bietet **154 Tools**: Zeichnen, Animation, Diagramme, Karten, Typografie, Physik, Bildbearbeitung, Datenvisualisierung und Export:
22
+ Der Server bietet **157 Tools**: Zeichnen, Animation, Diagramme, Karten, Typografie, Physik, Bildbearbeitung, Datenvisualisierung und Export:
23
23
 
24
24
  - Text, Formen, Geometrie und komplexe Grafiken erstellen
25
25
  - Mit deklarativen **Relationen** animieren statt mit Keyframes
package/README.es.md CHANGED
@@ -19,7 +19,7 @@
19
19
 
20
20
  El servidor MCP de PinePaper permite a los asistentes de IA crear y animar gráficos en [PinePaper Studio](https://pinepaper.studio) a través del Model Context Protocol. Funciona con cualquier IA que soporte llamadas a herramientas MCP (Claude, GPT, Gemini, modelos locales, etc.).
21
21
 
22
- Expone **154 herramientas**: dibujo, animación, diagramas, mapas, tipografía, física, edición de imágenes, visualización de datos y exportación:
22
+ Expone **157 herramientas**: dibujo, animación, diagramas, mapas, tipografía, física, edición de imágenes, visualización de datos y exportación:
23
23
 
24
24
  - Crear texto, formas, geometría y gráficos complejos
25
25
  - Animar con **relaciones** declarativas en lugar de fotogramas clave
package/README.fr.md CHANGED
@@ -19,7 +19,7 @@
19
19
 
20
20
  Le serveur MCP PinePaper permet aux assistants IA de créer et d'animer des graphiques dans [PinePaper Studio](https://pinepaper.studio) via le Model Context Protocol. Compatible avec toute IA gérant les appels d'outils MCP (Claude, GPT, Gemini, modèles locaux, etc.).
21
21
 
22
- Il expose **154 outils** : dessin, animation, diagrammes, cartes, typographie, physique, retouche d'image, visualisation de données et export :
22
+ Il expose **157 outils** : dessin, animation, diagrammes, cartes, typographie, physique, retouche d'image, visualisation de données et export :
23
23
 
24
24
  - Créer du texte, des formes, de la géométrie et des graphiques complexes
25
25
  - Animer avec des **relations** déclaratives plutôt que des images clés
package/README.hi.md CHANGED
@@ -19,7 +19,7 @@
19
19
 
20
20
  PinePaper MCP सर्वर AI असिस्टेंट्स को Model Context Protocol के ज़रिए [PinePaper Studio](https://pinepaper.studio) में ग्राफ़िक्स बनाने और एनिमेट करने देता है। MCP टूल कॉलिंग वाले किसी भी AI (Claude, GPT, Gemini, लोकल मॉडल आदि) के साथ काम करता है।
21
21
 
22
- सर्वर **154 टूल** देता है — ड्रॉइंग, एनिमेशन, डायग्राम, नक्शे, टाइपोग्राफ़ी, फिज़िक्स, इमेज एडिटिंग, डेटा विज़ुअलाइज़ेशन और एक्सपोर्ट:
22
+ सर्वर **157 टूल** देता है — ड्रॉइंग, एनिमेशन, डायग्राम, नक्शे, टाइपोग्राफ़ी, फिज़िक्स, इमेज एडिटिंग, डेटा विज़ुअलाइज़ेशन और एक्सपोर्ट:
23
23
 
24
24
  - टेक्स्ट, आकृतियाँ, ज्यामिति और जटिल ग्राफ़िक्स बनाना
25
25
  - कीफ़्रेम की जगह व्यवहार बताने वाले **रिलेशन** से एनिमेशन
package/README.ja.md CHANGED
@@ -19,7 +19,7 @@
19
19
 
20
20
  PinePaper MCP サーバーは、MCP 経由で AI アシスタントが [PinePaper Studio](https://pinepaper.studio) 上にグラフィックを作成・アニメーションさせるためのサーバーです。MCP ツールコールに対応した AI(Claude、GPT、Gemini、ローカルモデルなど)で動作します。
21
21
 
22
- **154 個のツール**を提供 — 描画・アニメーション・図・地図・タイポグラフィ・物理・画像編集・データ可視化・エクスポート:
22
+ **157 個のツール**を提供 — 描画・アニメーション・図・地図・タイポグラフィ・物理・画像編集・データ可視化・エクスポート:
23
23
 
24
24
  - テキスト、図形、ジオメトリ、複雑なグラフィックの作成
25
25
  - キーフレームではなく、ふるまいを宣言する**リレーション**でアニメーション
package/README.ko.md CHANGED
@@ -19,7 +19,7 @@
19
19
 
20
20
  PinePaper MCP 서버는 AI 어시스턴트가 MCP를 통해 [PinePaper Studio](https://pinepaper.studio)에서 그래픽을 만들고 애니메이션하게 해줍니다. MCP 툴 콜을 지원하는 모든 AI(Claude, GPT, Gemini, 로컬 모델 등)와 호환됩니다.
21
21
 
22
- **154개의 툴** 제공 — 드로잉, 애니메이션, 다이어그램, 지도, 타이포그래피, 물리, 이미지 편집, 데이터 시각화, 내보내기:
22
+ **157개의 툴** 제공 — 드로잉, 애니메이션, 다이어그램, 지도, 타이포그래피, 물리, 이미지 편집, 데이터 시각화, 내보내기:
23
23
 
24
24
  - 텍스트·도형·기하·복잡한 그래픽 생성
25
25
  - 키프레임 대신 행동을 선언하는 **릴레이션**으로 애니메이션
package/README.md CHANGED
@@ -30,7 +30,7 @@
30
30
 
31
31
  PinePaper MCP Server enables AI assistants to create and animate graphics in [PinePaper Studio](https://pinepaper.studio) via the Model Context Protocol (MCP). Works with any AI that supports MCP tool calling (Claude, GPT, Gemini, local models, etc.).
32
32
 
33
- The server exposes **154 tools** across drawing, animation, diagrams, maps, typography, physics, image editing, data visualization, and export. Using natural language, you can:
33
+ The server exposes **157 tools** across drawing, animation, diagrams, maps, typography, physics, image editing, data visualization, and export. Using natural language, you can:
34
34
 
35
35
  - Create geometric shapes, text collages, diagrams, and data charts
36
36
  - Apply 37+ character-level text effects and 28+ vertex deformation presets
@@ -41,7 +41,7 @@ The server exposes **154 tools** across drawing, animation, diagrams, maps, typo
41
41
 
42
42
  ## Running it: local or hosted
43
43
 
44
- **Local is free and complete.** Every one of the 154 tools works when you run
44
+ **Local is free and complete.** Every one of the 157 tools works when you run
45
45
  this server yourself. There is no reduced tier and nothing held back.
46
46
 
47
47
  What it needs:
@@ -246,6 +246,61 @@ If you do not want an agent executing anything, `code` mode is a first-class pat
246
246
  - Puppeteer mode launches Chrome with `--no-sandbox` and `--disable-setuid-sandbox`. That is routine for headless automation and it does weaken Chrome's own process sandbox. If that matters where you are running it, use `code` mode or put the server in a container.
247
247
  - Puppeteer itself is an **optional** peer dependency, kept out of the default tree precisely because a headless browser plus an install script is what scanners flag hardest. Install it only if you want the executing mode.
248
248
 
249
+ ## What's new in 1.6.16
250
+
251
+ ### New: video editing on the timeline
252
+
253
+ `pinepaper_media` gains `split` (cut a clip in two at a time),
254
+ `add_transition` (a crossfade or a dip between two clips that meet), and
255
+ `set_clip` with `timeOffset` to move a clip, not only trim it. Uploads take
256
+ `atPlayhead: true` to start at the current playback time. A studio that cannot
257
+ do one of these says so rather than reporting success.
258
+
259
+ ### New: AI image generation (beta)
260
+
261
+ `pinepaper_generate` creates images with AI models in the PinePaper cloud and
262
+ can place the first one on the canvas; `pinepaper_generate_estimate` prices a
263
+ request and lists the models, free. It is charged per image, needs a service
264
+ account key (`PINEPAPER_API_KEY`), and is enabled per organisation during the
265
+ beta — without it the tools say so, and nothing is charged.
266
+
267
+ Words are never drawn by the model: pass them as `input.text` (headline,
268
+ subhead, caption, call to action, label) and they are added as real, editable
269
+ PinePaper text over the image, laid out inside the title-safe area and given a
270
+ dark backing only where the image behind them is too bright to read.
271
+
272
+ ### New: add to an animation instead of replacing it
273
+
274
+ `pinepaper_keyframe_animate` takes `append: true` to add keys to an item's
275
+ existing animation — a button press after an entrance. Without it, a second
276
+ call replaces the animation, and the result now says when that happened.
277
+
278
+ ### New: byte-identical exports
279
+
280
+ `pinepaper_agent_export` takes `deterministic: true` for MP4 and WebM: the same
281
+ scene gives the same file, so exports can be checksummed or cached by hash. If
282
+ a run could not be pinned, the result says not to rely on the hash.
283
+
284
+ ### Fixed
285
+
286
+ - `pinepaper_import_asset` with a `url` failed on every call after fetching the
287
+ file successfully.
288
+ - `pinepaper_sound` `render_soundtrack` timed out on longer soundtracks; it now
289
+ has the same time budget as other exports.
290
+ - `pinepaper_audio_beats` answered success with no result for larger audio, and
291
+ could not read a local file path. Both work now.
292
+ - `pinepaper_camera_animate` without keyframes failed with a raw JSON error; it
293
+ now says what `keyframes` needs.
294
+ - `pinepaper_precomp`: `create` returned an internal id that no tool accepted,
295
+ and `add` / `remove` could not work at all. All three now round-trip the
296
+ precomp's item id, and a failed `remove` is reported.
297
+ - `pinepaper_media` `set_time_remap`, `speed_ramp`, `match_cut` and the track
298
+ matte actions accept the media id that upload returns, as documented.
299
+ - `modify_item` `content` on text whose content is keyframed now warns that the
300
+ keyframes override it.
301
+ - Exporting a landscape canvas for a portrait platform (TikTok, Stories) — or
302
+ the reverse — is a fidelity warning with the fix, not only a note.
303
+
249
304
  ## What's new in 1.6.15
250
305
 
251
306
  ### New: the PinePaper mark
@@ -1171,7 +1226,7 @@ Fourteen new tools (121 → 135) and new actions across the surface — the rele
1171
1226
 
1172
1227
  ## Toolkits & Token Budget
1173
1228
 
1174
- 154 tools is a lot of context. The server ships a **toolkit** system that serves only the tools a given client needs, plus a **verbosity** system that controls how long each tool description is.
1229
+ 157 tools is a lot of context. The server ships a **toolkit** system that serves only the tools a given client needs, plus a **verbosity** system that controls how long each tool description is.
1175
1230
 
1176
1231
  **Toolkit profiles** (`PINEPAPER_TOOLKIT`):
1177
1232
 
@@ -1376,7 +1431,7 @@ Generate instruction/code pairs for LLM fine-tuning:
1376
1431
 
1377
1432
  ## Tools Reference
1378
1433
 
1379
- All 154 tools, grouped by the tag used for toolkit filtering.
1434
+ All 157 tools, grouped by the tag used for toolkit filtering.
1380
1435
 
1381
1436
  ### Canvas (`canvas`)
1382
1437
  | Tool | Description |
@@ -1477,6 +1532,9 @@ All 154 tools, grouped by the tag used for toolkit filtering.
1477
1532
  |------|-------------|
1478
1533
  | `pinepaper_execute_generator` | Run a background generator |
1479
1534
  | `pinepaper_list_generators` | List available generators |
1535
+ | `pinepaper_generate` | AI image generation in the PinePaper cloud (charged; beta, per organisation) |
1536
+ | `pinepaper_generate_estimate` | Free price check, and the model list |
1537
+ | `pinepaper_generate_status` | Collect a generation that outlived its timeout |
1480
1538
  | `pinepaper_apply_effect` | Apply sparkle, blast, and other effects |
1481
1539
  | `pinepaper_text_effect` | 37 character-level text animations; replaces the text with one keyframed item per character |
1482
1540
  | `pinepaper_add_filter` | Add an image filter |
@@ -1871,6 +1929,8 @@ See [CONTRIBUTING.md](CONTRIBUTING.md) for detailed guidelines.
1871
1929
  |----------|-------------|---------|
1872
1930
  | `PINEPAPER_STUDIO_URL` | PinePaper Studio URL to connect to (`/editor` is appended automatically) | `https://pinepaper.studio` |
1873
1931
  | `PINEPAPER_HEADLESS` | Run the browser headless (set `false` to watch it work) | `true` |
1932
+ | `PINEPAPER_API_KEY` | Service-account key (`pp_sa_…`) for the cloud-backed tools (`pinepaper_generate`) | — |
1933
+ | `PINEPAPER_CLOUD_URL` | The PinePaper cloud those tools call | `https://cloud.pinepaper.studio` |
1874
1934
  | `PINEPAPER_EXECUTION_MODE` | `puppeteer` (execute in a real browser) or `code` (return generated code only) | `puppeteer` |
1875
1935
  | `PINEPAPER_EXPORT_DIR` | Directory for exported files | `<tmpdir>/pinepaper-exports` |
1876
1936
  | `PINEPAPER_LOCALE` | Language locale code | `en` |
package/README.pt-BR.md CHANGED
@@ -19,7 +19,7 @@
19
19
 
20
20
  O servidor MCP do PinePaper permite que assistentes de IA criem e animem gráficos no [PinePaper Studio](https://pinepaper.studio) via Model Context Protocol. Funciona com qualquer IA que suporte chamadas de ferramenta MCP (Claude, GPT, Gemini, modelos locais etc.).
21
21
 
22
- São **154 ferramentas**: desenho, animação, diagramas, mapas, tipografia, física, edição de imagens, visualização de dados e exportação:
22
+ São **157 ferramentas**: desenho, animação, diagramas, mapas, tipografia, física, edição de imagens, visualização de dados e exportação:
23
23
 
24
24
  - Criar texto, formas, geometria e gráficos complexos
25
25
  - Animar com **relações** declarativas em vez de keyframes
package/README.zh-CN.md CHANGED
@@ -19,7 +19,7 @@
19
19
 
20
20
  PinePaper MCP 服务器让 AI 助手通过 MCP 协议在 [PinePaper Studio](https://pinepaper.studio) 中创建和驱动图形动画。兼容任何支持 MCP 工具调用的 AI(Claude、GPT、Gemini、本地模型等)。
21
21
 
22
- 服务器提供 **154 个工具**,覆盖绘图、动画、图表、地图、排版、物理、图像编辑、数据可视化与导出:
22
+ 服务器提供 **157 个工具**,覆盖绘图、动画、图表、地图、排版、物理、图像编辑、数据可视化与导出:
23
23
 
24
24
  - 创建文本、形状、几何图形与复杂图稿
25
25
  - 用行为驱动的**关系(relations)**做动画,而不是逐帧关键帧
@@ -1,5 +1,5 @@
1
1
  {
2
- "sha": "21f9ebb",
2
+ "sha": "d683e91",
3
3
  "dirty": false,
4
- "builtAt": "2026-09-25T20:36:58.520Z"
4
+ "builtAt": "2026-09-27T06:25:49.247Z"
5
5
  }
@@ -4,9 +4,9 @@
4
4
  * FxTool's ITEM_TYPE_MAP and type classes (anchor, description, parentType,
5
5
  * mcpTool, mcpAction), read from the loaded module.
6
6
  *
7
- * Source: FxTool origin/main 253a01a04c886713f610e619ac6205e59751dbb4
7
+ * Source: FxTool origin/main 9dd578afaa83c6286bfa2f554e8665407be400e1
8
8
  * js/ontology/Vocabulary.js
9
- * sha256: 8c39f8ad6d2da359
9
+ * sha256: 48fb80f82d3d3220
10
10
  *
11
11
  * vocabulary.ts merges these over its hand-written port: the engine's map
12
12
  * wins where the two disagree, and a class the port lacks is added.
@@ -4,9 +4,9 @@
4
4
  * FxTool's ITEM_TYPE_MAP and type classes (anchor, description, parentType,
5
5
  * mcpTool, mcpAction), read from the loaded module.
6
6
  *
7
- * Source: FxTool origin/main 253a01a04c886713f610e619ac6205e59751dbb4
7
+ * Source: FxTool origin/main 9dd578afaa83c6286bfa2f554e8665407be400e1
8
8
  * js/ontology/Vocabulary.js
9
- * sha256: 8c39f8ad6d2da359
9
+ * sha256: 48fb80f82d3d3220
10
10
  *
11
11
  * vocabulary.ts merges these over its hand-written port: the engine's map
12
12
  * wins where the two disagree, and a class the port lacks is added.
@@ -1 +1 @@
1
- {"version":3,"file":"definitions.d.ts","sourceRoot":"","sources":["../../src/tools/definitions.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,IAAI,EAAE,MAAM,oCAAoC,CAAC;AAC1D,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AA+B/C,eAAO,MAAM,cAAc,6kbAyK+G,CAAC;AAW3I,eAAO,MAAM,eAAe,EAAE,IAAI,EAukRjC,CAAC;AAEF;;GAEG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAE5D;AAED;;GAEG;AACH,wBAAgB,YAAY,IAAI,MAAM,EAAE,CAEvC;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,WAAW,GAAG,IAAI,EAAE,CAO3D;AAED;;;;;GAKG;AACH,MAAM,MAAM,aAAa,GAAG,SAAS,GAAG,SAAS,GAAG,SAAS,CAAC;AAE9D;;;;GAIG;AACH,wBAAgB,oBAAoB,CAAC,SAAS,EAAE,aAAa,GAAG,IAAI,EAAE,CAQrE"}
1
+ {"version":3,"file":"definitions.d.ts","sourceRoot":"","sources":["../../src/tools/definitions.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,IAAI,EAAE,MAAM,oCAAoC,CAAC;AAC1D,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AA+B/C,eAAO,MAAM,cAAc,6kbAyK+G,CAAC;AAW3I,eAAO,MAAM,eAAe,EAAE,IAAI,EA2qRjC,CAAC;AAEF;;GAEG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAE5D;AAED;;GAEG;AACH,wBAAgB,YAAY,IAAI,MAAM,EAAE,CAEvC;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,WAAW,GAAG,IAAI,EAAE,CAO3D;AAED;;;;;GAKG;AACH,MAAM,MAAM,aAAa,GAAG,SAAS,GAAG,SAAS,GAAG,SAAS,CAAC;AAE9D;;;;GAIG;AACH,wBAAgB,oBAAoB,CAAC,SAAS,EAAE,aAAa,GAAG,IAAI,EAAE,CAQrE"}
@@ -1755,6 +1755,91 @@ EXAMPLE: { checks: ["contrast", "flash"], duration: 6, fps: 20 }`,
1755
1755
  },
1756
1756
  },
1757
1757
  },
1758
+ {
1759
+ name: 'pinepaper_generate',
1760
+ annotations: { title: 'Generate Image (cloud)', readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: true },
1761
+ description: `Generate images with an AI model in the PinePaper cloud, and optionally place the first one on the canvas. CHARGED per output — price it first with pinepaper_generate_estimate (free).
1762
+
1763
+ Needs a service-account key in PINEPAPER_API_KEY (pp_sa_…, render:create scope). It is an internal beta enabled per organisation: without it the result says "not enabled for your organisation", and nothing is charged. Every refusal says whether anything was charged.
1764
+
1765
+ - model or useCase: a model id from pinepaper_generate_estimate {listModels: true}, or a use case and the cloud picks its default (hero stills, plates, text in the image, character-consistent edits).
1766
+ - input: { prompt, aspect ('16:9' | '9:16' | '1:1' | '4:5'), n (1-4), seed?, negativePrompt?, imageUrls? (https references for edit models) }.
1767
+ - brief / designRef: always passed on; the cloud records each generation against the design.
1768
+ - place: 'cover' (fill the canvas, centred; default when true) or 'contain' — places the first asset: an image as an image item, a video as a video layer (with its durationSeconds). The fit uses the asset's delivered size, not the requested aspect.
1769
+ - timeoutSec: how long to wait (default 180). A job that outlives it keeps running and is only charged if it delivers; collect it with pinepaper_generate_status.
1770
+
1771
+ WORDS ARE VECTOR: give words as input.text [{content, role?: headline|subhead|caption|cta|label, font?}]. The model makes a text-free plate; the words come back as textLayers (plus a hint), and with place they are added as real, editable text over it: headline top-left (Anton by default), subhead below, caption / cta bottom-left, label top-right, inside title-safe, each contrast-checked against the plate (a dark scrim is added only where it falls short of WCAG 4.5:1, or 3:1 for large text). Their item ids are in placement.text.
1772
+
1773
+ The result: assets [{assetId, ref, width, height}] — the sizes the files HAVE (a model may pick its own size for an aspect), chargedUsd, and any model notes (e.g. a SynthID watermark) to pass on.`,
1774
+ inputSchema: {
1775
+ type: 'object',
1776
+ properties: {
1777
+ model: { type: 'string' },
1778
+ useCase: { type: 'string' },
1779
+ input: {
1780
+ type: 'object',
1781
+ properties: {
1782
+ prompt: { type: 'string' },
1783
+ aspect: { type: 'string', enum: ['16:9', '9:16', '1:1', '4:5'] },
1784
+ n: { type: 'integer', minimum: 1, maximum: 4 },
1785
+ seed: { type: 'integer' },
1786
+ negativePrompt: { type: 'string' },
1787
+ imageUrls: { type: 'array', items: { type: 'string' }, maxItems: 14, description: 'Reference / start-frame images: https URLs, or your own generated images as their ref "/scene-assets/<id>" (chain a still into a video or a character edit).' },
1788
+ seconds: { type: 'number', exclusiveMinimum: 0, maximum: 60, description: 'Video models: clip length; each model allows its own lengths (listModels).' },
1789
+ text: { type: 'array', maxItems: 12, items: { type: 'object', properties: { content: { type: 'string' }, role: { type: 'string', enum: ['headline', 'subhead', 'caption', 'cta', 'label'] }, font: { type: 'string' } }, required: ['content'] }, description: 'Words for the design. The model never draws them: the plate comes back text-free and these return as textLayers — with place, laid out as real PinePaper text.' },
1790
+ allowText: { type: 'boolean', description: 'Let the MODEL draw text — eval-tier models only (e.g. ideogram-v3); refused (422) elsewhere. Prefer text.' },
1791
+ },
1792
+ required: ['prompt'],
1793
+ },
1794
+ brief: { type: 'string' },
1795
+ designRef: { type: 'object', properties: { kind: { type: 'string' }, id: { type: 'string' } }, required: ['kind', 'id'] },
1796
+ place: { anyOf: [{ type: 'boolean' }, { type: 'string', enum: ['cover', 'contain'] }] },
1797
+ timeoutSec: { type: 'integer', minimum: 10, maximum: 1800 },
1798
+ },
1799
+ required: ['input'],
1800
+ },
1801
+ },
1802
+ {
1803
+ name: 'pinepaper_generate_estimate',
1804
+ annotations: { title: 'Estimate Generation (free)', readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: true },
1805
+ description: `Free: price a pinepaper_generate call before making it, or list the models. { listModels: true } returns every model you may use with its price per output, use cases, licence notes and the defaults per use case; { model | useCase, input } returns the estimate for that request. Needs PINEPAPER_API_KEY, like pinepaper_generate.`,
1806
+ inputSchema: {
1807
+ type: 'object',
1808
+ properties: {
1809
+ model: { type: 'string' },
1810
+ useCase: { type: 'string' },
1811
+ input: {
1812
+ type: 'object',
1813
+ properties: {
1814
+ prompt: { type: 'string' },
1815
+ aspect: { type: 'string', enum: ['16:9', '9:16', '1:1', '4:5'] },
1816
+ n: { type: 'integer', minimum: 1, maximum: 4 },
1817
+ seed: { type: 'integer' },
1818
+ negativePrompt: { type: 'string' },
1819
+ imageUrls: { type: 'array', items: { type: 'string' }, maxItems: 14, description: 'Reference / start-frame images: https URLs, or your own generated images as their ref "/scene-assets/<id>" (chain a still into a video or a character edit).' },
1820
+ seconds: { type: 'number', exclusiveMinimum: 0, maximum: 60, description: 'Video models: clip length; each model allows its own lengths (listModels).' },
1821
+ text: { type: 'array', maxItems: 12, items: { type: 'object', properties: { content: { type: 'string' }, role: { type: 'string', enum: ['headline', 'subhead', 'caption', 'cta', 'label'] }, font: { type: 'string' } }, required: ['content'] }, description: 'Words for the design. The model never draws them: the plate comes back text-free and these return as textLayers — with place, laid out as real PinePaper text.' },
1822
+ allowText: { type: 'boolean', description: 'Let the MODEL draw text — eval-tier models only (e.g. ideogram-v3); refused (422) elsewhere. Prefer text.' },
1823
+ },
1824
+ required: ['prompt'],
1825
+ },
1826
+ listModels: { type: 'boolean' },
1827
+ },
1828
+ },
1829
+ },
1830
+ {
1831
+ name: 'pinepaper_generate_status',
1832
+ annotations: { title: 'Generation Status', readOnlyHint: false, destructiveHint: false, idempotentHint: true, openWorldHint: true },
1833
+ description: `Collect a pinepaper_generate job that outlived its timeoutSec: its status, and when done its assets and chargedUsd. place: 'cover' | 'contain' places the first image, as pinepaper_generate does.`,
1834
+ inputSchema: {
1835
+ type: 'object',
1836
+ properties: {
1837
+ jobId: { type: 'string' },
1838
+ place: { anyOf: [{ type: 'boolean' }, { type: 'string', enum: ['cover', 'contain'] }] },
1839
+ },
1840
+ required: ['jobId'],
1841
+ },
1842
+ },
1758
1843
  {
1759
1844
  name: 'pinepaper_render_batch',
1760
1845
  annotations: {
@@ -2043,15 +2128,18 @@ EXAMPLE: { times: [0, 0.5, 1, 1.5, 2], seed: 42 }`,
2043
2128
  description: `Bring VIDEO and AUDIO onto the canvas from a URL, and control playback. Uploaded video is a first-class canvas item (drag, scale, animate, export like any shape); audio rides the timeline.
2044
2129
 
2045
2130
  ACTIONS:
2046
- - upload_video: { url (required), position?, scale?, timeOffset? (timeline start, s), clipInPoint?, clipOutPoint? (trim, s) } → { id, duration, width, height, name }
2047
- - upload_audio: { url (required), volume? (0–1, default 1), loop?, muted?, timeOffset? } → { id, registryId, duration, name }. Pass loop EXPLICITLY — loop:true for a music bed, loop:false for a voice-over or sting; when omitted, the studio's own default applies and differs between builds.
2131
+ - upload_video: { url (required), position?, scale?, timeOffset? (timeline start, s) or atPlayhead?: true (start at the current playback time), clipInPoint?, clipOutPoint? (trim, s) } → { id, duration, width, height, name }
2132
+ - upload_audio: { url (required), volume? (0–1, default 1), loop?, muted?, timeOffset? or atPlayhead? } → { id, registryId, duration, name }. Pass loop EXPLICITLY — loop:true for a music bed, loop:false for a voice-over or sting; when omitted, the studio's own default applies and differs between builds.
2048
2133
  - list: → all media [{ id, kind, duration, … }]
2049
2134
  - remove: { id } → removed boolean
2050
2135
  - set_playback_rate: { id, rate (0.25–4) } → applies to video or audio
2051
- - set_clip: { id, inPoint, outPoint (media-time s, outPoint > inPoint) } → re-trim an ALREADY-uploaded clip (video or audio)
2136
+ - set_clip: { id, inPoint, outPoint (media-time s, outPoint > inPoint), timeOffset? (canvas s: also MOVE the clip to start there) } → re-trim an ALREADY-uploaded clip (video or audio). A studio that cannot move clips refuses timeOffset rather than ignoring it.
2137
+ - split: { id, at (canvas s) } → cut a clip in two: { leftId, rightId, leftMediaId, rightMediaId, at }. The first half keeps its id. Refused (not claimed) where the studio cannot split or the time is outside the clip.
2138
+ - add_transition: { fromItemId (ends at the cut), toItemId (starts at it), transition?: { type: 'crossfade'|'dip', seconds, color } } → the same in preview and export. Split a clip, then transition between its halves, or join two clips that meet.
2139
+ - For an IMAGE on the timeline, use pinepaper_import_image with bornAt / ttl (seconds on screen).
2052
2140
 
2053
2141
  NOTES:
2054
- - URL-based: the URL is fetched in the browser, so it must be reachable + CORS-permitted.
2142
+ - The server fetches the URL (or reads a local path / data: URL) and hands the page the bytes, so it does not need to be CORS-permitted.
2055
2143
  - Use the returned id with set_playback_rate / set_clip / remove, and (for video) modify/animate it like any item.
2056
2144
 
2057
2145
  VIDEO EDITING:
@@ -2065,14 +2153,16 @@ EXAMPLE: { action: 'upload_video', url: 'https://…/clip.mp4', scale: 0.5, time
2065
2153
  inputSchema: {
2066
2154
  type: 'object',
2067
2155
  properties: {
2068
- action: { type: 'string', enum: ['upload_video', 'upload_audio', 'list', 'remove', 'set_playback_rate', 'set_clip', 'set_time_remap', 'speed_ramp', 'match_cut', 'apply_track_matte', 'stop_live_matte'], description: "Media action" },
2156
+ action: { type: 'string', enum: ['upload_video', 'upload_audio', 'list', 'remove', 'set_playback_rate', 'set_clip', 'split', 'add_transition', 'set_time_remap', 'speed_ramp', 'match_cut', 'apply_track_matte', 'stop_live_matte'], description: "Media action" },
2157
+ transition: { type: 'object', properties: { type: { type: 'string', enum: ['crossfade', 'dip'] }, seconds: { type: 'number', exclusiveMinimum: 0, maximum: 10 }, color: { type: 'string' } }, description: "add_transition: { type ('crossfade' default | 'dip'), seconds, color (dip) }." },
2158
+ atPlayhead: { type: 'boolean', description: 'upload_video / upload_audio: start at the current playback time (instead of timeOffset).' },
2069
2159
  remapTrack: { type: 'array', items: { type: 'object', properties: { time: { type: 'number' }, value: { type: 'number' }, easing: { type: 'string' } }, required: ['time', 'value'] }, description: 'set_time_remap: canvas-seconds → source-seconds curve (≥2 points). null clears the remap.' },
2070
2160
  segments: { type: 'array', items: { type: 'object', properties: { duration: { type: 'number' }, speed: { type: 'number' } }, required: ['duration', 'speed'] }, description: 'speed_ramp: consecutive {duration, speed} segments. speed 0 = freeze frame, negative = reverse.' },
2071
2161
  fromItemId: { type: 'string', description: 'match_cut: outgoing shot item id.' },
2072
2162
  toItemId: { type: 'string', description: 'match_cut: incoming shot item id.' },
2073
2163
  subject: { type: 'string', enum: ['detect', 'bounds'], description: "match_cut: subject source — 'detect' (on-device DETR, needs consent on first use) or 'bounds'." },
2074
2164
  label: { type: 'string', description: 'match_cut: narrow detection to one class ("person") when the biggest object is not the subject.' },
2075
- at: { type: 'number', description: 'match_cut: cut time in seconds (default 0).' },
2165
+ at: { type: 'number', description: 'match_cut: cut time in seconds (default 0). split: the canvas time to cut at (required).' },
2076
2166
  settle: { type: 'number', description: 'match_cut: seconds to relax to natural framing (default 0.8).' },
2077
2167
  fade: { type: 'number', description: 'match_cut: crossfade seconds; 0 = hard cut (default 0.12).' },
2078
2168
  consent: { type: 'boolean', description: 'match_cut: allow the detection model download (a first run without it returns needsConsent instead of downloading silently).' },
@@ -2089,7 +2179,7 @@ EXAMPLE: { action: 'upload_video', url: 'https://…/clip.mp4', scale: 0.5, time
2089
2179
  outPoint: { type: 'number', description: 'Clip out-point (media-time s, > inPoint) — set_clip.' },
2090
2180
  position: { type: 'object', properties: { x: { type: 'number' }, y: { type: 'number' } }, description: 'Canvas position — upload_video.' },
2091
2181
  scale: { type: 'number', description: 'Scale factor — upload_video.' },
2092
- timeOffset: { type: 'number', description: 'Timeline start offset (s) — upload_video / upload_audio.' },
2182
+ timeOffset: { type: 'number', description: 'Timeline start offset (s) — upload_video / upload_audio; set_clip: move the clip to start here.' },
2093
2183
  clipInPoint: { type: 'number', description: 'Trim in-point (s) — upload_video.' },
2094
2184
  clipOutPoint: { type: 'number', description: 'Trim out-point (s) — upload_video.' },
2095
2185
  volume: { type: 'number', description: 'Volume 0–1 (default 1) — upload_audio.' },
@@ -3571,6 +3661,10 @@ EXAMPLE — Reveal at 2s, skip first second of keyframe data, end at 4s of keyfr
3571
3661
  type: 'number',
3572
3662
  description: 'Stop at N seconds into the keyframe data (tail trim). Default: lastKeyframeTime.',
3573
3663
  },
3664
+ append: {
3665
+ type: 'boolean',
3666
+ description: 'Add these keys to the item\'s existing track (same-time keys merge, new values win) instead of replacing it — e.g. a button press after an entrance. Without it, a second call replaces the track. result.track says whether the track was appended to or replaced; studios without merge replace, and say so.',
3667
+ },
3574
3668
  },
3575
3669
  required: ['itemId', 'keyframes'],
3576
3670
  },
@@ -4901,7 +4995,9 @@ ACTIONS:
4901
4995
  - update_from_instance: Promote an instance's edits back into the master. Params: instanceId
4902
4996
  - detach: Make an instance an ordinary independent item. Params: instanceId
4903
4997
 
4904
- Overrides are the point: an instance can differ from its master and still receive master updates.`,
4998
+ Overrides are the point: an instance can differ from its master and still receive master updates.
4999
+
5000
+ Instances carry the master's LOOK (geometry, style, text), not its animation: instantiate and sync copy what the master is, not its keyframes or animations. To animate instances, animate each one (keyframe_animate on its instanceId, or stagger across them).`,
4905
5001
  inputSchema: {
4906
5002
  type: 'object',
4907
5003
  properties: {
@@ -8050,6 +8146,7 @@ VERIFY MOTION BEFORE YOU RENDER. An export takes seconds to minutes and shows yo
8050
8146
  alphaQuantizer: { type: 'integer', minimum: 0, maximum: 63, description: 'webm with transparent: alpha-stream quality, 0 = lossless … 63.' },
8051
8147
  loop: { anyOf: [{ type: 'boolean' }, { type: 'integer', minimum: 0, maximum: 1000 }], description: 'gif / apng: true = loop forever, false / 0 / 1 = play once, n = play n times (email clients often want a few plays, not forever). Refused on video formats — see SEAMLESS LOOPS.' },
8052
8148
  broadcast: { type: 'boolean', description: 'mp4 only: broadcast-safe — BT.709, limited range (16-235), tagged bt709, constant bitrate with an 8 Mbps floor at 720p+ (4 below). result.video reports what the encoder did.' },
8149
+ deterministic: { type: 'boolean', description: 'mp4 / webm: byte-identical files for the same scene (pins the container timestamps), so exports can be checksummed or cached by hash.' },
8053
8150
  broadcastHeadroom: { type: 'integer', minimum: 0, maximum: 40, description: 'mp4 with broadcast only, default 12: luma codes kept clear at both ends, so encoder ringing stays legal (12 measured clean on hard edges; 4 = ~100x fewer out-of-range samples, 12 = ~1000x; never zero). Fidelity raises luma_out_of_range with the legaliser command when any remain.' },
8054
8151
  bitrate: { type: 'integer', minimum: 100000, maximum: 200000000, description: 'mp4 / webm: target bits/s, replacing the quality-derived one. The browser encoder treats it as a CEILING; result.video.achievedBitrate is what it produced.' },
8055
8152
  minBitrate: { type: 'integer', minimum: 100000, maximum: 200000000, description: 'mp4 / webm: a floor; a miss is a fidelity warning naming the re-encode a delivery spec needs.' },