@pinepaper.studio/mcp-server 1.6.16 → 1.6.17

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 (51) 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 +50 -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/tools/definitions.d.ts.map +1 -1
  12. package/dist/tools/definitions.js +60 -12
  13. package/dist/tools/definitions.js.map +1 -1
  14. package/dist/tools/engine-methods.d.ts.map +1 -1
  15. package/dist/tools/engine-methods.js +4 -0
  16. package/dist/tools/engine-methods.js.map +1 -1
  17. package/dist/tools/handlers/beats.d.ts +64 -0
  18. package/dist/tools/handlers/beats.d.ts.map +1 -0
  19. package/dist/tools/handlers/beats.js +83 -0
  20. package/dist/tools/handlers/beats.js.map +1 -0
  21. package/dist/tools/handlers.d.ts.map +1 -1
  22. package/dist/tools/handlers.js +40 -5
  23. package/dist/tools/handlers.js.map +1 -1
  24. package/dist/tools/minimal-descriptions.d.ts.map +1 -1
  25. package/dist/tools/minimal-descriptions.js +2 -0
  26. package/dist/tools/minimal-descriptions.js.map +1 -1
  27. package/dist/tools/toolkits.d.ts.map +1 -1
  28. package/dist/tools/toolkits.js +2 -0
  29. package/dist/tools/toolkits.js.map +1 -1
  30. package/dist/types/code-generator.d.ts +23 -0
  31. package/dist/types/code-generator.d.ts.map +1 -1
  32. package/dist/types/code-generator.js +274 -24
  33. package/dist/types/code-generator.js.map +1 -1
  34. package/dist/types/schemas.d.ts +87 -0
  35. package/dist/types/schemas.d.ts.map +1 -1
  36. package/dist/types/schemas.js +34 -14
  37. package/dist/types/schemas.js.map +1 -1
  38. package/dist/utils/a11y.d.ts +2 -0
  39. package/dist/utils/a11y.d.ts.map +1 -1
  40. package/dist/utils/a11y.js +1 -1
  41. package/dist/utils/a11y.js.map +1 -1
  42. package/dist/utils/beats.d.ts +58 -0
  43. package/dist/utils/beats.d.ts.map +1 -0
  44. package/dist/utils/beats.js +110 -0
  45. package/dist/utils/beats.js.map +1 -0
  46. package/dist/utils/svg-size.d.ts +22 -0
  47. package/dist/utils/svg-size.d.ts.map +1 -0
  48. package/dist/utils/svg-size.js +43 -0
  49. package/dist/utils/svg-size.js.map +1 -0
  50. package/manifest.json +9 -1
  51. 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 **157 Tools**: Zeichnen, Animation, Diagramme, Karten, Typografie, Physik, Bildbearbeitung, Datenvisualisierung und Export:
