@pinepaper.studio/mcp-server 1.6.6 → 1.6.8

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 (178) hide show
  1. package/README.de.md +24 -1
  2. package/README.es.md +24 -1
  3. package/README.fr.md +24 -1
  4. package/README.hi.md +21 -1
  5. package/README.ja.md +22 -1
  6. package/README.ko.md +22 -1
  7. package/README.md +329 -14
  8. package/README.pt-BR.md +24 -1
  9. package/README.zh-CN.md +20 -1
  10. package/assets/edit-whenever.svg +75 -0
  11. package/dist/agent/export-manager.d.ts.map +1 -1
  12. package/dist/agent/export-manager.js +2 -2
  13. package/dist/agent/export-manager.js.map +1 -1
  14. package/dist/agent/session-manager.d.ts.map +1 -1
  15. package/dist/agent/session-manager.js.map +1 -1
  16. package/dist/assets/repositories/fontawesome.d.ts.map +1 -1
  17. package/dist/assets/repositories/fontawesome.js.map +1 -1
  18. package/dist/assets/repositories/openclipart.d.ts.map +1 -1
  19. package/dist/character/data/concepts.json +1 -0
  20. package/dist/character/data/depictions.json +1 -0
  21. package/dist/character/data/styles.json +1 -0
  22. package/dist/character/duration-scale.d.ts +13 -0
  23. package/dist/character/duration-scale.d.ts.map +1 -0
  24. package/dist/character/duration-scale.js +13 -0
  25. package/dist/character/duration-scale.js.map +1 -0
  26. package/dist/character/path-bbox.d.ts +82 -0
  27. package/dist/character/path-bbox.d.ts.map +1 -0
  28. package/dist/character/path-bbox.js +496 -0
  29. package/dist/character/path-bbox.js.map +1 -0
  30. package/dist/character/perform.d.ts +149 -0
  31. package/dist/character/perform.d.ts.map +1 -0
  32. package/dist/character/perform.js +626 -0
  33. package/dist/character/perform.js.map +1 -0
  34. package/dist/character/resolve.d.ts +51 -0
  35. package/dist/character/resolve.d.ts.map +1 -0
  36. package/dist/character/resolve.js +239 -0
  37. package/dist/character/resolve.js.map +1 -0
  38. package/dist/design/design-systems.d.ts +126 -0
  39. package/dist/design/design-systems.d.ts.map +1 -0
  40. package/dist/design/design-systems.js +240 -0
  41. package/dist/design/design-systems.js.map +1 -0
  42. package/dist/execution/canvas-state.d.ts +7 -0
  43. package/dist/execution/canvas-state.d.ts.map +1 -1
  44. package/dist/execution/canvas-state.js +20 -8
  45. package/dist/execution/canvas-state.js.map +1 -1
  46. package/dist/index.d.ts +20 -0
  47. package/dist/index.d.ts.map +1 -1
  48. package/dist/index.js +12 -5
  49. package/dist/index.js.map +1 -1
  50. package/dist/ontology/design-graph.d.ts +9 -0
  51. package/dist/ontology/design-graph.d.ts.map +1 -1
  52. package/dist/ontology/design-graph.js +98 -4
  53. package/dist/ontology/design-graph.js.map +1 -1
  54. package/dist/ontology/types.d.ts +42 -0
  55. package/dist/ontology/types.d.ts.map +1 -1
  56. package/dist/ontology/vocabulary.d.ts.map +1 -1
  57. package/dist/ontology/vocabulary.js +139 -0
  58. package/dist/ontology/vocabulary.js.map +1 -1
  59. package/dist/taxonomy/classifier.js +1 -1
  60. package/dist/taxonomy/classifier.js.map +1 -1
  61. package/dist/taxonomy/error-recovery.d.ts.map +1 -1
  62. package/dist/taxonomy/matcher.d.ts.map +1 -1
  63. package/dist/taxonomy/matcher.js.map +1 -1
  64. package/dist/tools/compact-descriptions.d.ts.map +1 -1
  65. package/dist/tools/compact-descriptions.js +25 -0
  66. package/dist/tools/compact-descriptions.js.map +1 -1
  67. package/dist/tools/definitions.d.ts +1 -1
  68. package/dist/tools/definitions.d.ts.map +1 -1
  69. package/dist/tools/definitions.js +1236 -45
  70. package/dist/tools/definitions.js.map +1 -1
  71. package/dist/tools/engine-methods.d.ts +18 -0
  72. package/dist/tools/engine-methods.d.ts.map +1 -0
  73. package/dist/tools/engine-methods.js +239 -0
  74. package/dist/tools/engine-methods.js.map +1 -0
  75. package/dist/tools/handlers/character.d.ts +121 -0
  76. package/dist/tools/handlers/character.d.ts.map +1 -0
  77. package/dist/tools/handlers/character.js +315 -0
  78. package/dist/tools/handlers/character.js.map +1 -0
  79. package/dist/tools/handlers.d.ts +2 -0
  80. package/dist/tools/handlers.d.ts.map +1 -1
  81. package/dist/tools/handlers.js +386 -22
  82. package/dist/tools/handlers.js.map +1 -1
  83. package/dist/tools/minimal-descriptions.d.ts.map +1 -1
  84. package/dist/tools/minimal-descriptions.js +24 -4
  85. package/dist/tools/minimal-descriptions.js.map +1 -1
  86. package/dist/tools/toolkits.d.ts.map +1 -1
  87. package/dist/tools/toolkits.js +21 -0
  88. package/dist/tools/toolkits.js.map +1 -1
  89. package/dist/types/code-generator.d.ts +141 -2
  90. package/dist/types/code-generator.d.ts.map +1 -1
  91. package/dist/types/code-generator.js +2246 -78
  92. package/dist/types/code-generator.js.map +1 -1
  93. package/dist/types/schemas.d.ts +9295 -603
  94. package/dist/types/schemas.d.ts.map +1 -1
  95. package/dist/types/schemas.js +1134 -61
  96. package/dist/types/schemas.js.map +1 -1
  97. package/dist/vendor/design/art-deco-generator.d.ts +52 -0
  98. package/dist/vendor/design/art-deco-generator.d.ts.map +1 -0
  99. package/dist/vendor/design/art-deco-generator.js +144 -0
  100. package/dist/vendor/design/art-deco-generator.js.map +1 -0
  101. package/dist/vendor/design/art-nouveau-generator.d.ts +46 -0
  102. package/dist/vendor/design/art-nouveau-generator.d.ts.map +1 -0
  103. package/dist/vendor/design/art-nouveau-generator.js +134 -0
  104. package/dist/vendor/design/art-nouveau-generator.js.map +1 -0
  105. package/dist/vendor/design/bauhaus-generator.d.ts +53 -0
  106. package/dist/vendor/design/bauhaus-generator.d.ts.map +1 -0
  107. package/dist/vendor/design/bauhaus-generator.js +126 -0
  108. package/dist/vendor/design/bauhaus-generator.js.map +1 -0
  109. package/dist/vendor/design/brutalist-generator.d.ts +53 -0
  110. package/dist/vendor/design/brutalist-generator.d.ts.map +1 -0
  111. package/dist/vendor/design/brutalist-generator.js +148 -0
  112. package/dist/vendor/design/brutalist-generator.js.map +1 -0
  113. package/dist/vendor/design/claymorphism-generator.d.ts +46 -0
  114. package/dist/vendor/design/claymorphism-generator.d.ts.map +1 -0
  115. package/dist/vendor/design/claymorphism-generator.js +135 -0
  116. package/dist/vendor/design/claymorphism-generator.js.map +1 -0
  117. package/dist/vendor/design/corporate-memphis-generator.d.ts +47 -0
  118. package/dist/vendor/design/corporate-memphis-generator.d.ts.map +1 -0
  119. package/dist/vendor/design/corporate-memphis-generator.js +144 -0
  120. package/dist/vendor/design/corporate-memphis-generator.js.map +1 -0
  121. package/dist/vendor/design/cyberpunk-generator.d.ts +52 -0
  122. package/dist/vendor/design/cyberpunk-generator.d.ts.map +1 -0
  123. package/dist/vendor/design/cyberpunk-generator.js +162 -0
  124. package/dist/vendor/design/cyberpunk-generator.js.map +1 -0
  125. package/dist/vendor/design/de-stijl-generator.d.ts +50 -0
  126. package/dist/vendor/design/de-stijl-generator.d.ts.map +1 -0
  127. package/dist/vendor/design/de-stijl-generator.js +154 -0
  128. package/dist/vendor/design/de-stijl-generator.js.map +1 -0
  129. package/dist/vendor/design/design-style.d.ts +3 -0
  130. package/dist/vendor/design/design-style.d.ts.map +1 -0
  131. package/dist/vendor/design/design-style.js +12 -0
  132. package/dist/vendor/design/design-style.js.map +1 -0
  133. package/dist/vendor/design/design-systems-dtcg.d.ts +59 -0
  134. package/dist/vendor/design/design-systems-dtcg.d.ts.map +1 -0
  135. package/dist/vendor/design/design-systems-dtcg.js +571 -0
  136. package/dist/vendor/design/design-systems-dtcg.js.map +1 -0
  137. package/dist/vendor/design/frutiger-aero-generator.d.ts +46 -0
  138. package/dist/vendor/design/frutiger-aero-generator.d.ts.map +1 -0
  139. package/dist/vendor/design/frutiger-aero-generator.js +133 -0
  140. package/dist/vendor/design/frutiger-aero-generator.js.map +1 -0
  141. package/dist/vendor/design/memphis-generator.d.ts +56 -0
  142. package/dist/vendor/design/memphis-generator.d.ts.map +1 -0
  143. package/dist/vendor/design/memphis-generator.js +158 -0
  144. package/dist/vendor/design/memphis-generator.js.map +1 -0
  145. package/dist/vendor/design/mid-century-upa-generator.d.ts +46 -0
  146. package/dist/vendor/design/mid-century-upa-generator.d.ts.map +1 -0
  147. package/dist/vendor/design/mid-century-upa-generator.js +137 -0
  148. package/dist/vendor/design/mid-century-upa-generator.js.map +1 -0
  149. package/dist/vendor/design/neumorphic-generator.d.ts +53 -0
  150. package/dist/vendor/design/neumorphic-generator.d.ts.map +1 -0
  151. package/dist/vendor/design/neumorphic-generator.js +182 -0
  152. package/dist/vendor/design/neumorphic-generator.js.map +1 -0
  153. package/dist/vendor/design/op-art-generator.d.ts +45 -0
  154. package/dist/vendor/design/op-art-generator.d.ts.map +1 -0
  155. package/dist/vendor/design/op-art-generator.js +116 -0
  156. package/dist/vendor/design/op-art-generator.js.map +1 -0
  157. package/dist/vendor/design/pixel-art-generator.d.ts +45 -0
  158. package/dist/vendor/design/pixel-art-generator.d.ts.map +1 -0
  159. package/dist/vendor/design/pixel-art-generator.js +143 -0
  160. package/dist/vendor/design/pixel-art-generator.js.map +1 -0
  161. package/dist/vendor/design/pop-art-generator.d.ts +53 -0
  162. package/dist/vendor/design/pop-art-generator.d.ts.map +1 -0
  163. package/dist/vendor/design/pop-art-generator.js +164 -0
  164. package/dist/vendor/design/pop-art-generator.js.map +1 -0
  165. package/dist/vendor/design/risograph-generator.d.ts +53 -0
  166. package/dist/vendor/design/risograph-generator.d.ts.map +1 -0
  167. package/dist/vendor/design/risograph-generator.js +170 -0
  168. package/dist/vendor/design/risograph-generator.js.map +1 -0
  169. package/dist/vendor/design/swiss-style-generator.d.ts +55 -0
  170. package/dist/vendor/design/swiss-style-generator.d.ts.map +1 -0
  171. package/dist/vendor/design/swiss-style-generator.js +147 -0
  172. package/dist/vendor/design/swiss-style-generator.js.map +1 -0
  173. package/dist/vendor/design/vaporwave-generator.d.ts +51 -0
  174. package/dist/vendor/design/vaporwave-generator.d.ts.map +1 -0
  175. package/dist/vendor/design/vaporwave-generator.js +139 -0
  176. package/dist/vendor/design/vaporwave-generator.js.map +1 -0
  177. package/manifest.json +65 -1
  178. package/package.json +18 -9
