@pinepaper.studio/mcp-server 1.6.23 → 1.6.25

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 (189) 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 +212 -17
  8. package/README.pt-BR.md +1 -1
  9. package/README.zh-CN.md +1 -1
  10. package/SECURITY.md +46 -0
  11. package/dist/agent/types.d.ts +114 -106
  12. package/dist/agent/types.d.ts.map +1 -1
  13. package/dist/agent/types.js +1 -1
  14. package/dist/agent/types.js.map +1 -1
  15. package/dist/browser/puppeteer-controller.d.ts +6 -0
  16. package/dist/browser/puppeteer-controller.d.ts.map +1 -1
  17. package/dist/browser/puppeteer-controller.js +99 -71
  18. package/dist/browser/puppeteer-controller.js.map +1 -1
  19. package/dist/build-info.json +2 -2
  20. package/dist/cli.js +7 -5
  21. package/dist/cli.js.map +1 -1
  22. package/dist/design/design-systems.js +2 -2
  23. package/dist/design/design-systems.js.map +1 -1
  24. package/dist/i18n/locales/en.js +1 -1
  25. package/dist/index.d.ts +1 -1
  26. package/dist/index.d.ts.map +1 -1
  27. package/dist/index.js +63 -12
  28. package/dist/index.js.map +1 -1
  29. package/dist/mcp/index.d.ts +5 -0
  30. package/dist/mcp/index.d.ts.map +1 -0
  31. package/dist/mcp/index.js +5 -0
  32. package/dist/mcp/index.js.map +1 -0
  33. package/dist/mcp/server.d.ts +86 -0
  34. package/dist/mcp/server.d.ts.map +1 -0
  35. package/dist/mcp/server.js +159 -0
  36. package/dist/mcp/server.js.map +1 -0
  37. package/dist/mcp/stdio.d.ts +20 -0
  38. package/dist/mcp/stdio.d.ts.map +1 -0
  39. package/dist/mcp/stdio.js +82 -0
  40. package/dist/mcp/stdio.js.map +1 -0
  41. package/dist/mcp/types.d.ts +598 -0
  42. package/dist/mcp/types.d.ts.map +1 -0
  43. package/dist/mcp/types.js +140 -0
  44. package/dist/mcp/types.js.map +1 -0
  45. package/dist/metrics/performance-tracker.d.ts.map +1 -1
  46. package/dist/metrics/performance-tracker.js +4 -3
  47. package/dist/metrics/performance-tracker.js.map +1 -1
  48. package/dist/ontology/hints.d.ts.map +1 -1
  49. package/dist/ontology/hints.js +8 -2
  50. package/dist/ontology/hints.js.map +1 -1
  51. package/dist/ontology/upstream-vocabulary.d.ts +2 -2
  52. package/dist/ontology/upstream-vocabulary.d.ts.map +1 -1
  53. package/dist/ontology/upstream-vocabulary.js +8 -2
  54. package/dist/ontology/upstream-vocabulary.js.map +1 -1
  55. package/dist/ontology/vocabulary.d.ts.map +1 -1
  56. package/dist/ontology/vocabulary.js +1 -0
  57. package/dist/ontology/vocabulary.js.map +1 -1
  58. package/dist/server/index.d.ts +1 -1
  59. package/dist/server/index.d.ts.map +1 -1
  60. package/dist/server/index.js +1 -1
  61. package/dist/server/index.js.map +1 -1
  62. package/dist/tools/batch-macros.d.ts +27 -0
  63. package/dist/tools/batch-macros.d.ts.map +1 -0
  64. package/dist/tools/batch-macros.js +158 -0
  65. package/dist/tools/batch-macros.js.map +1 -0
  66. package/dist/tools/choreograph.d.ts.map +1 -1
  67. package/dist/tools/choreograph.js +2 -0
  68. package/dist/tools/choreograph.js.map +1 -1
  69. package/dist/tools/compact-descriptions.d.ts.map +1 -1
  70. package/dist/tools/compact-descriptions.js +8 -7
  71. package/dist/tools/compact-descriptions.js.map +1 -1
  72. package/dist/tools/craft-tools.d.ts +1 -1
  73. package/dist/tools/craft-tools.d.ts.map +1 -1
  74. package/dist/tools/create-known-keys.d.ts +2 -0
  75. package/dist/tools/create-known-keys.d.ts.map +1 -0
  76. package/dist/tools/create-known-keys.js +24 -0
  77. package/dist/tools/create-known-keys.js.map +1 -0
  78. package/dist/tools/definitions.d.ts +3 -1
  79. package/dist/tools/definitions.d.ts.map +1 -1
  80. package/dist/tools/definitions.js +122 -19
  81. package/dist/tools/definitions.js.map +1 -1
  82. package/dist/tools/effect-check.d.ts +1 -1
  83. package/dist/tools/effect-check.d.ts.map +1 -1
  84. package/dist/tools/effect-check.js +4 -0
  85. package/dist/tools/effect-check.js.map +1 -1
  86. package/dist/tools/engine-lists.d.ts +5 -2
  87. package/dist/tools/engine-lists.d.ts.map +1 -1
  88. package/dist/tools/engine-lists.js +10 -2
  89. package/dist/tools/engine-lists.js.map +1 -1
  90. package/dist/tools/engine-methods.d.ts.map +1 -1
  91. package/dist/tools/engine-methods.js +2 -0
  92. package/dist/tools/engine-methods.js.map +1 -1
  93. package/dist/tools/engine-surface.d.ts +1 -1
  94. package/dist/tools/engine-surface.d.ts.map +1 -1
  95. package/dist/tools/engine-surface.js +67 -6
  96. package/dist/tools/engine-surface.js.map +1 -1
  97. package/dist/tools/export-file-check.d.ts +31 -0
  98. package/dist/tools/export-file-check.d.ts.map +1 -0
  99. package/dist/tools/export-file-check.js +103 -0
  100. package/dist/tools/export-file-check.js.map +1 -0
  101. package/dist/tools/export-file-receipt.d.ts +68 -0
  102. package/dist/tools/export-file-receipt.d.ts.map +1 -0
  103. package/dist/tools/export-file-receipt.js +171 -0
  104. package/dist/tools/export-file-receipt.js.map +1 -0
  105. package/dist/tools/handlers/beats.d.ts +8 -45
  106. package/dist/tools/handlers/beats.d.ts.map +1 -1
  107. package/dist/tools/handlers/camera.d.ts +1 -1
  108. package/dist/tools/handlers/camera.d.ts.map +1 -1
  109. package/dist/tools/handlers/export.d.ts +1 -1
  110. package/dist/tools/handlers/export.d.ts.map +1 -1
  111. package/dist/tools/handlers/export.js +34 -8
  112. package/dist/tools/handlers/export.js.map +1 -1
  113. package/dist/tools/handlers/font.d.ts +1 -1
  114. package/dist/tools/handlers/font.d.ts.map +1 -1
  115. package/dist/tools/handlers/font.js +8 -7
  116. package/dist/tools/handlers/font.js.map +1 -1
  117. package/dist/tools/handlers/generate.d.ts +42 -271
  118. package/dist/tools/handlers/generate.d.ts.map +1 -1
  119. package/dist/tools/handlers/generate.js +4 -3
  120. package/dist/tools/handlers/generate.js.map +1 -1
  121. package/dist/tools/handlers/maps.d.ts +1 -1
  122. package/dist/tools/handlers/maps.d.ts.map +1 -1
  123. package/dist/tools/handlers/ontology.d.ts +1 -1
  124. package/dist/tools/handlers/ontology.d.ts.map +1 -1
  125. package/dist/tools/handlers/tool-guide.d.ts +1 -1
  126. package/dist/tools/handlers/tool-guide.d.ts.map +1 -1
  127. package/dist/tools/handlers.d.ts +82 -4
  128. package/dist/tools/handlers.d.ts.map +1 -1
  129. package/dist/tools/handlers.js +366 -89
  130. package/dist/tools/handlers.js.map +1 -1
  131. package/dist/tools/lane.d.ts +39 -0
  132. package/dist/tools/lane.d.ts.map +1 -0
  133. package/dist/tools/lane.js +247 -0
  134. package/dist/tools/lane.js.map +1 -0
  135. package/dist/tools/minimal-descriptions.d.ts.map +1 -1
  136. package/dist/tools/minimal-descriptions.js +3 -2
  137. package/dist/tools/minimal-descriptions.js.map +1 -1
  138. package/dist/tools/nested-ignored.d.ts +16 -0
  139. package/dist/tools/nested-ignored.d.ts.map +1 -0
  140. package/dist/tools/nested-ignored.js +83 -0
  141. package/dist/tools/nested-ignored.js.map +1 -0
  142. package/dist/tools/p5-compat/p5-helpers.d.ts +1 -1
  143. package/dist/tools/p5-compat/p5-helpers.js +1 -1
  144. package/dist/tools/shape-params.d.ts +2 -2
  145. package/dist/tools/shape-params.d.ts.map +1 -1
  146. package/dist/tools/shape-params.js +15 -2
  147. package/dist/tools/shape-params.js.map +1 -1
  148. package/dist/tools/stick-vocabulary.d.ts +4 -4
  149. package/dist/tools/stick-vocabulary.d.ts.map +1 -1
  150. package/dist/tools/stick-vocabulary.js +8 -4
  151. package/dist/tools/stick-vocabulary.js.map +1 -1
  152. package/dist/tools/timeline.d.ts +136 -0
  153. package/dist/tools/timeline.d.ts.map +1 -0
  154. package/dist/tools/timeline.js +1041 -0
  155. package/dist/tools/timeline.js.map +1 -0
  156. package/dist/tools/toolkits.d.ts +22 -7
  157. package/dist/tools/toolkits.d.ts.map +1 -1
  158. package/dist/tools/toolkits.js +113 -21
  159. package/dist/tools/toolkits.js.map +1 -1
  160. package/dist/types/code-generator.d.ts +55 -2
  161. package/dist/types/code-generator.d.ts.map +1 -1
  162. package/dist/types/code-generator.js +671 -202
  163. package/dist/types/code-generator.js.map +1 -1
  164. package/dist/types/schemas.d.ts +5281 -25048
  165. package/dist/types/schemas.d.ts.map +1 -1
  166. package/dist/types/schemas.js +81 -41
  167. package/dist/types/schemas.js.map +1 -1
  168. package/dist/utils/asset-paths.d.ts.map +1 -1
  169. package/dist/utils/asset-paths.js +4 -4
  170. package/dist/utils/asset-paths.js.map +1 -1
  171. package/dist/utils/env.d.ts +9 -0
  172. package/dist/utils/env.d.ts.map +1 -0
  173. package/dist/utils/env.js +11 -0
  174. package/dist/utils/env.js.map +1 -0
  175. package/dist/utils/export-dir.d.ts +36 -0
  176. package/dist/utils/export-dir.d.ts.map +1 -0
  177. package/dist/utils/export-dir.js +86 -0
  178. package/dist/utils/export-dir.js.map +1 -0
  179. package/dist/utils/js-literal.d.ts +4 -0
  180. package/dist/utils/js-literal.d.ts.map +1 -0
  181. package/dist/utils/js-literal.js +25 -0
  182. package/dist/utils/js-literal.js.map +1 -0
  183. package/dist/utils/mcp-log.d.ts +1 -1
  184. package/dist/utils/mcp-log.d.ts.map +1 -1
  185. package/dist/version.d.ts.map +1 -1
  186. package/dist/version.js +5 -12
  187. package/dist/version.js.map +1 -1
  188. package/manifest.json +46 -63
  189. package/package.json +15 -12