22
+ Der Server bietet **159 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 **157 herramientas**: dibujo, animación, diagramas, mapas, tipografía, física, edición de imágenes, visualización de datos y exportación:
22
+ Expone **159 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 **157 outils** : dessin, animation, diagrammes, cartes, typographie, physique, retouche d'image, visualisation de données et export :
22
+ Il expose **159 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
- सर्वर **157 टूल** देता है — ड्रॉइंग, एनिमेशन, डायग्राम, नक्शे, टाइपोग्राफ़ी, फिज़िक्स, इमेज एडिटिंग, डेटा विज़ुअलाइज़ेशन और एक्सपोर्ट:
22
+ सर्वर **159 टूल** देता है — ड्रॉइंग, एनिमेशन, डायग्राम, नक्शे, टाइपोग्राफ़ी, फिज़िक्स, इमेज एडिटिंग, डेटा विज़ुअलाइज़ेशन और एक्सपोर्ट:
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
- **157 個のツール**を提供 — 描画・アニメーション・図・地図・タイポグラフィ・物理・画像編集・データ可視化・エクスポート:
22
+ **159 個のツール**を提供 — 描画・アニメーション・図・地図・タイポグラフィ・物理・画像編集・データ可視化・エクスポート:
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
- **157개의 툴** 제공 — 드로잉, 애니메이션, 다이어그램, 지도, 타이포그래피, 물리, 이미지 편집, 데이터 시각화, 내보내기:
22
+ **159개의 툴** 제공 — 드로잉, 애니메이션, 다이어그램, 지도, 타이포그래피, 물리, 이미지 편집, 데이터 시각화, 내보내기:
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 **157 tools** across drawing, animation, diagrams, maps, typography, physics, image editing, data visualization, and export. Using natural language, you can:
33
+ The server exposes **159 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 **157 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 157 tools works when you run
44
+ **Local is free and complete.** Every one of the 159 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,50 @@ 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.17
250
+
251
+ ### New: tell an agent "at 4 s, make it orange"
252
+
253
+ `pinepaper_modify_item` takes `atTime`: the change is written as a keyframe at
254
+ that moment, the same as dragging with auto-key on, eased from the previous
255
+ value and without disturbing the rest of the animation.
256
+ `pinepaper_query_mutations` shows a property's values over time.
257
+
258
+ ### New: cuts on the beat
259
+
260
+ `pinepaper_beat_cuts` analyses a music track, fits a beat grid and returns cut
261
+ points on every beat, every bar or every N beats — and can split a clip at each.
262
+ When the tempo is uncertain it says so and lists the likely alternatives;
263
+ `bpm` or `bpmHint` settles it.
264
+
265
+ ### New: exact frame counts, and larger canvases
266
+
267
+ - `pinepaper_agent_export` takes `frames` for an exact frame count (a duration
268
+ rounds up), for segments that must line up.
269
+ - Canvases up to 16384 px per side, for digital out-of-home and projection;
270
+ above 8192 the result notes that Safari and iOS may not manage it.
271
+ - `pinepaper_import_image` takes `maxEdge` (or `'native'`) and `nativeSize`, and
272
+ says when the studio stored an image smaller than its source.
273
+ - `pinepaper_media` `upload_video` takes `fit` (`contain`, `cover`, `none`), and
274
+ `scale` is documented as relative to it.
275
+
276
+ ### Changed: exports say more about what they produced
277
+
278
+ - When an MP4 cannot be made at the requested size, the file is named by what it
279
+ is (WebM) and a warning says why.
280
+ - A video whose animation did not play, or whose encoder froze, is flagged.
281
+ - Asking for ProRes or HAP explains the route that works (a PNG sequence).
282
+ - Frame captures, region stills and flash checks wait for video on screen, and
283
+ report whether they could.
284
+ - The engine's structured warnings reach the caller whole.
285
+
286
+ ### Fixed
287
+
288
+ - `pinepaper_accessibility_check` judged text only at the current playhead, so
289
+ timed captions could pass unchecked; it now samples the timeline, and says
290
+ when no text was visible rather than passing.
291
+ - `pinepaper_agent_export` accepts `fps` and `scale` for APNG.
292
+
249
293
  ## What's new in 1.6.16
250
294
 
251
295
  ### New: video editing on the timeline
@@ -1226,7 +1270,7 @@ Fourteen new tools (121 → 135) and new actions across the surface — the rele
1226
1270
 
1227
1271
  ## Toolkits & Token Budget
1228
1272
 
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.
1273
+ 159 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.
1230
1274
 
1231
1275
  **Toolkit profiles** (`PINEPAPER_TOOLKIT`):
1232
1276
 
@@ -1431,7 +1475,7 @@ Generate instruction/code pairs for LLM fine-tuning:
1431
1475
 
1432
1476
  ## Tools Reference
1433
1477
 
1434
- All 157 tools, grouped by the tag used for toolkit filtering.
1478
+ All 159 tools, grouped by the tag used for toolkit filtering.
1435
1479
 
1436
1480
  ### Canvas (`canvas`)
1437
1481
  | Tool | Description |
@@ -1653,6 +1697,8 @@ All 157 tools, grouped by the tag used for toolkit filtering.
1653
1697
  | `pinepaper_analyze_design` | Analyze design quality |
1654
1698
  | `pinepaper_validate_design` | Validate against design rules |
1655
1699
  | `pinepaper_validate` | General validation |