package/README.md CHANGED
@@ -8,7 +8,15 @@
8
8
  **English** · [简体中文](README.zh-CN.md) · [日本語](README.ja.md) · [한국어](README.ko.md) · [Español](README.es.md) · [Português (BR)](README.pt-BR.md) · [Français](README.fr.md) · [Deutsch](README.de.md) · [हिन्दी](README.hi.md)
9
9
 
10
10
  <p align="center">
11
- <img src="assets/hero.svg" alt="PinePaper MCP — a tool call on the left becomes motion on the canvas at the right" width="840">
11
+ <img src="assets/edit-whenever.svg" alt="Generate once. Edit whenever. — animated PinePaper poster: the headline assembles from scatter, a color wave runs through every letter, and 'generate twice / thrice' get struck out before 'once' is highlighted" width="720">
12
+ </p>
13
+
14
+ <p align="center">
15
+ <b>The animation engine agents can drive.</b><br>
16
+ This poster is one 16&nbsp;KB SVG — 100+ animations, no scripts. View source on it.<br><br>
17
+ <a href="https://pinepaper.studio/?utm_source=github&utm_medium=readme&utm_campaign=launch_pinned&utm_content=hero">Try PinePaper Studio</a> ·
18
+ <a href="https://pinepaper.studio/docs?utm_source=github&utm_medium=readme&utm_campaign=launch_pinned&utm_content=docs">Docs</a> ·
19
+ <a href="https://www.npmjs.com/package/@pinepaper.studio/mcp-server">npm</a>
12
20
  </p>
13
21
 
14
22
  *Everything above and below moves — these are animated SVGs exported straight from PinePaper tool calls, no video files, no GIFs. Open this README on GitHub and watch.*
@@ -17,18 +25,49 @@
17
25
 
18
26
  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.).
19
27
 
20
- The server exposes **135 tools** across drawing, animation, diagrams, maps, typography, physics, image editing, data visualization, and export. Using natural language, you can:
28
+ The server exposes **151 tools** across drawing, animation, diagrams, maps, typography, physics, image editing, data visualization, and export. Using natural language, you can:
29
+
30
+ - Create geometric shapes, text collages, diagrams, and data charts
31
+ - Apply 37+ character-level text effects and 28+ vertex deformation presets
32
+ - Wire behavioral relationships between objects (orbit, follow, point-at, mirror, parallax, morph)
33
+ - Animate with keyframes, timeline sequencing, and physics simulations
34
+ - Build interactive widgets with click/hover/drag event bindings
35
+ - Export to SVG, self-contained interactive HTML, MP4, and animated formats
36
+
37
+ ## Running it: local or hosted
38
+
39
+ **Local is free and complete.** Every one of the 151 tools works when you run
40
+ this server yourself. There is no reduced tier and nothing held back.
41
+
42
+ What it needs:
43
+
44
+ | | |
45
+ |---|---|
46
+ | Node | 18 or newer |
47
+ | Disk | Puppeteer downloads Chrome on install — roughly **320 MB** per version |
48
+ | Memory | a Chrome process plus the Studio canvas, so budget ~1 GB while a job runs |
21
49
 