@@ -22,7 +22,7 @@ export const COMPACT_DESCRIPTIONS = {
22
22
  pinepaper_set_background_color: `Set the canvas background color. Pass a hex color string (e.g. "#0f172a").`,
23
23
  pinepaper_set_canvas_size: `Set canvas dimensions: width+height, or a studio preset key alone — instagram-post (1080x1080), instagram-story / tiktok (1080x1920), youtube-thumbnail (1280x720), full-hd-1080p (1920x1080), twitter-post (1200x675). Platform names (instagram, youtube) are not preset keys; an unknown key is refused with the list.`,
24
24
  pinepaper_get_canvas_size: `Get current canvas width and height.`,
25
- pinepaper_clear_canvas: `Remove all items from the canvas.`,
25
+ pinepaper_clear_canvas: `Remove all items from the canvas. Item ids start again at item_1.`,
26
26
  pinepaper_refresh_page: `Reload the PinePaper browser page for a clean start.`,
27
27
  pinepaper_browser_connect: `Connect to PinePaper Studio. Pass headless: false to show the browser window.`,
28
28
  pinepaper_browser_disconnect: `Disconnect from the browser.`,
@@ -34,20 +34,20 @@ Pass description for creative direction and canvasPreset for platform sizing. WO
34
34
  pinepaper_agent_end_job: `Finish the current job and get a screenshot. Show it to the user.`,
35
35
  pinepaper_agent_reset: `Quick canvas reset. Faster than refresh_page.`,
36
36
  pinepaper_agent_analyze: `Analyze what's on the canvas and get export recommendations.`,
37
- pinepaper_tool_guide: `Get detailed docs for any tool or category. Call with no args for the full workflow guide.`,
38
- pinepaper_set_toolkit: `Switch available tools. Toolkits: agent, diagram, map, font, full, minimal. Verbosity: verbose, compact, minimal.`,
37
+ pinepaper_tool_guide: `Get detailed docs for any tool or category. Call with no args for the full workflow guide. For a scripted build of shapes, text, keyframes and relations exported to a file, PINEPAPER_TOOLKIT=lane serves a seven-tool agent lane whose descriptions carry the whole contract.`,
38
+ pinepaper_set_toolkit: `Switch available tools. Toolkits: agent, diagram, map, font, full, minimal, lane (the seven-tool agent lane). Verbosity: verbose, compact, minimal.`,
39
39
  // -------------------------------------------------------------------------
40
40
  // batch_execute
41
41
  // -------------------------------------------------------------------------
42
42
  pinepaper_agent_batch_execute: `Execute multiple operations in a single call — canvas setup, items, animations, effects, playback. Call ONCE per pipeline — calling twice doubles all items. This is the GLUE: a styled scene, a character, a story or a crafted title has its own tool (styled_scene, character, story, text_style), called first; shapes over a generator backdrop is the stock look.
43
43
 
44
- OPERATION TYPES (${AgentBatchOperationTypeSchema.options.length}): ${AgentBatchOperationTypeSchema.options.join(', ')}. create takes position {x, y} or [x, y].
44
+ OPERATION TYPES (${AgentBatchOperationTypeSchema.options.length}): ${AgentBatchOperationTypeSchema.options.join(', ')}. create takes position {x, y} or [x, y]. timeline takes GSAP-shaped tweens {to, vars, from, duration, at, stagger, ease, repeat, yoyo} and compiles them onto keyframe tracks (x/y are offsets from home).
45
45
 
46
- VARIABLE REFERENCES: "$0", "$1" etc. reference items by creation order within the batch.`,
46
+ VARIABLE REFERENCES: "$0", "$1" etc. reference the items this batch makes, in op order: create and group ops are numbered, nothing else. properties.id on a create chooses the item's id.`,
47
47
  // -------------------------------------------------------------------------
48
48
  // create_item
49
49
  // -------------------------------------------------------------------------
50
- pinepaper_create_item: `Create a text, shape, or graphic on the canvas. Returns an itemId for later reference.
50
+ pinepaper_create_item: `Create a text, shape, or graphic on the canvas. Returns an itemId for later reference; properties.id chooses it ("sun"), so replays address the same ids. A closed shape with a strokeColor and no fill is an outline.
51
51
 
52
52
  ITEM TYPES: ${ITEM_TYPES}.
53
53
  STYLING: gradients (color object with stops), shadows, blend modes, opacity. See inputSchema for properties.`,
@@ -81,7 +81,8 @@ GENERATORS (${GeneratorNameSchema.options.length}): ${GENERATORS}.`,
81
81
  // -------------------------------------------------------------------------
82
82
  pinepaper_add_relation: `Add a behavior relation between two items (orbits, follows, attached_to, etc.). Relations are compositional — an item can have multiple.
83
83
 
84
- RELATION TYPES: ${RELATION_TYPES}. A name registered with pinepaper_register_custom_relation this session is accepted too.`,
84
+ RELATION TYPES: ${RELATION_TYPES}. A name registered with pinepaper_register_custom_relation this session is accepted too.
85
+ UNITS: orbits speed is revolutions per second (0.5 = one turn every 2 s); angles are degrees.`,
85
86
  // -------------------------------------------------------------------------
86
87
  // create_diagram_shape
87
88
  // -------------------------------------------------------------------------
@@ -1 +1 @@
1
- {"version":3,"file":"compact-descriptions.js","sourceRoot":"","sources":["../../src/tools/compact-descriptions.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"compact-descriptions.js","sourceRoot":"","sources":["../../src/tools/compact-descriptions.ts"],"names":[],"mappings":"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"}
@@ -26,7 +26,7 @@
26
26
  * brand of its own — the cloud does the same from the scene's brand_kit op
27
27
  * (ui-kit-attach.ts).
28
28
  */
29
- import type { Tool } from '@modelcontextprotocol/sdk/types.js';
29
+ import type { Tool } from '../mcp/index.js';
30
30
  import type { DrawWeaveInput, DrawKnotsInput, DrawSashikoInput, DrawSubdivisionInput, UiKitInput } from '../types/schemas.js';
31
31
  export declare const CRAFT_TOOL_NAMES: readonly ["pinepaper_draw_weave", "pinepaper_draw_knots", "pinepaper_draw_sashiko", "pinepaper_draw_subdivision", "pinepaper_ui_kit"];
32
32
  export interface CraftBounds {
@@ -1 +1 @@
1
- {"version":3,"file":"craft-tools.d.ts","sourceRoot":"","sources":["../../src/tools/craft-tools.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,oCAAoC,CAAC;AAQ/D,OAAO,KAAK,EACV,cAAc,EACd,cAAc,EACd,gBAAgB,EAChB,oBAAoB,EACpB,UAAU,EACX,MAAM,qBAAqB,CAAC;AAE7B,eAAO,MAAM,gBAAgB,uIAMnB,CAAC;AAEX,MAAM,WAAW,WAAW;IAAG,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE;AAoCpF,gEAAgE;AAChE,wBAAgB,oBAAoB,IAAI,IAAI,EAAE,CAsB7C;AAED,4EAA4E;AAC5E,eAAO,MAAM,cAAc,QAEiF,CAAC;AAE7G,sFAAsF;AACtF,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEhD;AASD,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,cAAc,EAAE,KAAK,CAAC,EAAE,WAAW,GAAG,MAAM,CAGpF;AAED,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,cAAc,GAAG,MAAM,CAE/D;AAED,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,gBAAgB,EAAE,KAAK,CAAC,EAAE,WAAW,GAAG,MAAM,CAGxF;AAED,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,oBAAoB,EAAE,KAAK,CAAC,EAAE,WAAW,GAAG,MAAM,CAGhG;AAED,gFAAgF;AAChF,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,UAAU,GAAG,MAAM,EAAE,CAE7D;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,UAAU,GAAG,MAAM,GAAG,IAAI,CA8B9D"}
1
+ {"version":3,"file":"craft-tools.d.ts","sourceRoot":"","sources":["../../src/tools/craft-tools.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,iBAAiB,CAAC;AAQ5C,OAAO,KAAK,EACV,cAAc,EACd,cAAc,EACd,gBAAgB,EAChB,oBAAoB,EACpB,UAAU,EACX,MAAM,qBAAqB,CAAC;AAE7B,eAAO,MAAM,gBAAgB,uIAMnB,CAAC;AAEX,MAAM,WAAW,WAAW;IAAG,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE;AAoCpF,gEAAgE;AAChE,wBAAgB,oBAAoB,IAAI,IAAI,EAAE,CAsB7C;AAED,4EAA4E;AAC5E,eAAO,MAAM,cAAc,QAEiF,CAAC;AAE7G,sFAAsF;AACtF,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEhD;AASD,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,cAAc,EAAE,KAAK,CAAC,EAAE,WAAW,GAAG,MAAM,CAGpF;AAED,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,cAAc,GAAG,MAAM,CAE/D;AAED,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,gBAAgB,EAAE,KAAK,CAAC,EAAE,WAAW,GAAG,MAAM,CAGxF;AAED,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,oBAAoB,EAAE,KAAK,CAAC,EAAE,WAAW,GAAG,MAAM,CAGhG;AAED,gFAAgF;AAChF,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,UAAU,GAAG,MAAM,EAAE,CAE7D;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,UAAU,GAAG,MAAM,GAAG,IAAI,CA8B9D"}
@@ -0,0 +1,2 @@
1
+ export declare const CREATE_KNOWN_KEYS: ReadonlySet<string>;
2
+ //# sourceMappingURL=create-known-keys.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"create-known-keys.d.ts","sourceRoot":"","sources":["../../src/tools/create-known-keys.ts"],"names":[],"mappings":"AAWA,eAAO,MAAM,iBAAiB,EAAE,WAAW,CAAC,MAAM,CAYhD,CAAC"}
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Every `properties` key create_item can act on: what the engine's create()
3
+ * and normalizeParams() read (generated — see shape-params.ts), plus the keys
4
+ * generateCreateItemCode consumes itself before the engine sees them.
5
+ *
6
+ * One set, read by the create emitter (which reports the rest as ignored) and
7
+ * by the batch typo preflight (which must not call a key it acts on a typo:
8
+ * `ttl` on a line was "did you mean to?", issue #29 O8).
9
+ */
10
+ import { ACCEPTED_CREATE_PARAMS, NORMALIZE_PARAM_READS } from './shape-params.js';
11
+ export const CREATE_KNOWN_KEYS = new Set([
12
+ ...ACCEPTED_CREATE_PARAMS,
13
+ ...NORMALIZE_PARAM_READS,
14
+ // withRadiusAxes, gradients / shadow / blend / opacity emitted here, and
15
+ // setDynamicContent for text.
16
+ 'radiusX', 'radiusY', 'contentType', 'contentFormat', 'countdownTarget', 'countdownEndText',
17
+ // Lifetimes, on ANY item: this generator applies them through app.setLifetime
18
+ // (emitLifetime), whatever create() itself reads.
19
+ 'bornAt', 'ttl',
20
+ // A solid fill's own alpha (FxTool 12 STROKEFILL); confirmed per call by
21
+ // emitFillOpacityCheck, since an older studio ignores it.
22
+ 'fillOpacity',
23
+ ]);
24
+ //# sourceMappingURL=create-known-keys.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"create-known-keys.js","sourceRoot":"","sources":["../../src/tools/create-known-keys.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,EAAE,sBAAsB,EAAE,qBAAqB,EAAE,MAAM,mBAAmB,CAAC;AAElF,MAAM,CAAC,MAAM,iBAAiB,GAAwB,IAAI,GAAG,CAAC;IAC5D,GAAG,sBAAsB;IACzB,GAAG,qBAAqB;IACxB,yEAAyE;IACzE,8BAA8B;IAC9B,SAAS,EAAE,SAAS,EAAE,aAAa,EAAE,eAAe,EAAE,iBAAiB,EAAE,kBAAkB;IAC3F,8EAA8E;IAC9E,kDAAkD;IAClD,QAAQ,EAAE,KAAK;IACf,yEAAyE;IACzE,0DAA0D;IAC1D,aAAa;CACd,CAAC,CAAC"}
@@ -7,7 +7,7 @@
7
7
  * Note: Tool descriptions remain in English for optimal AI/LLM understanding.
8
8
  * User-facing messages (errors, success) are translated via i18n.
9
9
  */
10
- import { Tool } from '@modelcontextprotocol/sdk/types.js';
10
+ import { Tool } from '../mcp/index.js';
11
11
  import { I18nManager } from '../i18n/index.js';
12
12
  /**
13
13
  * The door block for a host's tool list (D72; cloud request from a3). A host
@@ -18,6 +18,8 @@ import { I18nManager } from '../i18n/index.js';
18
18
  export declare function buildDoorBlock(available?: Iterable<string>): string;
19
19
  /** The full door block (every tool), for the guide and a local server. */
20
20
  export declare const CHOOSE_THE_DOOR: string;
21
+ /** The tools the door table sends a model to (the core profile's `craft` seed is held equal to this). */
22
+ export declare const DOOR_TOOLS: readonly string[];
21
23
  export declare const AI_AGENT_GUIDE: string;
22
24
  export declare const PINEPAPER_TOOLS: Tool[];
23
25
  /**
@@ -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;AAmE/C;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,SAAS,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,GAAG,MAAM,CAYnE;AAED,0EAA0E;AAC1E,eAAO,MAAM,eAAe,QAAmB,CAAC;AAEhD,eAAO,MAAM,cAAc,QA4K+G,CAAC;AAW3I,eAAO,MAAM,eAAe,EAAE,IAAI,EAi9SjC,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,iBAAiB,CAAC;AACvC,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAoE/C;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,SAAS,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,GAAG,MAAM,CAYnE;AAED,0EAA0E;AAC1E,eAAO,MAAM,eAAe,QAAmB,CAAC;AAEhD,yGAAyG;AACzG,eAAO,MAAM,UAAU,EAAE,SAAS,MAAM,EAAmG,CAAC;AAE5I,eAAO,MAAM,cAAc,QA8K+G,CAAC;AAW3I,eAAO,MAAM,eAAe,EAAE,IAAI,EAmjTjC,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"}
@@ -10,9 +10,10 @@
10
10
  import { COMPACT_DESCRIPTIONS } from './compact-descriptions.js';
11
11
  import { MINIMAL_DESCRIPTIONS } from './minimal-descriptions.js';
12
12
  import { craftToolDefinitions } from './craft-tools.js';
13
+ import { TOOL_TAGS } from './toolkits.js';
13
14
  import { STICK_GAITS, STICK_POSES, STICK_SEQUENCES, STICK_EXPRESSIONS, STICK_PROPS } from './stick-vocabulary.js';
14
15
  import { AgentBatchOperationTypeSchema, GeneratorNameSchema, ItemTypeSchema } from '../types/schemas.js';
15
- import { DESIGN_MEDIA, DESIGN_MEDIA_APPLY, FILTER_TYPES, FILTER_DOCS, LINEAGE_KINDS, STYLED_SCENE_STYLES, STYLED_SCENE_STYLE_INFO } from './engine-lists.js';
16
+ import { DESIGN_MEDIA, DESIGN_MEDIA_APPLY, FILTER_TYPES, FILTER_DOCS, LINEAGE_KINDS, STYLED_SCENE_STYLES, STYLED_SCENE_STYLE_INFO, PATTERN_KINDS } from './engine-lists.js';
16
17
  import { EffectTypeSchema, AgentExportFormatSchema, RelationTypeSchema, SimpleAnimationTypeSchema, EasingSchema, KEYFRAME_EASINGS, EASING_DESCRIPTIONS, KEYFRAME_EASING_JSON_SCHEMA, GEOMETRY_OPERATIONS, THREAD_STITCHES, } from '../types/schemas.js';
17
18
  /**
18
19
  * Vocabulary lists derived from Zod schemas so tool descriptions stay in
@@ -66,6 +67,8 @@ export function buildDoorBlock(available) {
66
67
  }
67
68
  /** The full door block (every tool), for the guide and a local server. */
68
69
  export const CHOOSE_THE_DOOR = buildDoorBlock();
70
+ /** The tools the door table sends a model to (the core profile's `craft` seed is held equal to this). */
71
+ export const DOOR_TOOLS = [...new Set(DOORS.flatMap((d) => d.doors.map((x) => x.tool).filter((t) => !!t)))];
69
72
  export const AI_AGENT_GUIDE = `⚠️ You are connected to PinePaper Studio via MCP tools. ALWAYS use these tools to create visual content.
70
73
  NEVER create standalone HTML pages, React components, or web apps as a substitute. Do NOT use frontend design skills or CSS-only animations instead of PinePaper.
71
74
  PinePaper tools ARE the implementation — they generate Paper.js/JavaScript code that runs on the canvas and produce Canvas 2D, SVG, MP4, GIF, PNG exports.
@@ -81,6 +84,8 @@ The generated code is shown in tool responses and can be copied into PinePaper's
81
84
 
82
85
  ${CHOOSE_THE_DOOR}
83
86
 
87
+ THE AGENT LANE — when the job is a scene of shapes, text, keyframes and relations exported to a file (a data animation, a title card, a motion test), and no craft tool above is wanted: PINEPAPER_TOOLKIT=lane (or pinepaper_set_toolkit {toolkit: "lane"}) serves seven tools — pinepaper_agent_batch_execute, pinepaper_keyframe_animate, pinepaper_pattern, pinepaper_agent_export, pinepaper_lint_scene, pinepaper_event (timed and clicked events), pinepaper_clear_canvas (start over) — whose descriptions carry the rules that otherwise cost a failed build (the keyframe shape, an item's words and look inside properties, position is the centre). The whole contract is under 10k tokens. Use the full surface for characters, styled scenes, maps, diagrams and sound.
88
+
84
89
  WORKFLOW — Create → Validate → Iterate:
85
90
 
86
91
  1. pinepaper_agent_start_job (clearCanvas: true, canvasPreset)
@@ -102,7 +107,7 @@ RULES:
102
107
  - Primitive operations go in the ONE batch_execute — canvas, background, items, animation, masks, effects, playback
103
108
  - EXCEPTION: Diagrams (flowcharts, UML) use pinepaper_create_diagram_shape + pinepaper_connect, NOT batch_execute
104
109
  - A generator is a BACKDROP: under a composed scene it adds texture; on its own it is the stock look. Prefer a styled scene, a drawn world or a real photo for the ground of a piece
105
- - Use "$0", "$1" to reference items by creation order within the batch
110
+ - Use "$0", "$1" to reference the items a batch makes, in op order (create and group ops are numbered)
106
111
 
107
112
  ─── BATCH OPERATIONS (${AgentBatchOperationTypeSchema.options.length} types, in order) ───
108
113
 
@@ -355,6 +360,7 @@ IMPORTANT NOTES:
355
360
  - This removes ALL items from the canvas permanently
356
361
  - The welcome template (shown to first-time visitors) will be cleared
357
362
  - After clearing, use pinepaper_get_items to verify the canvas is empty
363
+ - Item ids start again at item_1 (one past any id still on the canvas), so a batch replayed after a clear gets the same ids
358
364
  - If items persist after clearing, try pinepaper_refresh_page instead`,
359
365
  inputSchema: {
360
366
  type: 'object',
@@ -420,6 +426,8 @@ USE WHEN:
420
426
 
421
427
  IMPORTANT:
422
428
  - Save the returned itemId! You need it for pinepaper_add_relation, pinepaper_modify_item, pinepaper_delete_item, etc.
429
+ - properties.id chooses the itemId yourself ("sun", "title"): the same call names the same item on every run, so a replay after pinepaper_clear_canvas addresses the same ids. An id a live item already holds gets a suffix ("sun_2"); the returned itemId is always the one to use. Letters, digits, spaces, - and _: an id with a quote, backslash or line break is refused. Without it, ids are item_1, item_2, … and start again at item_1 after a clear.
430
+ - A closed shape with a strokeColor and no fill (fillColor, color) is an OUTLINE; name a fillColor to fill it.
423
431
  - If there's a welcome template on the canvas, use pinepaper_clear_canvas first
424
432
  - Position defaults to canvas center (400, 300). Use position: {x, y} or [x, y] (both forms accepted) to place elsewhere. Position is the item's bounding-box CENTRE, not its top-left corner.
425
433
  - ROTATION is a property, at creation: properties: { rotation: 45 } — degrees, clockwise, about the item's own centre. It does not need a second call, and pinepaper_update_item takes the same property afterwards; keyframe_animate and the driven_by relation both animate it. A radial figure — a sunburst of thin triangles, a clock face, a compass rose — is N creates at rotation: i * (360/N), which is what pinepaper_agent_batch_execute is for. Nothing here needs to be faked with arcs or chevrons.
@@ -1178,6 +1186,7 @@ Use maxWidth/maxHeight to constrain the image dimensions while preserving aspect
1178
1186
  - nativeSize: true places the image at its source footprint even if it was stored smaller.
1179
1187
  - smoothing: 'off' (nearest-neighbour, for pixel art) | 'low' (default) | 'medium' | 'high'.
1180
1188
  - shadowColor / shadowBlur / shadowOffset: a drop shadow on the placed image, the same keys pinepaper_modify_item takes.
1189
+ - name: a name for the image, so a batch patch or any tool that takes an item can address it by name instead of its id.
1181
1190
 
1182
1191
  EXAMPLES:
1183
1192
  - Import photo: url: "https://example.com/photo.jpg"
@@ -1208,6 +1217,7 @@ EXAMPLES:
1208
1217
  },
1209
1218
  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." },
1210
1219
  nativeSize: { type: 'boolean', description: 'Place the image at its source footprint even if it was stored smaller.' },
1220
+ name: { type: 'string', description: 'A name for the image, so a batch patch (or any tool that takes an item) can address it by name instead of its id.' },
1211
1221
  mask: {
1212
1222
  type: 'string',
1213
1223
  enum: ['circle', 'rounded', 'hexagon', 'star'],
@@ -2346,7 +2356,7 @@ ACTIONS:
2346
2356
  - set_font_axes: { itemId, axes: { weight?, width?, slant? } } — STANDARD variable-font axes only (Canvas 2D has no font-variation-settings, so custom foundry axes are unreachable — platform limit, stated, not silent). Returns {applied, rejected}: CHECK rejected — an axis silently ignored is the failure this surface exists to prevent. All three are ordinary animatable properties: keyframe fontWeight and type breathes between weights.
2347
2357
  - list_styles: {} — styles + palettes + axes, for pickers. Call this first; styleKey strings come from here.
2348
2358
  - list: {} — the same as list_styles.
2349
- - cursive: { text, cursiveOptions?: { x?, y?, scale? (1), strokeColor? ('#ffffff'), strokeWidth? (2), nib? ('monoline' | 'broad' | {angle?, width?, contrast?, taper?}), animate? (false), duration? (2), easing? ('easeOut'), timeOffset? (0), singleStroke?, showGhost?, tension? } } → { itemId, strokes, width } — writes the words as STROKED handwriting, a path rather than a glyph. animate: true writes it on by itself over duration seconds (from timeOffset), no keyframes needed; otherwise pinepaper_animate's draw-on applies to it. Unknown cursiveOptions keys are refused.
2359
+ - cursive: { text, cursiveOptions?: { x?, y?, scale? (1), strokeColor? ('#ffffff'), strokeWidth? (2), nib? ('monoline' | 'broad' | {angle?, width?, contrast?, taper?}), animate? (false), duration? (2), easing? ('easeOut'), timeOffset? (0), singleStroke?, showGhost?, tension? } } → { itemId, strokes, width } — writes the words as STROKED handwriting, a path rather than a glyph. x, y is where the pen STARTS (the left end of the first letter), not the centre: to centre a word, set x to the centre minus half its width (the returned width; about 125 × scale px for nine letters). showGhost adds a faint full-word outline under the write-on; it does not move the word. animate: true writes it on by itself over duration seconds (from timeOffset), no keyframes needed; otherwise pinepaper_animate's draw-on applies to it. Unknown cursiveOptions keys are refused.
2350
2360
  - wrap: { itemId, maxWidth } — breaks a text item into lines no wider than maxWidth (canvas units). unwrap: { itemId } — restores the single line; wrap is not destructive.
2351
2361
  - to_collage: { itemId, text?, collageOptions? } — rebuilds a text item as a letter collage (same vocabulary as pinepaper_create_letter_collage); text defaults to the item's content.
2352
2362
 
@@ -3464,7 +3474,7 @@ USE WHEN:
3464
3474
  - Building live geometric constructions (GeoGebra-style — dragging an anchor updates the dependent)
3465
3475
 
3466
3476
  RELATION TYPES:
3467
- - orbits: Circular motion around target (params: radius, speed, direction, phaseDegrees). Use phaseDegrees. 'phase' is the one parameter in the whole relation vocabulary measured in RADIANS — the documented exception to "angles are DEGREES", kept only for scenes that already set it. phaseDegrees wins when both are given.
3477
+ - orbits: Circular motion around target (params: radius, speed, direction, phaseDegrees). speed is REVOLUTIONS PER SECOND: 0.5 is one turn every 2 s, 0.1 one turn every 10 s (not radians, not a period). Use phaseDegrees. 'phase' is the one parameter in the whole relation vocabulary measured in RADIANS — the documented exception to "angles are DEGREES", kept only for scenes that already set it. phaseDegrees wins when both are given.
3468
3478
  - follows: Move toward target with smoothing (params: offset, smoothing, delay)
3469
3479
  - attached_to: Fixed offset from target (params: offset, inherit_rotation)
3470
3480
  - maintains_distance: Stay fixed distance from target (params: distance, strength)
@@ -3489,12 +3499,13 @@ INTERACTIVE RELATIONS — the state machine lives in the graph.
3489
3499
  An event channel (pinepaper_event) is the hub: something FIRES it, and reactions bound to it run. Nothing here is a callback; it is all queryable graph, so it scrubs, exports and survives a reload.
3490
3500
 
3491
3501
  - Input triggers (item → event): on_click_fire, on_pointer_enter_fire, on_pointer_exit_fire, on_key_fire (params: key, modifiers, global, preventDefault). { key: 'Enter' } makes Enter activate a button exactly as a click does. The chord is matched EXACTLY in both directions — { key: 'Enter' } does NOT fire on Ctrl+Enter, and { key: 's' } does not steal the browser's Ctrl+S; ask for a modifier with modifiers: { ctrl: true }. Listens only while the source item has focus unless global: true, so it will not take keys from the rest of the page.
3492
- - Event reactions (event → item), params in common: property, value, key, by, color, template, delay, timeline.
3493
- · on_event_set_property / _set_color / _set_visibility / _set_data — write a value.
3502
+ - Event reactions (event → item). Each reads its own params:
3503
+ · on_event_set_property { property, value } / _set_color { color, which } / _set_data { property, value } (into item.data) — write a value.
3504
+ · on_event_set_visibility { visible } — true shows, false hides (value is not read, and is refused).
3494
3505
  · on_event_set_property_from_template — write a value built from a '{token}' TEMPLATE read off item.data, so the text can quote live state ("Score: {score}") instead of a literal fixed when you authored it.
3495
3506
  · on_event_increment (params: property, by) / on_event_toggle — counters and flip-flops.
3496
3507
  · on_event_fire_after (params: delay, timeline) — chain one beat to the next.
3497
- · on_event_fire_if — the only reaction that TESTS graph state rather than mutating it; params.predicate is an ExpressionIR program.
3508
+ · on_event_fire_if (params: predicate, event, else?) — the only reaction that TESTS graph state rather than mutating it. When the source fires it evaluates params.predicate and pulses the EVENT params.event if it holds (params.else if not); its target is not fired, so the visible change comes from a reaction on that second event. params.predicate is an ExpressionIR object, not a string: { op:'const', value } · { op:'cmp', cmp: eq|neq|gt|gte|lt|lte, a, b } · { op:'logic', logic: and|or|not, args:[…] } · { op:'graph', read: data|active|visible, item, property } (data reads item.data[property]). A string predicate, or no event, is refused.
3498
3509
  · on_event_add_relation / on_event_remove_relation — the scene rewires itself.
3499
3510
  · on_event_play_sound (source = the EVENT, target null; params: sound, gain?, note?) — play a sound when the event fires: a catalogue name (effect, drum or instrument; aliases accepted) or a define_sfx spec; gain is a multiplier capped at full scale; note is for instruments (default C5). An unknown sound is refused with the catalogue. Wire a click sound as on_click_fire (button → event) + on_event_play_sound (event → null). For a sound at a TIME, pinepaper_event create { at: seconds | [seconds] } fires the event on the timeline (and in video exports); a scene chain's cutSound puts one on every cut. LIMITS: the exported widget player does not run timed triggers, and a browser may block sound until the viewer's first click or key.
3500
3511
  · on_event_store_set / on_event_store_increment / restores_from — persistent state. The target is a store node whose id is the storage SCOPE, so two stores in a scene and two widgets on a page do not collide. restores_from is the read half and fires ONCE at load.
@@ -3528,11 +3539,12 @@ PROCEDURAL / DETERMINISTIC BINDING (Expression IR — S10 G1) — bind a propert
3528
3539
 
3529
3540
  EVENT-DRIVEN SCENE CHAINS (S11) — build a LONG scene as a graph of timed events, not a keyframe track. First make events with pinepaper_event (action:'create' → eventId). The relations below have an EVENT as their sourceId; firing the event runs the reaction. Chain beats over animation time with on_event_fire_after (timeline:'canvas'), have beats mutate the scene with on_event_add_relation, then kick it off with pinepaper_event action:'pulse'. Because canvas-timed fires are on the animation clock, the whole chain is scrub-, loop-, and replay-stable.
3530
3541
  - on_event_fire_after: sourceId=event, targetId=the NEXT event. When source fires, pulse target after params.delay ms. params.timeline: 'canvas' (animation clock — use for scene chains) | 'wall' (real setTimeout). This is the chaining primitive.
3542
+ - on_event_fire_if: sourceId=event, targetId=any item (it is not fired). params.event = the event to pulse when params.predicate holds, params.else = the one when it does not. A branch is two relations: A —on_event_fire_if { predicate, event: B }→ any item; B —on_event_set_color→ lamp. Example predicate, "score is at least 3": { op:'cmp', cmp:'gte', a:{ op:'graph', read:'data', item:'item_3', property:'score' }, b:{ op:'const', value:3 } }.
3531
3543
  - on_event_add_relation: sourceId=event, targetId=the item to affect. When the event fires, ADD a relation FROM that item: params { type (relation type, e.g. orbits/moves_along_path/driven_by), target (id or null for self), params (that relation's params) }. The scene evolves itself — new orbits/paths appear on a beat.
3532
3544
  - on_event_remove_relation: sourceId=event, targetId=item. Tears down a previously-added relation: params { type, target }.
3533
3545
  - on_event_set_color: sourceId=event, targetId=item. params { color, which: 'fill'|'stroke' }.
3534
3546
  - on_event_set_property: sourceId=event, targetId=item. params { property, value } — set any item property (opacity, rotation, strokeWidth, …).
3535
- - on_event_set_visibility: sourceId=event, targetId=item. params { visible } (default true).
3547
+ - on_event_set_visibility: sourceId=event, targetId=item. params { visible } (default true; false hides). params.value is not read: it is refused.
3536
3548
 
3537
3549
  STRUCTURAL LAYOUT (S12) — express STATIC COMPOSITION as relations instead of hardcoded x/y. Placement is computed from the TARGET'S BOUNDS and re-derived every frame, so moving or resizing the target moves the dependent with it, and the layout survives as editable graph data. Reach for these whenever the intent is "on", "under", "next to", "inside", or "lined up with" — a create_item with literal coordinates cannot express that intent and silently breaks when the target moves. All six need a target; all accept params.signal (deterministic IR port) and params.window.
3538
3550
  - on_top_of: source's BOTTOM edge rests on the target's TOP edge — stacking (a cocktail on a bar). params { gap (px between edges, default 0), align: 'left'|'center'(default)|'right', overhang (extra signed x-offset) }.
@@ -4825,6 +4837,58 @@ EXAMPLE:
4825
4837
  },
4826
4838
  },
4827
4839
  },
4840
+ {
4841
+ name: 'pinepaper_pattern',
4842
+ annotations: {
4843
+ title: 'Pattern',
4844
+ readOnlyHint: false,
4845
+ destructiveHint: false,
4846
+ idempotentHint: false,
4847
+ openWorldHint: false,
4848
+ },
4849
+ description: `Move many items with ONE stored declaration instead of a keyframe track on each: a wave running through a row of letters, a stagger spreading across a grid. The pattern is kept as a node: change its amplitude once and every member follows; remove it and the members go back to where they were. It is saved with the scene, undone as one step and restored on load.
4850
+
4851
+ KINDS:
4852
+ - phase_wave — members move on a sine, each a phase later than the one before. params: property ('y' default, 'x', 'rotation', 'opacity'), amplitude (px, degrees or 0..1), period (seconds per cycle), wavelength (members per full cycle), phase (radians). window { from, to } limits when it plays; time counts from \`from\`.
4853
+ - stagger — each member's animationDelay, derived from its place. params: step (s between neighbours), start (s), order: index | reverse | center | edges.
4854
+ - ring / orbit (the same motion) — members spaced evenly round a circle that turns. params: center ([x, y] or {x, y}; default 960, 540), target (an item id or name: the centre follows it), radius (px, default 200), period (seconds per turn, default 6), phase (RADIANS, the first member's angle), direction (1 clockwise, -1 or 'ccw'). Each member's own position is overwritten while it plays and comes back when the pattern is removed. window as for phase_wave.
4855
+
4856
+ MEMBERS — by names (a '*' matches any run: "letter-*"), ids, or a tag, in the order they are given; an array is taken as ids or names. A name that matches nothing is reported in the result, not ignored.
4857
+
4858
+ ACTIONS: create (needs id, kind, members) · modify (id + params, members or window) · remove (id) · list · get (id: the pattern and the items it holds).
4859
+
4860
+ EXAMPLE — a word waving, letter after letter:
4861
+ { "action": "create", "id": "wave", "kind": "phase_wave", "members": { "names": "letter-*" }, "params": { "amplitude": 12, "period": 1.2, "wavelength": 6 } }`,
4862
+ inputSchema: {
4863
+ type: 'object',
4864
+ properties: {
4865
+ action: { type: 'string', enum: ['create', 'modify', 'remove', 'list', 'get'], description: 'create · modify · remove · list · get' },
4866
+ id: { type: 'string', description: "the pattern's name; required except for list" },
4867
+ kind: { type: 'string', enum: [...PATTERN_KINDS], description: 'create: ' + PATTERN_KINDS.join(', ') },
4868
+ members: {
4869
+ description: 'which items: an array of ids or names, or { ids, names, tag }',
4870
+ oneOf: [
4871
+ { type: 'array', items: { type: 'string' } },
4872
+ {
4873
+ type: 'object',
4874
+ properties: {
4875
+ ids: { type: 'array', items: { type: 'string' } },
4876
+ names: { oneOf: [{ type: 'string' }, { type: 'array', items: { type: 'string' } }] },
4877
+ tag: { type: 'string' },
4878
+ },
4879
+ },
4880
+ ],
4881
+ },
4882
+ params: { type: 'object', description: 'phase_wave: property, amplitude, period, wavelength, phase · stagger: step, start, order · ring / orbit: center, target, radius, period, phase, direction' },
4883
+ window: {
4884
+ type: ['object', 'null'],
4885
+ properties: { from: { type: 'number' }, to: { type: 'number' } },
4886
+ description: 'phase_wave, ring, orbit: when it plays, in scene seconds',
4887
+ },
4888
+ },
4889
+ required: ['action'],
4890
+ },
4891
+ },
4828
4892
  {
4829
4893
  name: 'pinepaper_stagger',
4830
4894
  annotations: {
@@ -7993,7 +8057,7 @@ ACTIONS:
7993
8057
  SPEC:
7994
8058
  - mode: 'burst' (default) — bursts: [{ t, x, y, count, …per-burst overrides }]: a pop of particles at scene time t.
7995
8059
  - mode: 'trail' (or give target) — target (an item id), rate (per second), emitWindows [[t0, t1], …], window, offset: particles shed from a moving item.
7996
- - look and physics (per emitter or per burst): shape ('circle' | 'rect' | 'dash' | 'star' | 'confetti', or an array), palette [colours], size / sizes / sizeEnd, speed + angle ranges or velocities, gravity (px/s², +down), drag, friction, lifetime, fadeIn / fadeOut, spin, opacity, jitter, jitterGrow, seed.
8060
+ - look and physics (per emitter or per burst): shape ('circle' | 'rect' | 'dash' | 'star' | 'confetti', or an array), palette [colours], size / sizes / sizeEnd, speed + angle ranges or velocities ([[vx, vy], …] px/s, or [{x, y}, …]; particle i takes velocities[i % length], so give one per particle — the reply warns when count and the list differ), gravity (px/s², +down), drag, friction, lifetime, fadeIn / fadeOut, spin, opacity, jitter, jitterGrow, seed.
7997
8061
  UNITS (a number, or a [min, max] range picked per particle where it says range):
7998
8062
  - count: particles per burst, at most 10000 on the current studio (2000 on older studios) — a larger count is drawn at the cap and the reply warns with the number drawn. For more, add a second burst at the same t.
7999
8063
  - speed: px/s (range). angle: degrees, 0 = right, 90 = down (range). gravity: px/s². lifetime: seconds (range, > 0). size: px (range).
@@ -8680,7 +8744,7 @@ ITEMS:
8680
8744
  All: opacity, shadowColor, shadowBlur, blendMode, strokeColor, strokeWidth
8681
8745
  modify — {itemId, properties} — instant reposition/restyle. To MOVE an item, set {x,y} here (a one-shot position change, not an animation).
8682
8746
  delete — {itemId}
8683
- group — {itemIds: ["$0","$1",...], groupName} — combine the parts of a composite object into ONE draggable/animatable entity. ALWAYS group a specific named object (car, robot, house, character) after creating its parts. Returns {groupId}; safe — user can ungroup. Do NOT group a whole scene whose pieces move independently.
8747
+ group — {itemIds: ["$0","$1",...], groupName} — combine the parts of a composite object into ONE draggable/animatable entity. ALWAYS group a specific named object (car, robot, house, character) after creating its parts. Returns {groupId}, and the group takes the next "$N" like a create; safe — user can ungroup. Do NOT group a whole scene whose pieces move independently.
8684
8748
 
8685
8749
  ANIMATION:
8686
8750
  animate — Loop animation: {itemId, animationType, animationOptions}
@@ -8688,6 +8752,8 @@ ANIMATION:
8688
8752
  keyframe_animate — Timed animation: {itemId, keyframes: [{time, properties, easing}], duration, loop, append}. Replaces the item's track unless append: true (or mode: 'merge', the studio's spelling); two ops on one item in a batch are merged into one.
8689
8753
  Animatable properties: opacity, scale, scaleX, scaleY, x, y, rotation, fillColor, strokeColor, strokeWidth, width, height, radius, fontSize, trimStart/trimEnd/trimOffset (path draw-on)
8690
8754
  Easing (on the keyframe being moved TO): ${KEYFRAME_EASINGS_LIST}
8755
+ timeline — GSAP's timeline as JSON, compiled onto keyframe tracks (nothing is evaluated): {defaults: {ease, duration}, tweens: [{to: name | id | "$N" | [...] | "bar-*", vars: end values, from: start values, duration, delay, at: seconds | "<" | ">" | "+=0.2" | label, stagger: N | {each, from}, ease: "power2.out" | "none" | "back.out" | …, repeat, yoyo, repeatDelay}], duration?, labels?}. x/y are OFFSETS from where the item was created (as in GSAP); scale/scaleY on a bottom-anchored item (or transformOrigin "bottom") holds its edge; drawSVG "0%"→"100%" draws a path on; fill/color → fillColor. Every track is as long as the timeline. A tween it cannot carry is refused by name; the result has a receipt per tween.
8756
+ {type: "timeline", defaults: {ease: "power2.out"}, tweens: [{to: "bar-*", from: {scaleY: 0}, vars: {scaleY: 1}, duration: 0.8, at: 0.5, stagger: 0.15}, {to: "ring", vars: {rotation: 480}, duration: 8, ease: "none", at: 0}]}
8691
8757
  relation — Behavioral link: {sourceId, targetId, relationType, relationOptions}
8692
8758
  relationType: orbits, follows, attached_to, points_at, mirrors, parallax, wave_through, morphs_to, group_morphs_to, moves_along_path (+ 9 more in schema)
8693
8759
 
@@ -8702,7 +8768,7 @@ EFFECTS:
8702
8768
  PLAYBACK:
8703
8769
  play_timeline — {action: "play"|"stop"|"seek", duration, loop}
8704
8770
 
8705
- VARIABLE REFERENCES: "$0", "$1" etc. reference items by creation order within the batch. Place ALL create ops before any ops that reference them so the indices stay stable.
8771
+ VARIABLE REFERENCES: "$0", "$1" etc. reference the items this batch makes, in op order: create and group ops each take the next number (a ring / grid / orbit that makes items takes one per item); no other op does. [create, create, group, …] makes the group "$2". Place the ops that make an item before any op that references it.
8706
8772
 
8707
8773
  ANIMATION NOTES:
8708
8774
  - keyframe_animate position accepts [x, y] or { x, y } (normalized). fillColor/strokeColor accept rgba() for alpha. The create "opacity" and "blendMode" props are applied to the item.
@@ -8733,8 +8799,8 @@ EXAMPLE — Animated sky scene with timed reveals:
8733
8799
  properties: {
8734
8800
  type: {
8735
8801
  type: 'string',
8736
- enum: ['set_canvas_size', 'set_background', 'execute_generator', 'create', 'modify', 'delete', 'group', 'animate', 'keyframe_animate', 'relation', 'apply_mask', 'apply_effect', 'play_timeline'],
8737
- description: 'Operation type',
8802
+ enum: ['set_canvas_size', 'set_background', 'execute_generator', 'create', 'modify', 'delete', 'group', 'animate', 'keyframe_animate', 'relation', 'apply_mask', 'apply_effect', 'play_timeline', 'ring', 'grid', 'orbit', 'stagger', 'patch', 'timeline'],
8803
+ description: 'Operation type. timeline compiles a GSAP-shaped timeline onto keyframe tracks. ring / grid make many items in one op (each a create, so each fills a $N slot in order), orbit binds an orbits relation (making the orbiting item when itemType is given), stagger plays the same keyframes on itemIds one after another, patch changes the item with that name (refused when several items hold it).',
8738
8804
  },
8739
8805
  // Canvas setup
8740
8806
  width: { type: 'number', description: 'Canvas width for set_canvas_size (100-16384)' },
@@ -8821,8 +8887,32 @@ EXAMPLE — Animated sky scene with timed reveals:
8821
8887
  description: 'For play_timeline: action',
8822
8888
  },
8823
8889
  time: { type: 'number', description: 'For play_timeline seek: time in seconds' },
8890
+ // Macros
8891
+ count: { type: 'integer', minimum: 1, maximum: 200, description: 'ring: how many items (default 12)' },
8892
+ center: { type: 'object', properties: { x: { type: 'number' }, y: { type: 'number' } }, description: 'ring: the centre {x, y} (default 400, 300)' },
8893
+ radius: { type: 'number', description: 'ring: the circle the items sit on (default 150). orbit: the orbit radius.' },
8894
+ startAngle: { type: 'number', description: 'ring: degrees of the first item, clockwise from 3 o\'clock (default -90, the top)' },
8895
+ orient: { type: 'boolean', description: 'ring: turn each item to face out from the centre' },
8896
+ period: { type: 'number', description: 'ring: seconds for the stagger to travel once round (stagger = period / count)' },
8897
+ stagger: { type: 'number', description: 'ring, grid, stagger: seconds between one item\'s keyframes and the next' },
8898
+ rows: { type: 'integer', minimum: 1, description: 'grid: rows' },
8899
+ cols: { type: 'integer', minimum: 1, description: 'grid: columns (rows × cols up to 200)' },
8900
+ origin: { type: 'object', properties: { x: { type: 'number' }, y: { type: 'number' } }, description: 'grid: the first item {x, y} (default 100, 100)' },
8901
+ spacing: { oneOf: [{ type: 'number' }, { type: 'array', items: { type: 'number' }, minItems: 2, maxItems: 2 }], description: 'grid: gap between centres, or [dx, dy] (default 50)' },
8902
+ name: { type: 'string', description: 'ring, grid: name prefix (items are name_0, name_1 … or name_row_col). orbit: the made item\'s name. patch: the item to change.' },
8903
+ speed: { type: 'number', description: 'orbit: the orbits relation\'s speed (its own units; omit for the studio default)' },
8904
+ phaseDegrees: { type: 'number', description: 'orbit: starting angle in degrees' },
8905
+ // GSAP-shaped timeline (src/tools/timeline.ts)
8906
+ tweens: { type: 'array', items: { type: 'object' }, description: 'For timeline: [{to, vars, from, duration, delay, at, stagger, ease, repeat, yoyo, repeatDelay}]' },
8907
+ defaults: { type: 'object', description: 'For timeline: {ease, duration} for tweens that give none' },
8908
+ labels: { type: 'object', description: 'For timeline: {name: seconds}, for at: "name" or "name+=0.5"' },
8824
8909
  },
8825
8910
  required: ['type'],
8911
+ // Open, as the zod schema is (.passthrough()): a create op takes its
8912
+ // properties flat (content, fontSize, x, y …) and a keyframe op takes
8913
+ // timeOffset / timeUnits / clipInPoint / clipOutPoint at the top.
8914
+ // create_item's own check still names a property the studio ignores.
8915
+ additionalProperties: true,
8826
8916
  },