1700
+ | `pinepaper_beat_cuts` | Cut points on the music's beats or bars; split a clip at each |
1701
+ | `pinepaper_query_mutations` | A property's keyframe series over time |
1656
1702
  | `pinepaper_accessibility_check` | Text contrast and flashing (WCAG), as a heuristic screen |
1657
1703
  | `pinepaper_validate_scene` | Validate scene integrity |
1658
1704
  | `pinepaper_instantiate_ontology` | Compile a pp: design graph into a scene |
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 **157 ferramentas**: desenho, animação, diagramas, mapas, tipografia, física, edição de imagens, visualização de dados e exportação:
22
+ São **159 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
- 服务器提供 **157 个工具**,覆盖绘图、动画、图表、地图、排版、物理、图像编辑、数据可视化与导出:
22
+ 服务器提供 **159 个工具**,覆盖绘图、动画、图表、地图、排版、物理、图像编辑、数据可视化与导出:
23
23
 
24
24
  - 创建文本、形状、几何图形与复杂图稿
25
25
  - 用行为驱动的**关系(relations)**做动画,而不是逐帧关键帧
@@ -1,5 +1,5 @@
1
1
  {
2
- "sha": "d683e91",
2
+ "sha": "b387e3e",
3
3
  "dirty": false,
4
- "builtAt": "2026-09-27T06:25:49.247Z"
4
+ "builtAt": "2026-09-27T07:36:09.211Z"
5
5
  }
@@ -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,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"}
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,EA6tRjC,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"}
@@ -261,12 +261,12 @@ COMMON PRESETS:
261
261
  - hd-landscape: 1920x1080
262
262
  - hd-portrait: 1080x1920
263
263
 
264
- Max canvas size: 8192x8192 (a 5400x1350 carousel panorama fits). For wedding invitations, event cards, or detailed designs, use at least 1080x1080 or larger.`,
264
+ Max canvas size: 16384 per side (a 12000 px DOOH or projection canvas fits); above 8192 Safari / iOS may not render it, Chrome and Firefox do. For wedding invitations, event cards, or detailed designs, use at least 1080x1080 or larger.`,
265
265
  inputSchema: {
266
266
  type: 'object',
267
267
  properties: {
268
- width: { type: 'number', description: 'Canvas width in pixels (100-8192)' },
269
- height: { type: 'number', description: 'Canvas height in pixels (100-8192)' },
268
+ width: { type: 'number', description: 'Canvas width in pixels (100-16384)' },
269
+ height: { type: 'number', description: 'Canvas height in pixels (100-16384)' },
270
270
  preset: {
271
271
  type: 'string',
272
272
  description: 'Optional preset name',
@@ -732,6 +732,8 @@ Use the collage group's id for palette/collageStyle; use a child letter's id for
732
732
  isDecorative: { type: 'boolean', description: 'Mark as decorative/non-interactive' },
733
733
  },
734
734
  },
735
+ atTime: { type: 'number', minimum: 0, description: 'AUTO-KEY: instead of a static edit, write these properties as keyframes at this time (seconds) — the same as a user dragging with auto-key on. Eased from the previous value; other keys and other properties\' curves are kept. "At 4 s make it orange" is { properties: { fillColor: "orange" }, atTime: 4 }.' },
736
+ easing: { type: 'string', description: 'atTime: easing of the segment arriving at the new key (default linear).' },
735
737
  },
736
738
  required: ['itemId', 'properties'],
737
739
  },
@@ -1152,6 +1154,8 @@ EXAMPLES:
1152
1154
  type: 'number',
1153
1155
  description: 'Maximum height constraint in pixels',
1154
1156
  },
1157
+ maxEdge: { anyOf: [{ type: 'integer', minimum: 1 }, { type: 'string', enum: ['native'] }], description: "The longest edge the studio STORES the image at (px); 'native' keeps every pixel. Default: the studio's cap, which follows the canvas on desktop. The result says when the image was stored smaller than its source." },
1158
+ nativeSize: { type: 'boolean', description: 'Place the image at its source footprint even if it was stored smaller.' },
1155
1159
  mask: {
1156
1160
  type: 'string',
1157
1161
  enum: ['circle', 'rounded', 'hexagon', 'star'],
@@ -1729,6 +1733,47 @@ EXAMPLES:
1729
1733
  required: ['action'],
1730
1734
  },