22
- - Create text, shapes, geometry, and complex graphics
23
- - Animate items with behavior-driven **relations** rather than keyframes
24
- - Build long scenes as **event-driven chains** that stay scrub- and replay-stable
25
- - Generate procedural backgrounds and parametric/equation-driven paths
26
- - Author diagrams, maps, charts, and letter collages
27
- - Edit images: crop, chroma-key background removal, GPU filters, lasso cutouts, object detection
28
- - Export animated SVG, video frames, embeddable widgets, and LLM training data
50
+ That is fine on a laptop and awkward on a small VPS, a locked-down work machine,
51
+ or a container you would rather keep thin.
52
+
53
+ **[cloud.pinepaper.studio](https://cloud.pinepaper.studio) runs the same server
54
+ for you** — same tools, same version, over HTTP with no install and no browser
55
+ on your machine. It exists for three cases: you have no MCP client, you cannot
56
+ install one, or your machine cannot spare the browser.
57
+
58
+ Hosting costs money, so the hosted option is paid — it runs on credits. See
59
+ [cloud.pinepaper.studio](https://cloud.pinepaper.studio) for current pricing. Run it
60
+ locally if you can, but it is not identical: the hosted service runs a tested
61
+ set of LLMs and repairs generated code before it reaches the canvas, which a
62
+ local server structurally cannot do for itself. Which model to trust is a
63
+ question you can answer yourself rather than take on trust: a benchmark runs one
64
+ prompt across several models and puts the results side by side, any run
65
+ shareable. It is in invite-only beta.
29
66
 
30
67
  ## Made with tool calls
31
68
 
69
+ <p align="center"><img src="assets/hero.svg" width="720" alt="Animated vector graphics, made by tool calls — a tool call on the left runs and becomes a curve drawing itself on the right, composed with PinePaper Studio"></p>
70
+
32
71
  Every graphic below is an animated SVG produced through this server's tool surface — the arguments shown with each result are what an AI agent passes to the named tool. They aren't shell commands; **[Run these yourself](#run-these-yourself)** below shows the three ways to execute them.
33
72
 
34
73
  <!-- Stacked (image then code) rather than a two-column table so the SVGs render on
@@ -144,6 +183,261 @@ app.animate(sq, { animationType: 'rotate' });
144
183
 
145
184
  The same code an agent generates is the code you can paste — the canvas is yours either way, undo included.
146
185
 
186
+ ## Security: yes, it executes code
187
+
188
+ **Supply-chain scanners flag this package, and they are not wrong about the mechanism.** Socket and tools like it mark it as malware-adjacent because it evaluates JavaScript at runtime. The detection is correct about the capability and wrong about the intent, so here is exactly what happens.
189
+
190
+ **Every tool emits JavaScript — that is the architecture, not an exception.** A tool call is compiled into a snippet written against the PinePaper and Paper.js APIs; the snippet is the product. `pinepaper_execute_custom_code` is simply the case where the *agent* writes the snippet instead of the server generating it, which is what lets a model draw something no other tool has a name for. Removing execution would not harden this package, it would delete it.
191
+
192
+ **Where the code runs.** In a browser page on your own machine, against your own canvas. It does not run in the server process, and nothing is sent anywhere else to be executed.
193
+
194
+ **Two modes, and one of them never executes anything:**
195
+
196
+ | Mode | What happens |
197
+ |---|---|
198
+ | `code` (`PINEPAPER_EXECUTION_MODE=code`) | The tool returns the JavaScript and stops. Nothing runs. You read it and paste it if you want it. |
199
+ | `puppeteer` (default) | The server launches Chrome and runs the snippet in the page via `page.evaluate()`. |
200
+
201
+ If you do not want an agent executing anything, `code` mode is a first-class path, not a degraded one — the same snippet, handed to you instead of run.
202
+
203
+ **What guards execution.** On current engine builds the snippet goes through `app.runGenerated(code, { source: 'agent' })` — a governor with seeded determinism, loop and item budgets, and a machine-readable report — rather than a bare `eval`. Older engine builds fall back to `eval`.
204
+
205
+ **What to weigh before running it.**
206
+
207
+ - Code an agent writes runs with whatever that browser page has. Give this server the same trust you would give anything else you let write and run code on your machine — which is the trust you already extend to an MCP client with tool access.
208
+ - 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.
209
+ - 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.
210
+
211
+ ## What's new in 1.6.8
212
+
213
+ **Long-form export stops crossing the bridge as one string.** `pinepaper_agent_export` handed the bytes back as a base64 data URL. Two things were wrong with that and only one of them was a bug.
214
+
215
+ - The bug: a **streamed** export returns a `{streamed:true}` marker rather than a Blob, and `FileReader.readAsDataURL` throws on it — so any export that streamed *broke* this path instead of extending it.
216
+ - The ceiling: base64 of a ten-minute 1080p video is a ~1.6 GB string before JSON transport. No memory fix reaches that.
217
+ - But the ceiling was never the MCP response. This server already wrote video and PDF to a file above 500 KB and handed back a `filePath` — the only real limit was the single `page.evaluate` return value. So the paging belongs *inside* the tool: the studio holds the encoded file in its export store and returns an id, and the server pages it into the file it was going to write anyway. One tool call, one `filePath`, at any size, with at most one 4 MB chunk in memory on either side. An agent-facing pager would only have exposed a transport limit the agent cannot act on.
218
+ - `duration` goes from a 60-second cap to **600**. Ten minutes was unreachable regardless of how the bytes came back, so the cap was the other half of the ceiling. GIF keeps its own 15-second cap: it has a different encoder and does not stream.
219
+ - Failure leaves the export **held**. The store is the only copy, so the error names the id and the bytes reached, deletes the partial file, and does not release. An eviction mid-read is reported as an eviction, never as a missing file, and re-exporting stays the caller's decision.
220
+ - **This needs a studio with the export store** — `exportToStore` / `readExport` / `releaseExport`, which are live in the engine. An older studio takes the buffered path exactly as before, and both of its failures are now *named* instead of fatal: the marker says it streamed and there is nothing to page it from, and an export past a 96 MB inline ceiling gives its size, the ceiling and what to do. That ceiling sits above what the buffered path could already deliver, so nothing that worked before starts refusing.
221
+
222
+ **`pinepaper_instantiate_ontology` builds through the studio's own compiler.** The server-side port placed items as boxes — no paint, no text, no keyframes, no masks. The engine's compiler reads every node facet and builds through the template loader's own paths, which is the round trip the studio's pixel tests verify. The box loop survives only as the fallback for studios that predate the facade, and says what it lost.
223
+
224
+ - **A failed image reported success.** The door returned three of the counts the compiler gives it and dropped nine, `imagesFailed` among them — so a raster that never decoded read back as `success: true` with a full `itemIds` array. All the counts are surfaced now, and `imagesFailed` alone is enough to make the call unsuccessful, whether or not the compiler also logged an error diagnostic.
225
+
226
+ **The design graph keeps the recipes for everything code drew.** Three kinds of node have no geometry to round-trip, because code drew them and the code's inputs *are* their geometry. The graph kept a generator's name and not its parameters — enough to name a generator, not enough to re-run one.
227
+
228
+ - Nodes now carry `generator`, `generatorParams` and `generatorRole`; a mesh carries `meshProvenance` (`op`, the node it was derived from, and the options); the 3D stage rides at document level as `world`. All of it reaches the JSON-LD.
229
+ - The parameters have to be the **merged** set. What a generator hands its registry is empty, or two keys of thirty for the GPU generators, and a recipe built from that names a generator it cannot reproduce — which is indistinguishable from a working one until someone re-runs it.
230
+ - `pp:world` is a **sibling** of `pp:generator`, never nested inside it. A World3D scene has no generator, so a stage read inside `if (generator)` is dropped from exactly the scenes that cannot rebuild without it.
231
+
232
+ **Relation presets are adoptable.** `pinepaper_add_relation` takes a `presetId` — a community motion someone already tuned, with its symbols exposed as knobs — instead of making a caller name a type and guess at params. The preset decides the relation type, and any symbol you omit takes the midpoint of its declared range, so a preset applies sensibly with no values at all. List them through the new `catalogue`, which also returns what this build **rejected**: a preset for a relation type this engine does not have is a named absence, where dropping it silently would read as the catalogue simply being smaller.
233
+
234
+ **`pinepaper_query_capabilities` gains `catalogue`** — the eight registries the engine's own aggregate does not gather: rig presets, shader effects, stroke decorations, the precomp list, the image library, segment-edit kinds, shatter orders and world meshes. Each was a capability an agent had to guess at, which by this project's rule is the same as its not existing. A missing facade is named rather than answered with an empty list, because an empty list reads as "none exist" and that is a different, worse answer.
235
+
236
+ **Four more reachable things, and a note on the ones that turned out not to be gaps.** `pinepaper_text_style` gains `cursive` (text written as a **stroked path** rather than set in a glyph, so draw-on animation and `outline_stroke` both apply to it), `wrap`/`unwrap` (break a text item to a width, reversibly), and `to_collage` (convert an *existing* text item in place). `pinepaper_equation_path` gains `solveOde` — integrate an ODE and get the **trajectory back as data** rather than a drawn path, to inspect, feed to a path, or drive keyframes with.
237
+
238
+ What was *not* a gap is worth saying too, because it was on the list: `createFoldedText`, `createGradientText`, `createMagazineText`, `createPaperCutText` and `createTileText` are one-line wrappers over the letter-collage styles this server already offers, and `plotFunction`/`plotParametric`/`plotSurface` wrap three generators it already exposes. A method-name diff cannot tell "no tool reaches this" from "a tool reaches it under another name."
239
+
240
+ **Animated character parts no longer jump the moment they start moving.** `pinepaper_character` places each part at its path's bounding-box centre — the point PinePaper's `position` names — while the keyframe tracks were anchored on the depiction's declared anchor. The two are not the same point, so every animated part snapped between them as soon as its t=0 keyframe evaluated: measured at 19.6px for a pigeon's beak, which detaches it from the head. A track is relative motion around a base, so re-basing it on the centre the part was actually placed at preserves every displacement and removes the snap — now 0.000000px, with a test that also checks the performance did not flatten into a constant in the process.
241
+
242
+ **A concept that inherits performs and inks like the one it inherits from.** Two defects in the same resolver, both measured. Channels were read off the concept alone, so `pp:Bus` — which composes `pp:Vehicle`'s parts and inherits its `jounce` and `travel` — returned **zero tracks** with every beat reported ignored, while claiming success. And ink was keyed on the concept *requested* rather than the depiction actually composed, so `pp:Bus` drew 0 stroked parts where `pp:Vehicle`, the same geometry, drew 3 — the "flat art dropped into an inked scene reads as pasted in" failure the ink exists to avoid, hitting exactly the concepts that inherit rather than declare. Both now match their parent measure for measure, `pp:House` included.
243
+
244
+ **`pinepaper_character` stops silently ignoring four arguments it documents.** `position`, `scale`, `palette` and `ink` were all handled by the resolver and absent from the schema, so zod stripped them and a call written the way the rest of this vocabulary reads landed dead-centre at the default size — the precise outcome the resolver's own comment says must not happen.
245
+
246
+ **Two production advisories cleared, both found by validating the release rather than by anything failing.** `fast-uri` (HIGH — host confusion via skipped IDN canonicalization, SSRF via malformed IPv6 normalization, SSRF via repeated hostname percent-decoding, host confusion via percent-encoded scheme normalization) and `hono` (MODERATE — `toSSG()` writing outside its output directory, unbounded dot-notation nesting in `parseBody()`, a query parser reading past the URL fragment). Both arrive transitively and are pinned to floors in `overrides`, so neither resolver can drift back; both lockfiles re-resolved and `npm audit --omit=dev` reports zero.
247
+
248
+ **`pinepaper_design_medium`'s thread surface is now the whole engine's, and the second tool over it is gone.** `pinepaper_create_stitchcraft` was removed: **all six** of its presets dispatched into the same `ThreadPainting` module `apply_thread` already reaches — `embroidery_satin` → satinBetween/fillRegion, `running_seam` → runningStitchContour, `cross_stitch` → crossStitchFill, `stem_outline` → stemAlong, `seed_texture` → seedFill, `needlepainting` → fillRegion. Two tools over one engine is exactly the drift this surface keeps paying to remove.
249
+
250
+ - `apply_thread` now offers **all six stitches the engine publishes**, not four: `runningSeam` and `crossStitch` were missing, and they are what a caller reaching for stitchcraft wanted. It also gained the per-stitch parameters `STITCH_OPS` declares and nothing named — `slant`, `overlap`, `stagger`, `gapLen`, `gridSize`. `slant` is the one that matters most: a satin fill laid at a slant is what separates embroidery from ruling.
251
+ - `roughness` is hand wobble, applied by the tool *after* the engine lays the stitches, since the engine has no such option. Every point of every stitch takes its own phase off the seed, so a long contour wobbles along its whole length rather than shearing at one end, and a given seed sews the same irregularities every run.
252
+ - `pp:Stitchcraft` points at `pinepaper_design_medium` now.
253
+ - **And the list has one definition.** It had four copies here — two Zod enums and their two JSON mirrors — so correcting one left `pinepaper_compose` unable to ask for two stitches `apply_thread` could. The engine had the identical split for the identical reason on the same day: `MEDIA.thread.stitches` was hardcoded to the same stale four while `STITCH_OPS` published six. Two repos, four copies, one list, drifted the same direction — because neither read the published table. It is `THREAD_STITCHES`, declared once and spread, with a test asserting every served copy matches.
254
+
255
+ *Two corrections to this note, made in place rather than quietly edited.*
256
+
257
+ The removal was first justified as a tool "built on a phantom", because `app.applyStitchcraftToItem` had zero hits in the engine. The grep was accurate and the inference was not, twice over: the capability is real — it lives in `js/core/StitchcraftPresets.js`, imported as a module by the code runner and never exposed as an `app.*` method — and it returned zero hits only because that file was unpushed when the search ran. A missing method and an unpushed commit look identical to a grep and call for opposite responses. The redundancy was always the real reason, and it is the better one.
258
+
259
+ The replacement enum was then built by scraping quoted strings out of `ThreadPainting.js`, which is not the same thing as reading what it publishes. `STITCH_OPS` is the vocabulary, and it holds exactly six names. The scrape added eight that are planner functions and field kinds — `satinBetween`, `fillRegion`, `radial`, `spine` and the rest, every one of which `applyThreadPainting` refuses — and it dropped `runningSeam` and `crossStitch`, which are real. For one commit this surface advertised eight stitches that error and hid two that work, while removing the tool that had offered them. Enum parity means diffing against the published vocabulary, not against the file.
260
+
261
+ **New tool: `pinepaper_design_system`** — the design vocabulary as data, and eighteen styles that build a scene. Two different things, kept apart because they are not the same claim:
262
+
263
+ - A **design system** is a real, licensed, versioned product — Material Design 3, IBM Carbon, Polaris, Fluent 2, Spectrum, Primer, USWDS, GOV.UK and more. Twenty-one of them, as W3C DTCG tokens. `list_easings` returns every motion curve across all of them as a named easing with its licence — and with `pinepaper:authored` on the three we had to fill in, so a vendor's published curve and one of ours are never mistaken for each other.
264
+ - An **aesthetic style** is a look: Bauhaus, Art Deco, Swiss, De Stijl, vaporwave, risograph, brutalist, Memphis, claymorphism, op art, pixel art. Thirty-one named, eighteen of which `compose` a titled scene. `draw: false` returns the scene and the ops as data and draws nothing — read the composition before committing to it, the way `pinepaper_story`'s `distill` works.
265
+
266
+ This runs in the server, not the browser: a design decision does not need the canvas to be open. The data is **vendored** from mcp-cloud by `scripts/sync-design-systems.mjs`, the same shape as the engine's stick-figure sync — one authored copy upstream, a mechanical mirror here, a sha256 in every header, and a provenance test that fails on a hand edit. A partial composition reports as a failure naming the elements that did not create, rather than as a success with half a poster.
267
+
268
+ **New tools: `pinepaper_stick` and `pinepaper_story`.**
269
+
270
+ - `pinepaper_stick` is the vendored stick-figure kit — a rigged figure posed, walking, travelling, holding a prop, with a garment and hair and a timeline of expressions, plus the floor and wall it stands on. Distinct from `pinepaper_character`, which places a figure from the *design graph* by concept. Its options were discoverable only by reading the engine's source. The geometry is vendored from mcp-cloud, which makes it a three-repo artifact, and the failure message says so — the fix for a missing kit is in another repository.
271
+ - `pinepaper_story` turns prose into a scene. `distill` reduces an article to its beats and **draws nothing**, which is the half worth having on its own: read what the distiller made of the text, edit the beats, and only then assemble. Discovering that reading by looking at a finished scene is the expensive way round.
272
+
273
+ **New tool: `pinepaper_interchange`** — Lottie, dotLottie, GLB, BVH and PNG sequence. `pinepaper_agent_export` covers the *platform* formats sized for Instagram or YouTube; these are the ones another tool reads, and they had no tool at all. Import is here too, because a format you can only write is half a bridge.
274
+
275
+ - `exportGLB` and `exportBVH` refuse through `console.warn` and a falsy return, and the production build strips the console — over MCP that is a silent nothing. Both preconditions are checked before the call and named: "no perspective objects to export — create one with `createObject3D` first", "no rig to export — create a skeleton first".
276
+
277
+ **New tool: `pinepaper_sound`** — synthesis, and the drawing that is the same object. The engine carries a whole audio graph and nothing reached it; `pinepaper_audio_beats` *analyses* audio that already exists, and this *makes* audio.
278
+
279
+ - Tones, chords (by name, with the Hz readable without playing), named percussion and SFX, and plain-language descriptions — `from_text` resolves "a soft warm bell on A4" to a spec **without** playing it, so a caller can inspect or edit before committing.
280
+ - **Sound and drawing are one object, both ways.** `create` draws a sound *as* a waveform path: edit the path and the timbre changes with it. `timbre_from_path` reads any drawn path back as harmonic content — a curve someone drew by hand becomes the partials of a note.
281
+ - `timbreFromPath` answers a flat single-partial timbre for anything that is not a path with length, which is a legitimate timbre *and* the refusal, indistinguishable once returned. So the item is checked before the call and a non-path is refused by name.
282
+
283
+ **New tool: `pinepaper_motion`** — the generators' Animation knob, pointed at anything. The motion engine every generator's own animation runs on was reachable from the code console and from custom generators, and from no tool call.
284
+
285
+ - A **group** motion (drift, sway, rotate, pulse, wave, bounce) moves the target as one. A **field** motion (ripple, breathe, undulate) sweeps a crest *through* the children from an origin, with a chosen waveform — a wave passing through a crowd rather than a crowd moving together. Nothing else on this surface could do the second kind: `pinepaper_animate` applies a loop preset to one item.
286
+ - `action: 'list'` returns the engine's own catalogue. `motion` is deliberately a free string rather than an enum: pinning the names here is exactly how `add_relation` came to list 39 of the engine's 134 relations.
287
+ - Origins include `random` (every element on its own phase — a twinkle, not a wave) and `roam` (hopping between the corners and the centre); pass a `seed` to make `random` reproducible.
288
+ - The waveform `spike` is a narrow bump. It was called `pulse` until the engine noticed one word was naming both a waveform and an animation; saved scenes still carry the old spelling and it is still accepted, but it is not offered as a choice.
289
+
290
+ **New tool: `pinepaper_path`** — the destructive path operations Paper.js has always had and nothing here could reach. Booleans (`unite`, `subtract`, `intersect`, `exclude`, `divide`), `simplify`, `outline_stroke`, `toggle_closed`, repeat `pattern`s (concentric, radial, grid, extrude), `get_geometry`, and a lock.
291
+
292
+ - They live apart from `pinepaper_modify_item` on purpose: modify restyles an item and keeps its id, while every action here changes what items *exist*. A boolean **consumes its operands** — they stop existing, and their relations and keyframes go with them. The tool description says so, because a caller who reads a boolean as a restyle loses work.
293
+ - `outline_stroke` is the one worth knowing about: it turns a stroked line into a filled shape of the same width, which is what you do before exporting to a format with no stroke model, or before a boolean against a line.
294
+ - Each refusal is the engine's own — "a boolean needs at least two paths", "that path has no stroke to outline", "simplify needs a path" — passed through rather than reworded, because two wordings for one condition is the defect this project keeps fixing. The single exception is `get_geometry`, whose facade returns a bare `null`; that one place supplies a wording.
295
+
296
+ **`pinepaper_world3d` gains the mesh half, the import half and the physics half — 33 actions.** The graph learned to record `meshProvenance` above, and nothing could author a mesh: it could describe a thing the tool surface could not make.
297
+
298
+ - `extrude_path` sweeps a canvas path along a depth; `lathe_path` revolves its profile. The path itself is untouched — the mesh is new, and the engine records the op, the source path and the options as the mesh's provenance, so a captured scene can rebuild it rather than merely recognise it. **The option names on this action are exactly the names in that record**, pinned by a test, so `meshProvenance.opts` spreads straight back in.
299
+ - Lights (`add_light` / `set_light` / `remove_light` / `list_lights`) and shared materials (`add_material` / `set_material` / `remove_material` / `list_materials`), plus `list_meshes` and `remove_mesh`. At most 8 point lights exist at once: the shader array is fixed-size, so a ninth is refused by name rather than ignored.
300
+ - **`rotY` is radians, and says so.** It is stored raw and handed to `cos()`/`sin()` in the shader with no conversion anywhere on the path — an exception to the degrees convention the rest of this surface follows, and the sort of thing that silently produces a scene rotated by a factor of 57. `rotYDegrees` is the convenience spelling and is folded in before the engine sees it. (`arc` on `lathe_path` *is* degrees; the engine converts that one.)
301
+ - **Import and navigation.** `import_obj` and `import_gltf` bring real geometry in; `list_mesh_clips` and `set_mesh_clip` play what a skinned model arrived with. `set_nav_target` decides whether the pointer drives the 2D canvas or the 3D world, `ground_height` and `canvas_to_ground` and `world_to_canvas` convert between them, `raycast` picks, and `dolly_camera` / `pan_camera` move the view.
302
+ - **Physics in the world**, distinct from `pinepaper_physics` (which is the 2D `physicsWorld`) and deliberately narrower: a sphere or capsule under gravity, colliding with terrain, objects, actors and imported meshes. No stacking solver and no joints. `step_physics` reports the contacts made and the bodies removed — and returns `{contacts: [], removed: []}` with *no world*, which is exactly what a quiet step returns, so the guard is what separates them.
303
+ - **Several of those facades answer `null` — or `0` — when there is no world**, which is indistinguishable from a real answer: ground really can be at height 0, and a ray really can hit nothing. Each is guarded ahead of the call, so "there is no world" never arrives disguised as a measurement. Once past the guard, a null from `raycast` can only mean a miss, and is reported as one.
304
+ - **`add_object` stops advertising knobs that reach no pixel.** It offered `metalness`, `roughness` and `emissiveIntensity` — but a plain object is drawn by the prop shader, which declares no such uniform, so those were stored, listed and ignored. They render on the mesh path only, and the description now says which is which instead of letting a caller set one and see nothing.
305
+
306
+ **`attracts` was live in the engine and unnameable here.** The relation-parity guard compares the tool enum against a fixture of the engine's relation map — but the fixture is copied by hand, so the guard passed while the engine moved. The fixture is refreshed and `attracts` is callable. The exclusion list that keeps tool-emitted families (`deform_*`, `effect_*`, `geo_*`, the rigging set) out of `add_relation` is unchanged, and still written down with its reason.
307
+
308
+ **`pinepaper_character` was defined and dispatched nowhere.** It shipped in 1.6.7 as a schema with no handler behind it — the worst version of the problem this project keeps naming, because the tool *listed*. It is wired now, and a test fails the build if any defined tool has nothing dispatching it.
309
+
310
+ **Four chart types classified as `pp:Group`.** The graph's type lookup lowercased the item type before consulting its map, so every camelCase key in that map was unreachable — `barChart`, `lineChart`, `scatterPlot` and `areaChart` answered `pp:Group` instead of their own types. Nothing errored; a caller got a readable graph of the wrong thing. The lookup tries the key as spelled before folding case, and a test now asserts every key in the map is reachable, so the next camelCase key the engine adds fails a test instead of quietly answering `pp:Group`.
311
+
312
+ **The error path could throw while reporting an error.** Canvas-state capture promises never to throw and returns whatever the studio handed back, but the formatter read its fields unguarded — so a partial state replaced a real failure with a `TypeError` from the error path itself. Every field is read defensively now.
313
+
314
+ **The instrument catalogue stopped being a ceiling, and the soundtrack can be rendered.** Five audio facade methods landed in the engine after `pinepaper_sound` was written, and the tool could list and play the seventeen built-in sounds and nothing else — so a rhodes, a koto or a taiko was unreachable, while the engine's own comment calls those tables "a curated starting set, not a claim that music contains six instruments."
315
+
316
+ - `define_instrument`, `define_percussion` and `define_sfx` register a sound at runtime. It is first-class from then on: `listInstruments()` reads the live table, so it appears in the `list_*` catalogues and plays by name like a built-in. The response returns the **canonical** name — registration normalises to `[a-z][a-z0-9_-]`, so a model that registers `Rhodes` and plays `Rhodes` is naming something that does not exist.
317
+ - The engine's rules are mirrored rather than tightened. A melodic instrument needs a partial table because one without renders silence; percussion and SFX may be **pure noise**, because a hat and a whoosh are, and tightening that would refuse exactly the sounds the relaxation exists for. `pitch: {from, tau}` is carried through — the glide *is* the drum, and without it a defined kick comes out a beep.
318
+ - `pinepaper_agent_export` takes **format: `wav`** — the soundtrack on its own, off the visual path. No platform preset resolves to it, so a request for a picture can never come back as audio; it has to be asked for by name. `framing: camera` and the audio knobs on a visual format are *rejected* rather than ignored, because silently dropping them leaves a caller believing something untrue about the output, and `estimateOnly` reports confidence `exact` — uncompressed PCM size is arithmetic, and a model would only be less true. The empty case distinguishes two things the engine distinguishes: a scene with **uploaded** audio renders to nothing here (the offline renderer bakes only what it can synthesize) and is routed to mp4/webm, which mux it — telling that caller "no audio" would be false.
319
+ - `render_soundtrack` mixes every placed sound to a WAV **offline** — no Web Audio, no playback, which is what makes it work in a headless studio — and writes it to a file through the same path video and PDF take. An empty scene is refused by name instead of producing a silent file, and any sound that could not be mixed is reported as `dropped`: a soundtrack missing a track otherwise looks exactly like a complete one.
320
+
321
+ **Eleven shapes the engine draws were reachable from nothing.** FxTool's `ShapeRegistry` registers 34 shapes and `create()` delegates any of them. Flowchart, UML and network route through `pinepaper_create_diagram_shape`, so 23 were callable — and the other eleven appeared in no tool enum anywhere: `disk`, `circle-outline`, `arrow-right`, and the **entire** annotation set (`speech-bubble`, `speech-bubble-square`, `speech-bubble-pointed`, `thought-bubble`, `comment-box`, `callout-box`, `double-bubble`, `quote-bubble`). The renderer was never the limit: `create()` already forwards `tailDirection` and `tailSize`, parameters that exist only for bubbles. So an agent asked for a comic panel or an annotated diagram had to hand-build the outline or decline, for a shape the engine had the whole time. `itemType` goes 17 → 28, each one documented with the engine's own description rather than a guess, and the emitted code is *executed* against a stub in the suite — reading a spread operator and inferring the rest is how a widened enum ships a dead door.
322
+
323
+ **The media list advertised seven of nine.** `hatch` and `watercolor` — both native fidelity, and `hatch` has its own `apply_hatch` action in the same tool — were missing from the served JSON description while the Zod copy beside it and the agent guide both listed them. Three copies, and the stale one was the copy a model reads. `pinepaper_compose`'s two-medium enum was checked against the engine for the same reason and is correct: `COMPOSABLE_MEDIA` is frozen at `['vector','thread']`, and both tables are fixtures now.
324
+
325
+ **A scene read could be 500 items of 800 and say nothing.** `exportCanvasOntology` returns the true `itemCount` beside an item list capped at `maxItems`, and `childCount` beside a capped children array — so a partial answer was indistinguishable from a complete one unless the caller thought to compare two fields that look like they agree. Truncation is now reported when, and only when, something was clipped: both numbers, the knob to raise, and what to do past 500 where the cap truncates rather than paginates. An older studio that omits `itemCount` is reported as unknown, never as partial.
326
+
327
+ **The server's own identity string banned two tools it ships.** `SERVER_INFO.description` carried a flat prohibition on producing HTML or React — no qualifier, no tool named — while this server ships `pinepaper_export_widget_html` and `pinepaper_export_widget`, which produce exactly those. That string is the first text a client shows a model, before any tool, every session. Same defect as the `agent_start_job` description fixed above, in the widest-read place available. The rule is substitution, not format — and the prohibition is described here rather than quoted, because the guard flags a banned imperative in this README too, and it is right to: a model reads the sentence, not the quotation marks around it. The guard that catches it had been reading two surfaces out of four; it now sweeps all 19 resources, every prompt, all three verbosity tiers, the manifest and this README, and its liveness floor compares against the declared lists name by name rather than counting.
328
+
329
+ ## What's new in 1.6.7
330
+
331
+ **Four more item-stage shader effects** — `electric_arc`, `vortex`, `rain_veil`, `caustics` (ABYSSAL's noise library). The `item` shader stage went from four built-ins to eight and nothing here named the new half.
332
+
333
+ **`on_key_fire` now matches a chord exactly.** Its modifier tests were one-way — they required a modifier that was asked for but never rejected one that was not — so `{ key: 'Enter' }` fired on Ctrl+Enter, Shift+Enter and Cmd+Enter alike, and `{ key: 's' }` fired on the browser's own Ctrl+S. Those are different intents. The relation's documentation says so now, along with the focus gate that keeps it from taking keys from the rest of the page. (Reported from this repo during the relation audit; fixed engine-side.)
334
+
335
+ **Three appliers that failed in silence now report.** The engine's `animate`, `applyAnimatedMask` and `applyCutoutStyle` refused an unknown key only through `console.warn`, and the production build strips the console — while returning values identical between success and failure (`undefined` either way, a Paper Group either way, and the very item it was given). Over MCP, where there is no console to read, an unknown key left the canvas unchanged and told every caller it had worked.
336
+
337
+ The engine now records the refusal on the item it already hands back, and these tools read it: a refused animation type, a mask that applied but will never animate, and a cutout preset that returned the item untouched are all reported as failures, each carrying the requested value **and the known list**, so a caller can correct itself without a second round trip.
338
+
339
+ **New tool: `pinepaper_character`** — place a figure from the graph and direct it. The character layer was reachable from the cloud's build script and nowhere else, which by this project's own rule means it did not exist: an MCP client, a cloud caller and a small on-device model all see these schemas and nothing behind them.
340
+
341
+ - It replaces roughly thirty exactly-right calls — create the skeleton, add each bone with the right parent and angle, create each shape, attach each to the right bone, then author poses — where one mistake anywhere leaves a broken figure. That volume of exactly-right output is the reported reason characters do not work for smaller models.
342
+ - Direction is declarative beats: `{ concept: "pp:Pigeon", at: {...}, height: 300, beats: [{ at: 0, channel: "bob", until: 8 }, { at: 1.4, channel: "blink" }] }`.
343
+
344
+ **`create_item` gains `shader` and `field` item types.** The cloud renderer has drawn shaders and parametric fields for months, reachable only by hand-writing a scene document — so the capability existed for whoever writes the build script and for nobody else.
345
+
346
+ - The description names the parameters and the expression variables a field is written in: a parameter nobody can discover is the same as a parameter that is not there.
347
+ - `bornAt`/`ttl` are documented on `properties`. They always passed through (`properties` is a free record) and nothing mentioned them, so no caller could build a piece that cuts between shots — which is why the only multi-shot pieces that exist had their shots inferred from a naming convention in a build script.
348
+ - **A surface is not a shape**, and the ontology now says so instead of filing these under Path because they also end up as pixels: `pp:CanvasSurface`, with `pp:ShaderSurface` and `pp:ParametricField` under it. A shape is built as an item and drawn from its geometry; a surface is evaluated as the frame is drawn.
349
+
350
+
351
+ **New tool: `pinepaper_import_motion_capture`** — BVH import and retarget. The engine has had `importBVH`/`retargetBVH` for releases and nothing exposed them; a model cannot use a capability no tool call reaches.
352
+
353
+ - `mode: 'import'` builds a new skeleton shaped like the capture file. `mode: 'retarget'` drives an **existing** rig, so proportions stay the character's and only the motion comes from the clip — that distinction is the reason the tool exists.
354
+ - Angles transfer as bind-pose deltas, so a T-posed CMU rest is not slammed onto a rig with a relaxed stance. Bones the alias table cannot place come back as `unmatchedSource`/`unmatchedTarget` instead of silently driving half a rig, so a caller can build `boneMap` from the failure. `fps` defaults to 15 — CMU records at 120, and nobody wants 120 poses a second on a canvas timeline.
355
+
356
+ **`pinepaper_rigging` gains the pose-motion half — 18 actions.** The engine had 26 pose methods; the tool exposed two. The pose library (`list_poses`, `load_pose`, `interpolate_poses`, `list_skeletons`), playback (`play_pose_sequence`, `stop_pose_sequence`, `apply_pose_transition`), procedural layers (`auto_walk`, `auto_breath`, `auto_idle`, `auto_jump`), root locomotion (`move_root`, `stop_root_track`), and the export/deform edges (`bake_animation`, `add_secondary_motion`, `skin_path`, `list_shape_keys`, `load_shape_key`). Each was checked against the engine source rather than its docs, which name tools that were never registered.
357
+
358
+ - **New capability: `stitch_poses`** — join clips into one continuous performance, entering a cyclic clip at the phase closest to where the previous one ended so the legs do not teleport mid-stride.
359
+
360
+ **New tool: `pinepaper_design_medium`** — the third design axis: what physically makes the marks. Every medium declares a *fidelity*, and `resolve` refuses the ones it cannot honestly render rather than producing flat shapes in their colours. `apply_thread` renders an item as needlepainting; the direction field is what separates that from hatching.
361
+
362
+ **New tool: `pinepaper_text_effect`** — 37 character-level text animations (terminaltexteffects' vocabulary, reimplemented in the engine from source). `list` returns the effects; `apply` explodes a text item into one animated item per character.
363
+
364
+ - The planner is pure and emits **keyframes**, so the result is ordinary animated items: it scrubs on the timeline, survives undo and session restore, and exports through the existing MP4 / SMIL / Lottie paths. Every effect ends at rest.
365
+ - **It replaces the text item.** Unlike `pinepaper_text_style` (which adopts the text's registry id), this removes the original and returns the new per-character ids — so relations and keyframes on the source id do not survive. `keepSource: true` is the escape hatch. The tool is marked `destructiveHint` and says so in its description, because it inverts the id-preservation convention every neighbouring tool follows.
366
+ - Resting characters are painted with a gradient across the text block by default (what the upstream effects actually do); `gradient: false` keeps the authored fill. `seed` defaults to 1, so a given text + effect + seed animates identically every run.
367
+
368
+ **Two more enums that named things the engine does not have.** Both were the same shape as the relation gap, found by diffing every validated enum against the engine rather than by anything failing.
369
+
370
+ - **`canvasPreset` on the agent-flow tools** passed an export *platform* name (`instagram`, `youtube`, `web`) straight to `setCanvasSize`, which keys on `instagram-post` and `full-hd-1080p`. Seven of ten matched nothing: the engine fell through to its default, resized the artboard to 800×600, and recorded the preset as applied — so asking for an Instagram canvas got neither the size nor an error. Now mapped, and pinned by a test against the engine's preset list. The platform vocabulary is unchanged, because `instagram` is the right word for an export target and only the canvas-size use was wrong.
371
+ - **`pinepaper_modify_item` now documents `pathData`** — reshaping the geometry itself, not just its styling, so a traced or hand-drawn outline can be corrected without deleting and recreating the item (which would lose its id and every relation and keyframe pointing at it).
372
+
373
+ **`pinepaper_animate` offered an animation that does not exist.** `slide` was in the enum, in three JSON schemas and in two prose lists. The engine has no such type — the real ones are `slideLeftRight` and `slideUpDown`. It accepted the value, wrote it to the item, and the driver's switch fell through: the item sat still while its own data claimed a slide, and the call reported success. The same enum hid twelve types that do work (`breathe`, `glow`, `jelly`, `path`, `shake`, `swing`, `scrollUp/Down/Left/Right`, and the two real slides), so the surface both invented one animation and concealed a dozen.
374
+
375
+ All 18 driver types are now offered, and a parity test pins the enum, every JSON-Schema copy of it, and the prose against a fixture of the engine's `ANIMATION_TYPES`. A unit test that asserted `slide` parses — pinning the bug in place — was corrected. Letter collages keep their own separate four-name vocabulary, which is not drift.
376
+
377
+ **95 live relations were not callable.** `pinepaper_add_relation` offered 39 of the engine's 134, and the enum is a hard gate — a name missing from it is rejected at validation. The missing set was not a random 95: it was essentially the entire **interactive** vocabulary, every event-channel relation included, so the state-machine-via-relations capability was undiscoverable and unusable. `pinepaper_scene_graph` was emitting `on_click_fire` and `on_event_set_active` relations that an agent could not then create, inspect or recreate by hand.
378
+
379
+ Nothing was broken at runtime, which is why it survived: the engine could do it and nothing could *name* it. For a model those are the same condition.
380
+
381
+ - **42 relations are now callable** — the input triggers (`on_click_fire`, `on_pointer_enter_fire`, `on_pointer_exit_fire`, `on_key_fire`), the full `on_event_*` reaction set including template-interpolated property writes and the persistent-store pair, the `on_enter_*`/`on_exit_*` proximity families, `exclusive_group` / `menubar_group`, and the behavioural relations `repels`, `wiggle`, `spring_follow`, `syncs_with`, `triggers_animation`, `connects_to`, `part_of`, `attached_to_tail`, `head_points_to`, `anchored_in_world`, `tours`, `synced_to_audio`, and `expresses` — which `pinepaper_import_layered_character` already promised would make an imported character blink, while the enum made it unnameable.
382
+ - **Relations a dedicated tool emits stay out** — `deform_*`, `effect_*`, `geo_*`, `bone_*` and friends. The agent authors those *through* that tool, and a second name here would be a worse way to do the same thing. That exclusion list is written down with its reason, so the next engine diff doesn't re-litigate all 95.
383
+ - **The map behind the validator was the same bug one layer down.** `RELATION_TYPE_MAP` gates "is this a known relation", so a relation callable but unmapped makes the validator report a perfectly valid scene as using an unknown one. 40 entries and 42 `pp:` edge definitions were backfilled from the engine's own descriptions.
384
+ - **The real fix is the parity test.** The enum is duplicated across five tool schemas plus the zod schema, and nothing checked any copy against the engine or against each other. It's now pinned to a fixture of the engine's registry map, asserting in both directions — nothing offered that the engine cannot run, nothing runnable that the surface hides — and that all six copies agree. The additions are just this week's payload.
385
+
386
+ The relation catalogue in the tool description now names families rather than all 80 members, and points at `pinepaper_query_capabilities { kind: 'relation' }` for the live list, which reads the registry instead of a list written down in prose.
387
+
388
+ **Hatching reaches the tool surface** — `pinepaper_design_medium` gains `apply_hatch`, `list_flow_fields` and `list_hatch_options`. PinePaper could fill and it could stitch, and it could not hatch; the gap was already named in the thread-painting code, which notes that a constant stitch field "looks like hatching, which is a different medium."
389
+
390
+ - **Hatching states value through line density, not colour.** The same shape at 6px spacing and at 3px reads as light and dark with nothing else changed. `gradient` makes the density fall off across the shape — a shaded ramp rather than a flat tone.
391
+ - The straight ruling is what a printer makes; `flowField` is what makes it read as *drawn* — `hand` is the small correlated wander of a hand-drawn line, `waves` for water and hair, `spiral` for wood grain around a knot. `continuous` joins the whole set into one serpentine path.
392
+ - Reimplemented from [p5.brush](https://github.com/acamposuribe/p5.brush)'s source (MIT, Alejandro Campos Uribe), **not vendored**: p5.brush is WebGL2-only and its output is raster, so vendoring it would put a second renderer in front of Paper's vector geometry and forfeit infinite-resolution scaling, SVG export and the relation graph. The maths is renderer-agnostic and is the part worth having.
393
+ - Every refusal names its fix. The engine reports all five of its distinct failures as `console.warn`, which production strips — so the tool checks the shape first and answers "text has no outline, convert it with `pinepaper_text_style` first" or "distance is 400px against bounds 150x150" instead of a bare null. A group is hatched up to 40 paths and says so when there were more.
394
+
395
+ **GSAP's vocabulary, PinePaper's engine.** An audit of GSAP's concept set against the 49 relations found most of it already present under other names — MotionPath is `moves_along_path`, MorphSVG is `morphs_to`, DrawSVG is trim paths, Physics2D is `spring_follow`, SplitText is the 37 text effects, nested timelines are precomps, and `wiggle` is richer than CustomWiggle. Five concepts were genuinely missing. They are adopted as **vocabulary, not as a dependency**: a second animation runtime is one that none of the SMIL, Lottie or MP4 exporters would understand, so the grammar is GSAP's and the implementations are independent.
396
+
397
+ **New tool: `pinepaper_sequence`** (`pp:TimelinePosition`) — say WHEN relative to something else instead of in absolute seconds. `"<"`, `">"`, `"+=1"`, `"-=25%"`, labels and `"intro+=0.5"` resolve to seconds, and `place` threads a whole run so each clip resolves against the ones before it. A pure planner; it touches nothing.
398
+
399
+ - The one thing to get right: **a percentage means different things in different forms.** `"-=25%"` is a quarter of the clip *being inserted*; `"<25%"` is a quarter of the *previous* one. They agree only when the two clips are the same length, and getting it backwards yields timings that look almost right.
400
+
401
+ **New tool: `pinepaper_stagger`** (`pp:Stagger`) — the shape of a delay across many items: a grid lighting up outward from the centre, a row converging from both edges. `each` fixes the gap between neighbours; `amount` fixes the total. Delays are written to the channel the engine and the SMIL exporter already read, so a staggered scene scrubs and exports — nothing here is playback-only. `staggered_with` gains the same shape parameters (`count`, `from`, `amount`, `grid`, `axis`, `distributeEase`).
402
+
403
+ **New tool: `pinepaper_flip`** (`pp:Flip`) — animate a layout change *without describing the motion*. Record where things are, rearrange them however you like, and the transition is derived from the difference: the one animation an author never has to specify, which is what makes it usable for re-sorts, auto-layout passes and filters nobody could enumerate in advance. It writes ordinary keyframes, so the transition scrubs and exports. Rotation is compared on the shortest arc — 359° to 1° is a two-degree move, not a near-full spin the wrong way.
404
+
405
+ **`pinepaper_play_timeline` gains rate, progress and scroll** (`pp:TimeScale`, `pp:InputDrivenPlayback`) — `set_time_scale` / `get_time_scale`, `get_progress` / `set_progress`, `bind_scroll` / `unbind_scroll` / `list_scrub_anchors`.
406
+
407
+ - Rate is deliberately unclamped: 0 freezes the clock without stopping playback, and a negative rate runs the scene backwards. Changing it rebases the clock, so the playhead does not jump. **Export is unaffected** — a scene watched at 0.5x still exports its real duration rather than a file twice as long.
408
+ - Scroll binding always releases a previous binding first: the listener holds the scene alive, so a rebind without an unbind is a leak *and* leaves two bindings scrubbing one timeline.
409
+
410
+ **`orbits` gains `phaseDegrees`.** `phase` was the single parameter in the whole relation vocabulary measured in radians, against this engine's own stated convention that angles are degrees. `phaseDegrees` now takes precedence; `phase` is kept, and documented as the exception, because changing it outright would silently re-time every scene that already sets it — a 57× error of exactly the kind the convention exists to prevent.
411
+
412
+ **`pinepaper_design_medium` was served but unlisted.** It had been missing from `manifest.json`'s tool list since it shipped — introduced above, but invisible to the marketplace listing. Caught by the prepublish guard while regenerating the manifest for the tools above.
413
+
414
+ **New tool: `pinepaper_scene_graph`** — compiles an interactive story or quiz into native items and relations: cards, answer buttons, click→event routing, exclusive-group mutex visibility, and score tracking.
415
+
416
+ - `action: 'validate'` runs the same structural check **without drawing anything** — errors, warnings, reachable nodes, cycles. Check a generated graph before committing a canvas full of cards to it.
417
+ - The schema refuses a graph the engine would refuse, and one it would silently mangle: a dangling `to`, a `start` naming no node, a non-terminal card with no way out, and **duplicate node ids** — the engine keys its node index by id, so a repeated id quietly replaces the earlier node rather than erroring.
418
+ - Two ways out of a card: `answers` waits for a click, `next` (+ `duration`) auto-advances for a linear story beat.
419
+ - The result forwards `failed`, `wired` and `cycles`. A graph can render completely and still leave relations unwired — it looks built and is inert, and that count is the only thing that says so.
420
+
421
+ **New tool: `pinepaper_query_capabilities`** — asks the engine what it can do (text styles, character effects, generators, deforms, relations) and recommends one: `list`, `find`, `coverage`, and a mood/subject-weighted `choose`.
422
+
423
+ - It reads `app.getCapabilities()`, which **warms the lazy registries first**. Generators do not exist until the heavy modules land (~1.2s after boot) and the rigging/blending/deform relation rules only register once their subsystem is touched — answered cold, the engine reports zero generators and roughly 77 of ~100 relations. `warm: false` opts out when a cheap re-read of what is already resident is enough.
424
+ - `coverage` names its own blind spots: kinds with no source wired, and entries that can be applied but not *ranked* because they carry no description. A chooser that scores on description can never recommend those, so it says so.
425
+ - `seed` gives a stable tiebreak among equal-scoring candidates; with no seed the order is stable by key. Either way a repeated call answers the same way.
426
+
427
+ **Every tool property now declares a type.** Ten inputs across `pinepaper_event`, `pinepaper_component`, `pinepaper_world3d`, `pinepaper_rigging`, `pinepaper_text_style`, `pinepaper_equation_path` and the new capabilities tool were published with a description and no `type` — valid JSON Schema, but strict function-calling clients reject a typeless property, and this server claims to work with any MCP-capable model. They are `anyOf` unions now.
428
+
429
+ **`pinepaper_connect` / `connect_ports` accept an `id`.** `update_connector` and `remove_connector` address a connector by `connectorId`, and there was previously no value a caller could correctly pass — creation returns code rather than a result, and the engine's fallback is timestamp-based. Assign your own and reuse it.
430
+
431
+ **`pinepaper_world3d` `add_object` forwards PBR material fields** — `metalness`, `roughness`, `emissiveIntensity`. *(Corrected in 1.6.8: `metalness` and `roughness` are accepted and ignored on a plain object — the prop shader declares no such uniform. They render on the mesh path. Left here rather than quietly edited, because a drifted claim is worse than a missing one.)*
432
+
433
+ Follows 1.6.6, whose dependency-security work is described below.
434
+
435
+ **Dependency security.** `puppeteer` moves to ^25, clearing GHSA-jmr9-qjv8-65gv (`extract-zip` symlink path traversal) — `@puppeteer/browsers` 3.2.1 drops `extract-zip` entirely. The published package was never exposed (puppeteer is an optional peer), but the browser tools need one, and the path was re-verified against real Chrome rather than a green unit suite that never launches a browser.
436
+
437
+ `qs` is pinned to ^6.16.0, clearing GHSA-4mjr-xmp4-gh2g — a denial of service on the **production** chain, via `@modelcontextprotocol/sdk` → `express`. `npm audit` reported zero against it, as it did through the 1.6.6 work: its registry feed lags GitHub's. Verified instead with an OSV sweep of all 82 production packages, which is clean.
438
+
439
+ **Engine requirement.** Several capabilities this server has always emitted correct calls for did nothing until recent FxTool builds: **physics** (the step callback was never registered, so nothing moved), scene-wide **GPU filters** on the WebGPU tier, **map region colour animation** (which reported success while animating nothing), and `modify_item`'s `pathData`. No change was needed here — the calls were right — but run an FxTool from 2026-08-29 or later to get them.
440
+
147
441
  ## What's new in 1.6.6
148
442
 
149
443
  Dependency security, no new tools and no API changes:
@@ -196,7 +490,7 @@ Fourteen new tools (121 → 135) and new actions across the surface — the rele
196
490
 
197
491
  ## Toolkits & Token Budget
198
492
 
199
- 135 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.
493
+ 151 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.
200
494
 
201
495
  **Toolkit profiles** (`PINEPAPER_TOOLKIT`):
202
496
 
@@ -367,7 +661,7 @@ Choropleths, region styling, and data-driven map animation via `pinepaper_map`,
367
661
  Search and import free SVG assets from multiple repositories:
368
662
 
369
663
  - **SVGRepo**: 500,000+ icons with various licenses
370
- - **OpenClipart**: 150,000+ public domain clipart (CC0)
664
+ - **OpenClipart**: 151,000+ public domain clipart (CC0)
371
665
  - **Iconify**: 200,000+ icons from multiple icon sets
372
666
  - **Font Awesome**: 2,000+ free icons (CC BY 4.0)
373
667
 
@@ -401,7 +695,7 @@ Generate instruction/code pairs for LLM fine-tuning:
401
695
 
402
696
  ## Tools Reference
403
697
 
404
- All 135 tools, grouped by the tag used for toolkit filtering.
698
+ All 151 tools, grouped by the tag used for toolkit filtering.
405
699
 
406
700
  ### Canvas (`canvas`)
407
701
  | Tool | Description |
@@ -425,6 +719,7 @@ All 135 tools, grouped by the tag used for toolkit filtering.
425
719
  | `pinepaper_geometry` | Geometric construction primitives |
426
720
  | `pinepaper_group` | Group / ungroup / break apart |
427
721
  | `pinepaper_arrange` | Z-order: bring forward/back/front/back |
722
+ | `pinepaper_path` | Booleans, simplify, outline stroke, repeat patterns, lock |
428
723
 
429
724
  ### Batch (`batch`)
430
725
  | Tool | Description |
@@ -435,6 +730,7 @@ All 135 tools, grouped by the tag used for toolkit filtering.
435
730
  ### Import (`import`)
436
731
  | Tool | Description |
437
732
  |------|-------------|
733
+ | `pinepaper_import_motion_capture` | Import or retarget a BVH motion-capture clip |
438
734
  | `pinepaper_import_svg` | Import SVG markup |
439
735
  | `pinepaper_import_image` | Import a raster image |
440
736
  | `pinepaper_detect_objects` | Detect objects in an image (text queries, composite as nodes) |
@@ -457,9 +753,13 @@ All 135 tools, grouped by the tag used for toolkit filtering.
457
753
  ### Animation (`animation`)
458
754
  | Tool | Description |
459
755
  |------|-------------|
756
+ | `pinepaper_sound` | Synthesis: tones, chords, SFX, sound-as-waveform-path |
757
+ | `pinepaper_motion` | Generator motion engine: group and field motions |
460
758
  | `pinepaper_animate` | Apply a simple loop animation |
461
759
  | `pinepaper_keyframe_animate` | Timed keyframe animation |
462
- | `pinepaper_play_timeline` | Control playback |
760
+ | `pinepaper_play_timeline` | Control playback, rate, progress, scroll-driven scrubbing |
761
+ | `pinepaper_stagger` | Shape a delay across many items |
762
+ | `pinepaper_flip` | Animate a layout change without describing the motion |
463
763
  | `pinepaper_get_animatable_properties` | List animatable properties |
464
764
  | `pinepaper_get_available_easings` | List easing functions |
465
765
  | `pinepaper_construction_sequence` | Staged construction animation |
@@ -486,6 +786,9 @@ All 135 tools, grouped by the tag used for toolkit filtering.
486
786
  | `pinepaper_create_scene` | Create a scene |
487
787
  | `pinepaper_manage_scenes` | Manage scenes |
488
788
  | `pinepaper_scene_playback` | Scene playback control |
789
+ | `pinepaper_scene_graph` | Interactive story / quiz card scene graph |
790
+ | `pinepaper_sequence` | Relative timeline positions for a run of clips |
791
+ | `pinepaper_sequence` | Relative timeline positions for a run of clips |
489
792
  | `pinepaper_event` | Create / pulse event channels for scene chains |
490
793
 
491
794
  ### Generators, Effects & Filters
@@ -494,6 +797,7 @@ All 135 tools, grouped by the tag used for toolkit filtering.
494
797
  | `pinepaper_execute_generator` | Run a background generator |
495
798
  | `pinepaper_list_generators` | List available generators |
496
799
  | `pinepaper_apply_effect` | Apply sparkle, blast, and other effects |
800
+ | `pinepaper_text_effect` | 37 character-level text animations; replaces the text with one keyframed item per character |
497
801
  | `pinepaper_add_filter` | Add an image filter |
498
802
 
499
803
  ### Editing (`selection`, `transform`, `history`)
@@ -503,6 +807,7 @@ All 135 tools, grouped by the tag used for toolkit filtering.
503
807
  | `pinepaper_transform` | Transform items — fit to frame, nudge, flip, reorder |
504
808
  | `pinepaper_history` | Undo / redo |
505
809
  | `pinepaper_compose` | Arrange items into a named collage pattern and film it |
810
+ | `pinepaper_design_medium` | What makes the marks — media with honest fidelity, and needlepainting |
506
811
  | `pinepaper_brand_kit` | Apply brand colours / fonts by role, with a contrast audit |
507
812
  | `pinepaper_component` | Reusable master + instances, with per-instance overrides |
508
813
  | `pinepaper_artboard` | Resize the artboard; per-item reflow constraints |
@@ -569,6 +874,10 @@ All 135 tools, grouped by the tag used for toolkit filtering.
569
874
  |------|-------------|
570
875
  | `pinepaper_rigging` | Skeletons, bones, IK, breakdown poses; BVH mocap import/retarget, Spine import |
571
876
  | `pinepaper_import_layered_character` | Decomposed character layers → role-bound parts (blink/smile work immediately) |
877
+ | `pinepaper_design_system` | DTCG design systems + 18 composable aesthetic styles |
878
+ | `pinepaper_stick` | The vendored stick-figure kit: figure and set |
879
+ | `pinepaper_story` | Prose becomes a scene: distill, assemble, plan a book |
880
+ | `pinepaper_character` | Place a figure from the design graph and direct it with beats — no geometry, no bones, no poses |
572
881
 
573
882
  ### Typography (`font`, `letter_collage`)
574
883
  | Tool | Description |
@@ -594,6 +903,7 @@ All 135 tools, grouped by the tag used for toolkit filtering.
594
903
  | `pinepaper_get_items` | Get canvas items |
595
904
  | `pinepaper_get_relation_stats` | Relation statistics |
596
905
  | `pinepaper_query` | General canvas query |
906
+ | `pinepaper_query_capabilities` | Query and recommend capabilities |
597
907
 
598
908
  ### Ontology (`ontology`)
599
909
  | Tool | Description |
@@ -624,6 +934,7 @@ All 135 tools, grouped by the tag used for toolkit filtering.
624
934
  | `pinepaper_agent_end_job` | End job with summary and recommendations |
625
935
  | `pinepaper_agent_reset` | Quick canvas reset without page refresh |
626
936
  | `pinepaper_agent_batch_execute` | Execute multiple operations in batch |
937
+ | `pinepaper_interchange` | Lottie, dotLottie, GLB, BVH, PNG sequence |
627
938
  | `pinepaper_agent_export` | Smart export with platform auto-detection |
628
939
  | `pinepaper_agent_analyze` | Analyze content for export recommendations |
629
940
 
@@ -658,7 +969,7 @@ All 135 tools, grouped by the tag used for toolkit filtering.
658
969
  1. Create a yellow circle as the sun (radius 60) at center
659
970
  2. Create a blue circle as Earth (radius 20)
660
971
  3. Create a gray circle as the Moon (radius 8)
661
- 4. Add relation: Earth orbits Sun at radius 150, speed 0.3
972
+ 4. Add relation: Earth orbits Sun at radius 151, speed 0.3
662
973
  5. Add relation: Moon orbits Earth at radius 40, speed 0.8
663
974
  ```
664
975
 
@@ -747,6 +1058,10 @@ The server does not draw anything itself. It validates a tool call, generates Ja
747
1058
 
748
1059
  ### Setup
749
1060
 
1061
+ > Installing pulls Chrome down through Puppeteer (~320 MB). If that is more than
1062
+ > the machine can spare, [cloud.pinepaper.studio](https://cloud.pinepaper.studio)
1063
+ > runs the same server over HTTP with nothing to install.
1064
+
750
1065
  ```bash
751
1066
  git clone https://github.com/pinepaper/mcp-server.git
752
1067
  cd mcp-server
package/README.pt-BR.md CHANGED
@@ -14,7 +14,7 @@
14
14
 
15
15
  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.).
16
16
 
17
- São **135 ferramentas**: desenho, animação, diagramas, mapas, tipografia, física, edição de imagens, visualização de dados e exportação:
17
+ São **151 ferramentas**: desenho, animação, diagramas, mapas, tipografia, física, edição de imagens, visualização de dados e exportação:
18
18
 
19
19
  - Criar texto, formas, geometria e gráficos complexos
20
20
  - Animar com **relações** declarativas em vez de keyframes
@@ -64,6 +64,29 @@ Experimente pedir à sua IA:
64
64
  - **`pinepaper_image_filter` corrigido e ampliado** — ligado ao motor real de filtros GPU com os 15 filtros (família de meio-tom, posterizar, vinheta, HSL, dither…)
65
65
  - **README como recurso MCP** — clientes podem ler `pinepaper://docs/readme` (com variantes por idioma) sem sair do protocolo
66
66
 
67
+ ## Local ou hospedado
68
+
69
+ **Local é gratuito e completo.** Todas as ferramentas funcionam se você mesmo
70
+ executar este servidor. Não existe uma versão reduzida.
71
+
72
+ Requisitos: Node 18 ou mais recente, cerca de **320 MB** de disco (o Puppeteer
73
+ baixa o Chrome) e aproximadamente 1 GB de memória enquanto um trabalho roda. Em
74
+ um notebook isso é tranquilo; em um VPS pequeno ou uma máquina de trabalho
75
+ restrita, nem tanto.
76
+
77
+ **O [cloud.pinepaper.studio](https://cloud.pinepaper.studio) executa o mesmo
78
+ servidor para você** — mesmas ferramentas, mesma versão, por HTTP, sem
79
+ instalação e sem navegador na sua máquina.
80
+
81
+ Hospedagem custa dinheiro, então é paga — funciona por créditos. Os preços
82
+ atuais estão em [cloud.pinepaper.studio](https://cloud.pinepaper.studio). Rode localmente
83
+ se puder, mas não é idêntico: o serviço hospedado usa um conjunto testado de
84
+ LLMs e repara o código gerado antes que ele chegue ao canvas — algo que um
85
+ servidor local não consegue fazer sozinho. Em qual modelo confiar é uma
86
+ pergunta que você mesmo pode responder: um benchmark roda um prompt em vários
87
+ modelos e mostra os resultados lado a lado, com qualquer execução
88
+ compartilhável. Está em beta apenas por convite.
89
+
67
90
  ## Mais
68
91
 
69
92
  A referência completa de ferramentas, toolkits e orçamento de tokens, e a lista de relações estão no [README em inglês](README.md). O fluxo canônico para agentes está no recurso `pinepaper://docs/agent-guide`.
package/README.zh-CN.md CHANGED
@@ -14,7 +14,7 @@
14
14
 
15
15
  PinePaper MCP 服务器让 AI 助手通过 MCP 协议在 [PinePaper Studio](https://pinepaper.studio) 中创建和驱动图形动画。兼容任何支持 MCP 工具调用的 AI(Claude、GPT、Gemini、本地模型等)。
16
16
 
17
- 服务器提供 **135 个工具**,覆盖绘图、动画、图表、地图、排版、物理、图像编辑、数据可视化与导出:
17
+ 服务器提供 **151 个工具**,覆盖绘图、动画、图表、地图、排版、物理、图像编辑、数据可视化与导出:
18
18
 
19
19
  - 创建文本、形状、几何图形与复杂图稿
20
20
  - 用行为驱动的**关系(relations)**做动画,而不是逐帧关键帧
@@ -64,6 +64,25 @@ npm install -g @pinepaper.studio/mcp-server
64
64
  - **`pinepaper_image_filter` 修复并扩充** —— 直连真实 GPU 滤镜引擎,完整 15 种滤镜(半调家族、色调分离、暗角、HSL、抖动等)
65
65
  - **README 成为 MCP 资源** —— 客户端可直接读取 `pinepaper://docs/readme`(含多语言变体)
66
66
 
67
+ ## 本地运行或托管
68
+
69
+ **本地运行免费且功能完整。** 只要你自己运行这个服务器,所有工具都可用,
70
+ 没有功能缩水的版本。
71
+
72
+ 需要:Node 18 或更高版本、约 **320 MB** 磁盘空间(Puppeteer 会下载 Chrome),
73
+ 以及任务运行期间约 1 GB 内存。笔记本电脑没问题,小型 VPS 或受限的办公电脑
74
+ 则未必。
75
+
76
+ **[cloud.pinepaper.studio](https://cloud.pinepaper.studio) 替你运行同一个
77
+ 服务器** —— 相同的工具、相同的版本,通过 HTTP 提供,无需安装,也不需要在你的
78
+ 机器上运行浏览器。
79
+
80
+ 托管需要成本,因此是付费的,按额度(credits)运行。当前价格请见
81
+ [cloud.pinepaper.studio](https://cloud.pinepaper.studio)。能在本地运行就在本地运行,
82
+ 但两者并不完全相同:托管服务使用经过测试的 LLM,并在生成的代码进入画布前
83
+ 进行修复 —— 这是本地服务器自身无法做到的。哪个模型更合适,你可以自己验证:基准测试用同一个提示词在多个模型上运行,
84
+ 并排展示结果,任意一次运行都可分享。目前为邀请制测试版。
85
+
67
86
  ## 更多
68
87
 
69
88
  完整的工具参考、工具包(toolkit)与令牌预算、关系类型列表等,请见 [英文版 README](README.md)。文档也可以在 MCP 协议内读取:资源 `pinepaper://docs/agent-guide` 是为 AI 代理准备的规范工作流。