8827
8917
  description: 'Array of operations to execute in order',
8828
8918
  },
@@ -9507,6 +9597,8 @@ USE WHEN: You need full parameter docs, examples, or workflow guidance — espec
9507
9597
 
9508
9598
  PREFER RESOURCES WHERE POSSIBLE: The full AI Agent Guide is also available via the MCP resources API at pinepaper://docs/agent-guide — clients that support resources should pull it that way rather than calling this tool. Per-domain references live at pinepaper://docs/{generators,relations,masks,diagrams,maps,effects-and-filters,fonts,custom-paths,paperjs-in-pinepaper,templates,customization,getting-started}. Use this tool when the client doesn't support resources or when you want a specific tool's verbose description.
9509
9599
 
9600
+ THE AGENT LANE: for a scene built from shapes, text, keyframes and relations and exported to a file, a seven-tool lane carries the whole contract in its descriptions (no guide, no lessons file): start the server with PINEPAPER_TOOLKIT=lane, or pinepaper_set_toolkit {toolkit: "lane"}.
9601
+
9510
9602
  MODES:
9511
9603
  - No args → returns the full AI Agent Guide (same content as pinepaper://docs/agent-guide)
9512
9604
  - tool: "pinepaper_agent_batch_execute" → returns that tool's full verbose description
@@ -9539,20 +9631,26 @@ CATEGORIES: agent, browser, canvas, core, import, assets, batch, relations, anim
9539
9631
  idempotentHint: true,
9540
9632
  openWorldHint: false,
9541
9633
  },