1731
1735
  },
1736
+ {
1737
+ name: 'pinepaper_beat_cuts',
1738
+ annotations: { title: 'Beat-Snapped Cuts', readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: false },
1739
+ description: `Cut on the music: analyse a track's beats (or take beat times you already have), fit a beat grid, and return cut points on every beat, every bar, or every N beats — optionally splitting a video or audio clip at each one.
1740
+
1741
+ - source: the music — an upload id, URL, data: URL or local file path. Or beats: [seconds] to skip the analysis.
1742
+ - every: 'beat' (default) | 'bar' | N beats. beatsPerBar (default 4). range: [from, to] seconds.
1743
+ - bpm: the tempo, if you know it (the grid's phase is still fitted to the music). Otherwise the studio's detection and its usual confusions (double, half, 3:4, 4:3 …) are scored against the music and the best is used; bpmHint: [min, max] keeps the choice in a range. The result lists the candidates, and says lowConfidence with a warning when the tempo is uncertain — pass bpm then.
1744
+ - clipId: split this clip at each cut, in order; cuts outside the clip are skipped and listed.
1745
+
1746
+ Returns cuts (seconds), the grid (bpm, phase, period, confidence) and, with clipId, the pieces' ids.`,
1747
+ inputSchema: {
1748
+ type: 'object',
1749
+ properties: {
1750
+ source: { type: 'string' },
1751
+ beats: { type: 'array', items: { type: 'number' } },
1752
+ bpm: { type: 'number' },
1753
+ bpmHint: { type: 'array', items: { type: 'number' }, minItems: 2, maxItems: 2, description: '[min, max] bpm to choose within.' },
1754
+ includeOnsets: { type: 'boolean', description: 'Also return the detected onsets (for diagnosing a tempo pick).' },
1755
+ every: { anyOf: [{ type: 'string', enum: ['beat', 'bar'] }, { type: 'integer', minimum: 1, maximum: 64 }] },
1756
+ beatsPerBar: { type: 'integer', minimum: 1, maximum: 16 },
1757
+ range: { type: 'array', items: { type: 'number' }, minItems: 2, maxItems: 2 },
1758
+ clipId: { type: 'string' },
1759
+ },
1760
+ },
1761
+ },
1762
+ {
1763
+ name: 'pinepaper_query_mutations',
1764
+ annotations: { title: 'Query Property Keyframes', readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false },
1765
+ description: `A property's values over time: the item's keyframe series ({t, frame, value, easing} per key), for one property or all, optionally within [from, to] seconds. The read side of modify_item { atTime } (auto-key): "what changed at 4 s?", "show the colour over time". It reads the item's keyframe track; it does not yet say WHO made each change or the value before it — that needs the studio's mutation log.`,
1766
+ inputSchema: {
1767
+ type: 'object',
1768
+ properties: {
1769
+ itemId: { type: 'string' },
1770
+ property: { type: 'string', description: 'One property; all animated properties when omitted.' },
1771
+ range: { type: 'array', items: { type: 'number' }, minItems: 2, maxItems: 2, description: '[from, to] seconds.' },
1772
+ fps: { type: 'number', description: 'For the frame numbers (default 30).' },
1773
+ },
1774
+ required: ['itemId'],
1775
+ },
1776
+ },
1732
1777
  {
1733
1778
  name: 'pinepaper_accessibility_check',
1734
1779
  annotations: {
@@ -1750,7 +1795,7 @@ EXAMPLE: { checks: ["contrast", "flash"], duration: 6, fps: 20 }`,
1750
1795
  type: 'object',
1751
1796
  properties: {
1752
1797
  checks: { type: 'array', items: { type: 'string', enum: ['contrast', 'flash'] }, description: 'Which checks (default both).' },
1753
- duration: { type: 'number', exclusiveMinimum: 0, maximum: 120, description: 'flash: seconds of the timeline to sample (default 5).' },
1798
+ duration: { type: 'number', exclusiveMinimum: 0, maximum: 120, description: 'Seconds of the timeline to sample (default 5): flash samples it at fps; contrast at 0 s, inside each text lifetime, at keyframe times and every second.' },
1754
1799
  fps: { type: 'integer', minimum: 10, maximum: 60, description: 'flash: samples per second (default 20).' },
1755
1800
  },
1756
1801
  },
@@ -2128,7 +2173,7 @@ EXAMPLE: { times: [0, 0.5, 1, 1.5, 2], seed: 42 }`,
2128
2173
  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.
2129
2174
 
2130
2175
  ACTIONS:
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 }
2176
+ - upload_video: { url (required), position?, fit? ('contain' default | 'cover' | 'none' = source pixels), scale? (a multiplier on that fit — with fit 'none', on the source pixels), timeOffset? (timeline start, s) or atPlayhead?: true (start at the current playback time), clipInPoint?, clipOutPoint? (trim, s) } → { id, duration, width, height, name }
2132
2177
  - 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.
2133
2178
  - list: → all media [{ id, kind, duration, … }]
2134
2179
  - remove: { id } → removed boolean
@@ -2178,7 +2223,8 @@ EXAMPLE: { action: 'upload_video', url: 'https://…/clip.mp4', scale: 0.5, time
2178
2223
  inPoint: { type: 'number', description: 'Clip in-point (media-time s) — set_clip.' },
2179
2224
  outPoint: { type: 'number', description: 'Clip out-point (media-time s, > inPoint) — set_clip.' },
2180
2225
  position: { type: 'object', properties: { x: { type: 'number' }, y: { type: 'number' } }, description: 'Canvas position — upload_video.' },
2181
- scale: { type: 'number', description: 'Scale factor — upload_video.' },
2226
+ scale: { type: 'number', description: "upload_video: a multiplier on the fit (contain by default), not on the source pixels; with fit: 'none', of the source pixels." },
2227
+ fit: { type: 'string', enum: ['contain', 'cover', 'none'], description: "upload_video: size before scale — 'contain' (default), 'cover', or 'none' (source pixels)." },
2182
2228
  timeOffset: { type: 'number', description: 'Timeline start offset (s) — upload_video / upload_audio; set_clip: move the clip to start here.' },
2183
2229
  clipInPoint: { type: 'number', description: 'Trim in-point (s) — upload_video.' },
2184
2230
  clipOutPoint: { type: 'number', description: 'Trim out-point (s) — upload_video.' },
@@ -2720,6 +2766,7 @@ render_soundtrack mixes every placed sound to a WAV and writes it to a file. It
2720
2766
  noiseFreq: { type: 'number', description: 'define_percussion / define_sfx: noise band centre in Hz.' },
2721
2767
  hz: { type: 'number', description: 'define_percussion / define_sfx: base frequency in Hz.' },
2722
2768
  pitch: { type: 'object', description: 'define_percussion / define_sfx: { from, tau } pitch glide. The glide IS the drum — omit it and a kick comes out a beep.' },
2769
+ duration: { type: 'number', description: 'render_soundtrack: seconds to render (options.duration also works; this wins if both are given). Without either, the studio uses the timeline length (3 s when there is none).' },
2723
2770
  sampleRate: { type: 'number', description: 'render_soundtrack: samples per second (default 48000).' },
2724
2771
  bitDepth: { type: 'number', enum: [16, 32], description: 'render_soundtrack: 16 (default) or 32-bit float.' },
2725
2772
  note: { type: 'string', description: "play_tone: scientific pitch, e.g. 'A4'." },
@@ -7835,7 +7882,7 @@ NOTE: For diagrams (flowcharts, UML), use pinepaper_create_diagram_shape + pinep
7835
7882
 
7836
7883
  ⚠️ EVERY operation executes LIVE on the canvas. Calling this twice DOUBLES all items. Call ONCE per pipeline.
7837
7884
 
7838
- ⚠️ SIZING: All positions/sizes MUST fit within the canvas. start_job returns canvasSize. Keep items within 5%-95% of canvas width/height. Max canvas: 8192x8192.
7885
+ ⚠️ SIZING: All positions/sizes MUST fit within the canvas. start_job returns canvasSize. Keep items within 5%-95% of canvas width/height. Max canvas: 16384 per side (above 8192, Safari / iOS may fail).
7839
7886
 
7840
7887
  ONTOLOGY PREFLIGHT: Before code generation, this tool validates itemType, relationType, effectType, and generatorName against the canonical PinePaper vocabulary. A typo (e.g. "circel") returns a structured VALIDATION_ERROR with the operation index, the offending field, the canonical valid list, and a suggested fix — fix and retry rather than guessing. Pass skipValidation: true to bypass when intentionally using experimental vocabulary.
7841
7888
 
@@ -7922,8 +7969,8 @@ EXAMPLE — Animated sky scene with timed reveals:
7922
7969
  description: 'Operation type',
7923
7970
  },
7924
7971
  // Canvas setup
7925
- width: { type: 'number', description: 'Canvas width for set_canvas_size (100-8192)' },
7926
- height: { type: 'number', description: 'Canvas height for set_canvas_size (100-8192)' },
7972
+ width: { type: 'number', description: 'Canvas width for set_canvas_size (100-16384)' },
7973
+ height: { type: 'number', description: 'Canvas height for set_canvas_size (100-16384)' },
7927
7974
  preset: { type: 'string', description: 'Canvas preset for set_canvas_size' },
7928
7975
  backgroundColor: { type: 'string', description: 'For set_background: hex color' },
7929
7976
  generatorName: {
@@ -8146,6 +8193,7 @@ VERIFY MOTION BEFORE YOU RENDER. An export takes seconds to minutes and shows yo
8146
8193
  alphaQuantizer: { type: 'integer', minimum: 0, maximum: 63, description: 'webm with transparent: alpha-stream quality, 0 = lossless … 63.' },
8147
8194
  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.' },
8148
8195
  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.' },
8196
+ frames: { type: 'integer', minimum: 1, maximum: 36000, description: 'Animated formats: exactly this many frames instead of duration. A duration makes ceil(duration x fps) frames (7.91667 s at 24 fps is 191, not 190), so use frames for frame-exact segments.' },
8149
8197
  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.' },
8150
8198
  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.' },
8151
8199
  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.' },
@@ -8172,7 +8220,7 @@ VERIFY MOTION BEFORE YOU RENDER. An export takes seconds to minutes and shows yo
8172
8220
  properties: {
8173
8221
  x: { type: 'number' }, y: { type: 'number' },
8174
8222
  width: { type: 'number', exclusiveMinimum: 0 }, height: { type: 'number', exclusiveMinimum: 0 },
8175
- outputWidth: { type: 'integer', minimum: 1, maximum: 8192 }, outputHeight: { type: 'integer', minimum: 1, maximum: 8192 },
8223
+ outputWidth: { type: 'integer', minimum: 1, maximum: 16384 }, outputHeight: { type: 'integer', minimum: 1, maximum: 16384 },
8176
8224
  excludeForeign: { type: 'boolean', description: 'Default true: an item reaching into the region but centred outside it (a neighbouring card overflow) is left out of this image; result.excludedItems names them. false renders everything that touches the region.' },
8177
8225
  },
8178
8226
  required: ['x', 'y', 'width', 'height'],
@@ -8204,8 +8252,8 @@ VERIFY MOTION BEFORE YOU RENDER. An export takes seconds to minutes and shows yo
8204
8252
  duration: {
8205
8253
  type: 'number',
8206
8254
  minimum: 0.5,
8207
- maximum: 60,
8208
- description: 'Video duration in seconds for mp4/webm/gif (default 5). Max 60 for mp4/webm; GIF is capped at 15 because it has no bitrate target, so size scales with frames × dimensions — use mp4/webm for longer clips. Static formats ignore this. If you set play_timeline to N seconds, pass the same N here.',
8255
+ maximum: 600,
8256
+ description: 'Video duration in seconds for mp4/webm/gif (default 5). Max 600 for mp4/webm (past about a minute the file is paged back from the studio\'s export store); GIF is capped at 15 because it has no bitrate target, so size scales with frames × dimensions — use mp4/webm for longer clips. The file has ceil(duration × fps) frames — for an exact count use frames instead. Static formats ignore this. If you set play_timeline to N seconds, pass the same N here.',
8209
8257
  },
8210
8258
  },
8211
8259
  // Nothing is required: platform defaults to 'auto', which is the canvas's