9542
- description: `Switch the active toolkit profile and/or verbosity level at runtime. The tools/list updates immediately.
9634
+ description: `Load more tools, or switch the toolkit profile and/or verbosity, at runtime. The tools/list updates immediately.
9635
+
9636
+ The list starts with the CORE tools (the craft tools, the agent workflow, canvas and query). Everything else loads on demand:
9637
+ - load: ["map"] adds a group; load: ["<a tool's name>"] adds one tool. Loaded tools stay for the session, and the tools they name come with them.
9638
+ - Groups: ${Object.keys(TOOL_TAGS).join(', ')}.
9543
9639
 
9544
9640
  USE WHEN:
9545
- - You need diagram tools but are on the 'agent' profile → switch to 'diagram' or 'full'
9546
- - You need map tools → switch to 'map' or 'full'
9641
+ - You need a tool that is not listed (maps, diagrams, fonts, physics, ontology…) → load its group or its name
9642
+ - You want everything at once → toolkit: 'full' (or 'agent', which leaves out three diagnostics)
9547
9643
  - You want more/less detail in tool descriptions → switch verbosity
9548
9644
 
9549
9645
  PROFILES:
9646
+ - core: the craft tools and what they name, the agent workflow, canvas and query — default
9550
9647
  - full: Every tool, no filtering
9551
- - agent: Every tool except the diagnostics (get_performance_metrics, diagnostic_report) and register_item — default
9648
+ - agent: Every tool except the diagnostics (get_performance_metrics, diagnostic_report) and register_item
9552
9649
  - diagram: Diagram/flowchart tools
9553
9650
  - map: Map/choropleth tools
9554
9651
  - font: Font creation tools
9555
9652
  - minimal: Bare essentials
9653
+ - lane: the agent lane — seven tools (batch_execute, keyframe_animate, pattern, agent_export, lint_scene, event, clear_canvas) whose descriptions carry everything needed to build and export a shape/text/keyframe scene; set it for a scripted build that needs nothing else. It lists no way back: set it last.
9556
9654
 
9557
9655
  VERBOSITY:
9558
9656
  - verbose: Full descriptions
@@ -9563,8 +9661,13 @@ VERBOSITY:
9563
9661
  properties: {
9564
9662
  toolkit: {
9565
9663
  type: 'string',
9566
- description: 'Toolkit profile: full, agent, diagram, map, font, minimal',
9567
- enum: ['full', 'agent', 'diagram', 'map', 'font', 'minimal'],
9664
+ description: 'Toolkit profile: core (default), full, agent, diagram, map, font, minimal, lane',
9665
+ enum: ['core', 'full', 'agent', 'diagram', 'map', 'font', 'minimal', 'lane'],
9666
+ },
9667
+ load: {
9668
+ type: 'array',
9669
+ items: { type: 'string' },
9670
+ description: `Tool groups or tool names to add to the list for this session. Groups: ${Object.keys(TOOL_TAGS).join(', ')}.`,
9568
9671
  },
9569
9672
  verbosity: {
9570
9673
  type: 'string',