@pinepaper.studio/mcp-server 1.5.3 → 1.5.5

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 (77) hide show
  1. package/README.md +6 -4
  2. package/dist/agent/types.d.ts +16 -16
  3. package/dist/browser/url-target.d.ts +26 -0
  4. package/dist/browser/url-target.d.ts.map +1 -0
  5. package/dist/browser/url-target.js +50 -0
  6. package/dist/browser/url-target.js.map +1 -0
  7. package/dist/cli.js +2 -1
  8. package/dist/cli.js.map +1 -1
  9. package/dist/index.d.ts.map +1 -1
  10. package/dist/index.js +48 -4
  11. package/dist/index.js.map +1 -1
  12. package/dist/ontology/hints.d.ts +71 -0
  13. package/dist/ontology/hints.d.ts.map +1 -0
  14. package/dist/ontology/hints.js +189 -0
  15. package/dist/ontology/hints.js.map +1 -0
  16. package/dist/ontology/vocabulary.d.ts.map +1 -1
  17. package/dist/ontology/vocabulary.js +34 -0
  18. package/dist/ontology/vocabulary.js.map +1 -1
  19. package/dist/prompts/index.d.ts.map +1 -1
  20. package/dist/prompts/index.js +146 -0
  21. package/dist/prompts/index.js.map +1 -1
  22. package/dist/tools/compact-descriptions.d.ts +3 -0
  23. package/dist/tools/compact-descriptions.d.ts.map +1 -1
  24. package/dist/tools/compact-descriptions.js +17 -9
  25. package/dist/tools/compact-descriptions.js.map +1 -1
  26. package/dist/tools/definitions.d.ts +1 -1
  27. package/dist/tools/definitions.d.ts.map +1 -1
  28. package/dist/tools/definitions.js +1251 -2327
  29. package/dist/tools/definitions.js.map +1 -1
  30. package/dist/tools/handlers/camera.d.ts +19 -0
  31. package/dist/tools/handlers/camera.d.ts.map +1 -0
  32. package/dist/tools/handlers/camera.js +100 -0
  33. package/dist/tools/handlers/camera.js.map +1 -0
  34. package/dist/tools/handlers/export.d.ts +12 -0
  35. package/dist/tools/handlers/export.d.ts.map +1 -0
  36. package/dist/tools/handlers/export.js +30 -0
  37. package/dist/tools/handlers/export.js.map +1 -0
  38. package/dist/tools/handlers/font.d.ts +12 -0
  39. package/dist/tools/handlers/font.d.ts.map +1 -0
  40. package/dist/tools/handlers/font.js +135 -0
  41. package/dist/tools/handlers/font.js.map +1 -0
  42. package/dist/tools/handlers/maps.d.ts +19 -0
  43. package/dist/tools/handlers/maps.d.ts.map +1 -0
  44. package/dist/tools/handlers/maps.js +184 -0
  45. package/dist/tools/handlers/maps.js.map +1 -0
  46. package/dist/tools/handlers/ontology.d.ts +20 -0
  47. package/dist/tools/handlers/ontology.d.ts.map +1 -0
  48. package/dist/tools/handlers/ontology.js +185 -0
  49. package/dist/tools/handlers/ontology.js.map +1 -0
  50. package/dist/tools/handlers/tool-guide.d.ts +14 -0
  51. package/dist/tools/handlers/tool-guide.d.ts.map +1 -0
  52. package/dist/tools/handlers/tool-guide.js +52 -0
  53. package/dist/tools/handlers/tool-guide.js.map +1 -0
  54. package/dist/tools/handlers.d.ts +18 -0
  55. package/dist/tools/handlers.d.ts.map +1 -1
  56. package/dist/tools/handlers.js +213 -695
  57. package/dist/tools/handlers.js.map +1 -1
  58. package/dist/tools/minimal-descriptions.d.ts +4 -0
  59. package/dist/tools/minimal-descriptions.d.ts.map +1 -1
  60. package/dist/tools/minimal-descriptions.js +45 -66
  61. package/dist/tools/minimal-descriptions.js.map +1 -1
  62. package/dist/tools/toolkits.d.ts.map +1 -1
  63. package/dist/tools/toolkits.js +36 -62
  64. package/dist/tools/toolkits.js.map +1 -1
  65. package/dist/types/code-generator.d.ts +35 -34
  66. package/dist/types/code-generator.d.ts.map +1 -1
  67. package/dist/types/code-generator.js +869 -474
  68. package/dist/types/code-generator.js.map +1 -1
  69. package/dist/types/schemas.d.ts +1047 -988
  70. package/dist/types/schemas.d.ts.map +1 -1
  71. package/dist/types/schemas.js +282 -84
  72. package/dist/types/schemas.js.map +1 -1
  73. package/dist/version.d.ts +11 -0
  74. package/dist/version.d.ts.map +1 -0
  75. package/dist/version.js +18 -0
  76. package/dist/version.js.map +1 -0
  77. package/package.json +1 -1
@@ -9,6 +9,16 @@
9
9
  */
10
10
  import { COMPACT_DESCRIPTIONS } from './compact-descriptions.js';
11
11
  import { MINIMAL_DESCRIPTIONS } from './minimal-descriptions.js';
12
+ import { EffectTypeSchema, SimpleAnimationTypeSchema, } from '../types/schemas.js';
13
+ /**
14
+ * Vocabulary lists derived from Zod schemas so tool descriptions stay in
15
+ * sync automatically. The description-schema-parity test
16
+ * (src/__tests__/unit/description-schema-parity.test.ts) fails CI if any
17
+ * tool description that names a vocabulary slot drops or invents values
18
+ * relative to the source-of-truth schema.
19
+ */
20
+ const EFFECT_TYPES_LIST = EffectTypeSchema.options.join(', ');
21
+ const SIMPLE_ANIMATION_TYPES_LIST = SimpleAnimationTypeSchema.options.join(', ');
12
22
  // =============================================================================
13
23
  // AI AGENT GUIDE (exported for pinepaper_tool_guide)
14
24
  // =============================================================================
@@ -47,7 +57,7 @@ RULES:
47
57
  CANVAS: set_canvas_size (width/height or preset) → set_background (color) → execute_generator (procedural art)
48
58
  ITEMS: create (itemType, position, properties) → modify (itemId, properties) → delete (itemId)
49
59
  ANIMATE: animate (loop presets) → keyframe_animate (timed reveals) → relation (behavioral links)
50
- EFFECTS: apply_mask (reveal animations) → apply_effect (sparkle/blast)
60
+ EFFECTS: apply_mask (reveal animations) → apply_effect (sparkle/blast/bubbles/fireflies/trail...)
51
61
  PLAY: play_timeline (start playback)
52
62
 
53
63
  ─── GENERATORS (prefer these for backgrounds) ───
@@ -64,6 +74,7 @@ Choose based on mood:
64
74
 
65
75
  Shapes: circle, rectangle, star, ellipse, triangle, polygon, line, arc, path
66
76
  Text: text (content, fontSize, fontFamily, color, fontWeight)
77
+ Dynamic text: set contentType on text items → clock (live time), timer (elapsed), countdown (from N seconds), stopwatch (pauseable)
67
78
  All items: opacity, shadowColor, shadowBlur, blendMode, strokeColor, strokeWidth
68
79
 
69
80
  SVG imports for recognizable objects (planes, cars, animals, buildings):
@@ -73,7 +84,7 @@ SVG imports for recognizable objects (planes, cars, animals, buildings):
73
84
 
74
85
  Loop presets (animate): pulse, rotate, bounce, fade, wobble, slide, typewriter
75
86
  Keyframe (keyframe_animate): [{time, properties, easing}] → opacity, scale, scaleX, scaleY, x, y, rotation, fillColor, strokeColor, fontSize
76
- Relations (relation): orbits, follows, attached_to, points_at, mirrors, parallax, wave_through, morphs_to (+ 9 more in batch_execute schema)
87
+ Relations (relation): orbits, follows, attached_to, points_at, mirrors, parallax, wave_through, morphs_to, group_morphs_to, moves_along_path (+ 9 more in batch_execute schema)
77
88
  Masks (apply_mask): wipeLeft, wipeRight, wipeUp, wipeDown, iris, irisOut, star, heart, curtainHorizontal, curtainVertical, cinematic, diagonalWipe, revealUp, revealDown
78
89
  Effects (apply_effect): sparkle, blast
79
90
 
@@ -111,10 +122,35 @@ Shapes: process (rect), decision (diamond), terminal (rounded), data, document,
111
122
  Workflow: create shapes with positions → connect with arrows → optional auto_layout
112
123
  See pinepaper://docs/diagrams for full examples.
113
124
 
125
+ ─── STANDALONE TOOLS (not batch — call directly) ───
126
+
127
+ Deformation: pinepaper_deform — vertex-level presets (fold, squeeze, twist, ripple, wave, breathe, wobble...)
128
+ Phase-driven animation: sin, blink, pingpong, elastic, heartbeat, stepped
129
+ Use for organic motion that keyframes can't achieve.
130
+
131
+ Sprite Sheets: pinepaper_sprite_sheet — generate from skeleton poses, play, export (PNG + atlas)
132
+ For character animation and game sprite pipelines.
133
+
134
+ Interaction: pinepaper_interaction — continuous physics behaviors (repel, attract, follow, orbit, slingshot)
135
+ For interactive storytelling, quizzes, games. trigger_action for state changes (incrementScore, navigate, showFeedback).
136
+
137
+ Data Viz: pinepaper_create_chart — create/update/reconfigure/remove charts (bar, line, scatter, area)
138
+ Pass data as array of objects + options. Auto-animated with expression-driven oscillation.
139
+
140
+ Magic: pinepaper_magic — ontology-aware auto-animation + style remix
141
+ One-click animate (mood: calm/professional/energetic/dramatic/whimsical) or remix (cycle colors/fonts).
142
+
143
+ Physics: pinepaper_physics — rigid body simulation (init, add_body, apply_force, create_joint)
144
+ For interactive simulations, gravity, collisions. Based on Box2D/Planck.js.
145
+
146
+ Measurement: pinepaper_measurement — rulers, grid, snap-to-grid, get item dimensions
147
+ For precise layouts and alignment.
148
+
114
149
  ─── CANVAS & EXPORT ───
115
150
 
116
151
  Presets: instagram (1080x1080), youtube (1920x1080), tiktok (1080x1920), twitter (1200x675)
117
- Export: pinepaper_agent_export (SVG/PNG/GIF/MP4/WebM/PDF), pinepaper_export_svg`;
152
+ Export: pinepaper_agent_export (SVG/PNG/GIF/MP4/WebM/PDF), pinepaper_export_svg
153
+ Widget: pinepaper_export_widget (pp:PinePaper ontology JSON), pinepaper_export_widget_html (self-contained HTML with tree-shaken runtime)`;
118
154
  /*
119
155
  * The AI_AGENT_GUIDE constant above is included as a comment in verbose/compact modes
120
156
  * and served on-demand via pinepaper_tool_guide in minimal mode.
@@ -290,7 +326,7 @@ USE WHEN:
290
326
  IMPORTANT:
291
327
  - Save the returned itemId! You need it for pinepaper_add_relation, pinepaper_modify_item, pinepaper_delete_item, etc.
292
328
  - If there's a welcome template on the canvas, use pinepaper_clear_canvas first
293
- - Position defaults to canvas center (400, 300). Use position: {x, y} to place elsewhere.
329
+ - Position defaults to canvas center (400, 300). Use position: {x, y} or [x, y] (both forms accepted) to place elsewhere.
294
330
  - DO NOT take screenshots after every create operation. Trust the API response - if it returns success, the item was created. Take ONE screenshot at the end to verify the final result.
295
331
 
296
332
  ⚠️ COMPLEX CHARACTERS/ILLUSTRATIONS:
@@ -352,12 +388,23 @@ For glossy 3D spheres, use pinepaper_create_glossy_sphere instead. For diagonal
352
388
  description: 'Type of item to create',
353
389
  },
354
390
  position: {
355
- type: 'object',
356
- properties: {
357
- x: { type: 'number', description: 'X coordinate (default: 400)' },
358
- y: { type: 'number', description: 'Y coordinate (default: 300)' },
359
- },
360
- description: 'Position on canvas',
391
+ oneOf: [
392
+ {
393
+ type: 'object',
394
+ properties: {
395
+ x: { type: 'number', description: 'X coordinate (default: 400)' },
396
+ y: { type: 'number', description: 'Y coordinate (default: 300)' },
397
+ },
398
+ },
399
+ {
400
+ type: 'array',
401
+ items: { type: 'number' },
402
+ minItems: 2,
403
+ maxItems: 2,
404
+ description: '[x, y] tuple — array shorthand for position',
405
+ },
406
+ ],
407
+ description: 'Position on canvas. Either {x, y} object or [x, y] array.',
361
408
  },
362
409
  properties: {
363
410
  type: 'object',
@@ -435,7 +482,15 @@ MODIFIABLE PROPERTIES:
435
482
  - blendMode: Blend mode (normal, multiply, screen, overlay, etc.)
436
483
 
437
484
  GRADIENT OBJECT FORMAT:
438
- {type: "linear"|"radial", stops: [{color: "#fff", offset: 0}, {color: "#000", offset: 1}], origin: [x,y], destination: [x,y]}`,
485
+ {type: "linear"|"radial", stops: [{color: "#fff", offset: 0}, {color: "#000", offset: 1}], origin: [x,y], destination: [x,y]}
486
+
487
+ LETTER-COLLAGE PROPS (non-destructive — registry ids, animations, relations, effects, deformations all preserved):
488
+ - palette (collage group): Swap palette name in-place. e.g. "wordle", "spring", "sunset", "magazine". Walks existing letters, rewrites tile + text fills. No geometry change.
489
+ - collageStyle (collage group): Swap visual style — "tile" | "magazine" | "paperCut" | "fold" | "gradient" | "image". Geometry rebuilds; every registryId is preserved via graft.
490
+ - palette + collageStyle (collage group): Combine in one call to apply both atomically.
491
+ - bgColor (single letter group, child of a collage): Tile/background fill for that one letter.
492
+ - textColor (single letter group): PointText fill for that one letter.
493
+ Use the collage group's id for palette/collageStyle; use a child letter's id for bgColor/textColor. Prefer this over destructive recreation.`,
439
494
  inputSchema: {
440
495
  type: 'object',
441
496
  properties: {
@@ -445,7 +500,7 @@ GRADIENT OBJECT FORMAT:
445
500
  },
446
501
  properties: {
447
502
  type: 'object',
448
- description: 'Properties to update: x, y, width, height, scale, scaleX, scaleY, rotation, opacity, color, strokeColor, strokeWidth, fontSize, content. DO NOT pass animationType here — use pinepaper_animate or pinepaper_keyframe_animate instead.',
503
+ description: 'Properties to update: x, y, width, height, scale, scaleX, scaleY, rotation, opacity, color, strokeColor, strokeWidth, fontSize, content. Letter-collage non-destructive props (preserve ids/animations/relations): palette, collageStyle (collage group); bgColor, textColor (single letter). DO NOT pass animationType here — use pinepaper_animate or pinepaper_keyframe_animate instead.',
449
504
  additionalProperties: true,
450
505
  },
451
506
  data: {
@@ -707,6 +762,65 @@ Returns the itemId of the imported SVG group, which can be used with pinepaper_a
707
762
  },
708
763
  },
709
764
  },
765
+ {
766
+ name: 'pinepaper_import_mermaid',
767
+ annotations: {
768
+ title: 'Import Mermaid Diagram',
769
+ readOnlyHint: false,
770
+ destructiveHint: false,
771
+ idempotentHint: false,
772
+ openWorldHint: false,
773
+ },
774
+ description: `Import a Mermaid diagram source string and render it onto the canvas as native diagram shapes + connectors. Faster than building a flowchart shape-by-shape with pinepaper_create_diagram_shape + pinepaper_connect.
775
+
776
+ USE WHEN:
777
+ - User asks for a flowchart, sequence diagram, ER diagram, class diagram, or state machine
778
+ - You have Mermaid source from another tool / docs / the user's clipboard
779
+ - You want to author multi-node diagrams in one call instead of N create+connect operations
780
+
781
+ SUPPORTED DIAGRAM TYPES (auto-detected from the first non-blank line):
782
+ - flowchart / graph: shapes + edges + subgraphs + chained edges (TD, LR, RL, BT directions)
783
+ - stateDiagram(-v2): states, transitions, [*] start/end, stereotypes, nested states
784
+ - sequenceDiagram: participants, messages, activations / lifelines
785
+ - erDiagram: entities + relationships + attributes
786
+ - classDiagram: classes, fields, methods, visibility, inheritance / association
787
+
788
+ OPTIONS:
789
+ - autoLayout (default true): run hierarchical/force layout after import. Set false to keep coordinates exactly as parsed.
790
+ - clearExisting (default false): remove existing canvas items first. Default is additive — diagram is appended.
791
+
792
+ EXAMPLE (flowchart):
793
+ {
794
+ "mermaidText": "flowchart TD\\n A[Start] --> B{Decision}\\n B -->|Yes| C[Action]\\n B -->|No| D[End]"
795
+ }
796
+
797
+ EXAMPLE (sequenceDiagram):
798
+ {
799
+ "mermaidText": "sequenceDiagram\\n Alice->>Bob: Hello\\n Bob-->>Alice: Hi back\\n Note right of Bob: Thinking..."
800
+ }
801
+
802
+ Returns { success, nodeCount, edgeCount, nodes, edges, errors }. The created shapes participate in the relation/animation systems just like natively created items — you can grab their ids from \`nodes\` and feed them into pinepaper_add_relation, pinepaper_animate, etc.
803
+
804
+ NOTE: Import-only — there is no MCP equivalent of FxTool's exportMermaid. Mermaid lacks animation primitives, so a round-trip would silently drop animations.`,
805
+ inputSchema: {
806
+ type: 'object',
807
+ properties: {
808
+ mermaidText: {
809
+ type: 'string',
810
+ description: 'Mermaid diagram source. First line picks the type (flowchart, stateDiagram, sequenceDiagram, erDiagram, classDiagram).',
811
+ },
812
+ autoLayout: {
813
+ type: 'boolean',
814
+ description: 'Run auto-layout after import (default: true).',
815
+ },
816
+ clearExisting: {
817
+ type: 'boolean',
818
+ description: 'Clear existing canvas items first (default: false).',
819
+ },
820
+ },
821
+ required: ['mermaidText'],
822
+ },
823
+ },
710
824
  {
711
825
  name: 'pinepaper_import_image',
712
826
  annotations: {
@@ -1151,6 +1265,8 @@ RELATION COMPATIBILITY:
1151
1265
  Circle→Circle: radius interpolation
1152
1266
  Text→Text: font blend
1153
1267
  Cross-type: particle denoising transition
1268
+ - group_morphs_to: pair-by-index morph between two paper.Groups (any two — graph vertices+edges, letter collages, dashboard clusters). Path.Line children deform via endpoints; other children translate; excess children fade. Params: duration, hold, loop, easing (linear|easeIn|easeOut|easeInOut), deformLines.
1269
+ - moves_along_path: self-relation (targetId=null); item is driven along a custom-drawn path stored in params.path (array of {x,y} or [x,y]). Params: path, speed, closed, phase, easing (linear|easeIn|easeOut|easeInOut|sine|bounce|pingpong).
1154
1270
 
1155
1271
  VERIFYING ANIMATION WORKS:
1156
1272
  After adding a relation, verify the animation is running:
@@ -1172,7 +1288,7 @@ Relations are COMPOSITIONAL - an item can have multiple relations that work toge
1172
1288
  },
1173
1289
  relationType: {
1174
1290
  type: 'string',
1175
- enum: ['orbits', 'follows', 'attached_to', 'maintains_distance', 'points_at', 'mirrors', 'parallax', 'bounds_to', 'animates', 'grows_from', 'staggered_with', 'indicates', 'circumscribes', 'wave_through', 'camera_follows', 'camera_animates', 'morphs_to'],
1291
+ enum: ['orbits', 'follows', 'attached_to', 'maintains_distance', 'points_at', 'mirrors', 'parallax', 'bounds_to', 'animates', 'grows_from', 'staggered_with', 'indicates', 'circumscribes', 'wave_through', 'camera_follows', 'camera_animates', 'morphs_to', 'group_morphs_to', 'moves_along_path'],
1176
1292
  description: 'Type of relationship',
1177
1293
  },
1178
1294
  params: {
@@ -1206,7 +1322,7 @@ USE WHEN:
1206
1322
  targetId: { type: 'string', description: 'Target item ID' },
1207
1323
  relationType: {
1208
1324
  type: 'string',
1209
- enum: ['orbits', 'follows', 'attached_to', 'maintains_distance', 'points_at', 'mirrors', 'parallax', 'bounds_to', 'animates', 'grows_from', 'staggered_with', 'indicates', 'circumscribes', 'wave_through', 'camera_follows', 'camera_animates', 'morphs_to'],
1325
+ enum: ['orbits', 'follows', 'attached_to', 'maintains_distance', 'points_at', 'mirrors', 'parallax', 'bounds_to', 'animates', 'grows_from', 'staggered_with', 'indicates', 'circumscribes', 'wave_through', 'camera_follows', 'camera_animates', 'morphs_to', 'group_morphs_to', 'moves_along_path'],
1210
1326
  description: 'Specific relation type to remove (optional - removes all if not specified)',
1211
1327
  },
1212
1328
  },
@@ -1234,7 +1350,7 @@ USE WHEN:
1234
1350
  itemId: { type: 'string', description: 'Item to query relations for' },
1235
1351
  relationType: {
1236
1352
  type: 'string',
1237
- enum: ['orbits', 'follows', 'attached_to', 'maintains_distance', 'points_at', 'mirrors', 'parallax', 'bounds_to', 'animates', 'grows_from', 'staggered_with', 'indicates', 'circumscribes', 'wave_through', 'camera_follows', 'camera_animates', 'morphs_to'],
1353
+ enum: ['orbits', 'follows', 'attached_to', 'maintains_distance', 'points_at', 'mirrors', 'parallax', 'bounds_to', 'animates', 'grows_from', 'staggered_with', 'indicates', 'circumscribes', 'wave_through', 'camera_follows', 'camera_animates', 'morphs_to', 'group_morphs_to', 'moves_along_path'],
1238
1354
  description: 'Filter by relation type (optional)',
1239
1355
  },
1240
1356
  direction: {
@@ -1437,7 +1553,7 @@ USE WHEN:
1437
1553
  - Any animation with specific timing or sequential stages
1438
1554
 
1439
1555
  ANIMATABLE PROPERTIES:
1440
- - position: [x, y] array
1556
+ - position: [x, y] array (a { x, y } object is also accepted and normalized)
1441
1557
  - x, y: Individual coordinates
1442
1558
  - scale: Uniform scale
1443
1559
  - scaleX, scaleY: Axis scaling
@@ -1453,7 +1569,17 @@ EASING OPTIONS:
1453
1569
  - easeOut: Slow end
1454
1570
  - easeInOut: Slow start and end
1455
1571
  - bounce: Bounce effect
1456
- - elastic: Elastic overshoot`,
1572
+ - elastic: Elastic overshoot
1573
+
1574
+ CLIP WINDOW (optional — Premiere/Canva-style clip behavior):
1575
+ - timeOffset: Shift the whole clip in canvas time (seconds). The animation only runs while canvas time is in [timeOffset, timeOffset + (clipOutPoint - clipInPoint)].
1576
+ - clipInPoint: Skip the first N seconds of keyframe data (head trim).
1577
+ - clipOutPoint: Stop at N seconds into the keyframe data (tail trim). Default: lastKeyframeTime.
1578
+ Outside the clip window the item is hidden via item.visible=false (opacity is left alone, so opacity-keyframes still work inside the window).
1579
+
1580
+ EXAMPLE — Reveal at 2s, skip first second of keyframe data, end at 4s of keyframe data:
1581
+ { itemId, timeOffset: 2, clipInPoint: 1, clipOutPoint: 4, keyframes: [...] }
1582
+ // Item visible during canvas time 2..5s; keyframes shifted so kf time=1 plays at canvas 2s.`,
1457
1583
  inputSchema: {
1458
1584
  type: 'object',
1459
1585
  properties: {
@@ -1486,6 +1612,18 @@ EASING OPTIONS:
1486
1612
  type: 'boolean',
1487
1613
  description: 'Whether to loop the animation',
1488
1614
  },
1615
+ timeOffset: {
1616
+ type: 'number',
1617
+ description: 'Shift the whole clip in canvas time (seconds). Item is hidden outside [timeOffset, timeOffset+window].',
1618
+ },
1619
+ clipInPoint: {
1620
+ type: 'number',
1621
+ description: 'Skip the first N seconds of keyframe data (head trim).',
1622
+ },
1623
+ clipOutPoint: {
1624
+ type: 'number',
1625
+ description: 'Stop at N seconds into the keyframe data (tail trim). Default: lastKeyframeTime.',
1626
+ },
1489
1627
  },
1490
1628
  required: ['itemId', 'keyframes'],
1491
1629
  },
@@ -1754,29 +1892,60 @@ Requires maskType and keyframes array.`,
1754
1892
  idempotentHint: false,
1755
1893
  openWorldHint: false,
1756
1894
  },
1757
- description: `Animate camera with keyframe-based zoom and pan sequence for cinematic effects.
1895
+ description: `Animate camera with keyframe-based zoom, pan, and 3D tilt sequence for cinematic effects.
1758
1896
 
1759
1897
  USE WHEN:
1760
1898
  - Creating cinematic camera movements
1761
1899
  - Building presentation zoom sequences
1762
1900
  - Making dramatic reveals with camera motion
1763
1901
  - Tour animations showing different parts of canvas
1902
+ - 3D perspective effects (pitch/yaw tilt via equirectangular projection)
1903
+
1904
+ The camera follows a keyframe sequence. For an orbit-style camera (revolving
1905
+ around a subject), add 4-8 keyframes around the pivot using pathMode: "arc"
1906
+ with pivot + arcDirection on each segment. There is no separate "orbit" mode
1907
+ — it is expressible as keyframes + arc paths.
1764
1908
 
1765
1909
  KEYFRAME PROPERTIES:
1766
1910
  - time: Time in seconds
1767
1911
  - zoom: Zoom level (1=normal, 2=2x zoom in, 0.5=zoom out)
1768
- - center: View center [x, y]
1912
+ - focus: Camera target, resolved live against the scene graph. Accepts:
1913
+ [x, y] literal position
1914
+ 'item-id' itemRegistry lookup → item bounds center (tracks the item as it moves)
1915
+ { item: 'id', offset: [dx, dy] } item center + offset
1916
+ - center: [x, y] — legacy alias, honored only when focus is absent
1917
+ - pitch: 3D tilt in degrees (0=flat, positive=tilt forward). Uses equirectangular projection
1918
+ - yaw: 3D rotation in degrees. Uses equirectangular projection
1769
1919
  - easing: Timing function (linear, easeIn, easeOut, easeInOut, bounce, elastic)
1770
1920
 
1771
- EXAMPLE:
1921
+ CURVED INTER-KEYFRAME PATHS (optional; default is linear):
1922
+ - pathOut: [dx, dy] — bezier tangent handle when LEAVING this keyframe
1923
+ - pathIn: [dx, dy] — bezier tangent handle when ARRIVING at this keyframe
1924
+ Either handle alone promotes the segment to a cubic bezier.
1925
+ - pathMode: 'arc' — arc around a pivot. Requires pivot: [x, y]; optional arcDirection: 'ccw'|'cw'
1926
+ - pathMode: 'custom' + path: 'M x y C ...' — sample any SVG path string (falls back to linear when Paper.js is unavailable)
1927
+ Endpoints always match the resolved focus of each keyframe — handles only shape the curve between them.
1928
+
1929
+ EXAMPLE (with 3D tilt):
1772
1930
  {
1773
1931
  "duration": 6,
1774
1932
  "loop": true,
1933
+ "fov": 60,
1934
+ "keyframes": [
1935
+ { "time": 0, "zoom": 1, "focus": [400, 300], "pitch": 0, "yaw": 0 },
1936
+ { "time": 2, "zoom": 2, "focus": "hero-character", "pitch": 12, "yaw": -5, "easing": "easeInOut" },
1937
+ { "time": 4, "zoom": 2, "focus": { "item": "villain", "offset": [0, -40] }, "pitch": 8, "yaw": 3, "easing": "easeOut" },
1938
+ { "time": 6, "zoom": 1, "focus": [400, 300], "pitch": 0, "yaw": 0, "easing": "easeInOut" }
1939
+ ]
1940
+ }
1941
+
1942
+ EXAMPLE (curved arc between waypoints):
1943
+ {
1944
+ "duration": 4,
1775
1945
  "keyframes": [
1776
- { "time": 0, "zoom": 1, "center": [400, 300] },
1777
- { "time": 2, "zoom": 2, "center": [400, 300], "easing": "easeInOut" },
1778
- { "time": 4, "zoom": 2, "center": [600, 300], "easing": "easeOut" },
1779
- { "time": 6, "zoom": 1, "center": [400, 300], "easing": "easeInOut" }
1946
+ { "time": 0, "zoom": 1, "focus": [200, 300], "pathOut": [120, -60] },
1947
+ { "time": 2, "zoom": 1.5, "focus": [800, 300], "pathIn": [-120, -60], "pathMode": "arc", "pivot": [500, 450], "arcDirection": "ccw" },
1948
+ { "time": 4, "zoom": 1, "focus": [200, 300] }
1780
1949
  ]
1781
1950
  }`,
1782
1951
  inputSchema: {
@@ -1790,183 +1959,113 @@ EXAMPLE:
1790
1959
  properties: {
1791
1960
  time: { type: 'number', description: 'Time in seconds' },
1792
1961
  zoom: { type: 'number', description: 'Zoom level (1=normal, 2=2x zoom in)' },
1962
+ focus: {
1963
+ description: 'Camera target, resolved live against the scene graph. Accepts [x, y], an item id string, or { item: "id", offset: [dx, dy] }. Takes precedence over center.',
1964
+ },
1793
1965
  center: {
1794
1966
  type: 'array',
1795
1967
  items: { type: 'number' },
1796
- description: 'View center [x, y]',
1968
+ description: 'Legacy view center [x, y] — honored only when focus is absent',
1797
1969
  },
1970
+ pitch: { type: 'number', description: '3D tilt in degrees (0=flat, positive=forward tilt)' },
1971
+ yaw: { type: 'number', description: '3D rotation in degrees' },
1798
1972
  easing: {
1799
1973
  type: 'string',
1800
1974
  enum: ['linear', 'easeIn', 'easeOut', 'easeInOut', 'bounce', 'elastic'],
1801
1975
  },
1976
+ pathOut: {
1977
+ type: 'array',
1978
+ items: { type: 'number' },
1979
+ description: 'Bezier tangent handle [dx, dy] when leaving this keyframe. Promotes segment to cubic bezier.',
1980
+ },
1981
+ pathIn: {
1982
+ type: 'array',
1983
+ items: { type: 'number' },
1984
+ description: 'Bezier tangent handle [dx, dy] when arriving at this keyframe. Promotes segment to cubic bezier.',
1985
+ },
1986
+ pathMode: {
1987
+ type: 'string',
1988
+ enum: ['arc', 'custom'],
1989
+ description: 'arc: curve around pivot (requires pivot). custom: sample an SVG path (requires path).',
1990
+ },
1991
+ pivot: {
1992
+ type: 'array',
1993
+ items: { type: 'number' },
1994
+ description: 'Arc center [x, y] when pathMode is "arc"',
1995
+ },
1996
+ arcDirection: {
1997
+ type: 'string',
1998
+ enum: ['ccw', 'cw'],
1999
+ description: 'Arc sweep direction when pathMode is "arc" (default: ccw)',
2000
+ },
2001
+ path: {
2002
+ type: 'string',
2003
+ description: 'SVG path string (e.g. "M 100 200 C 150 100 350 100 400 200") when pathMode is "custom"',
2004
+ },
1802
2005
  },
1803
2006
  },
1804
2007
  },
1805
2008
  duration: { type: 'number', description: 'Total animation duration in seconds' },
1806
2009
  loop: { type: 'boolean', description: 'Loop the animation' },
1807
2010
  delay: { type: 'number', description: 'Delay before animation starts' },
2011
+ fov: { type: 'number', description: 'Field of view in degrees for 3D perspective (default: 60)' },
1808
2012
  },
1809
2013
  required: ['keyframes', 'duration'],
1810
2014
  },
1811
2015
  },
1812
2016
  {
1813
- name: 'pinepaper_camera_zoom',
1814
- annotations: {
1815
- title: 'Camera Zoom',
1816
- readOnlyHint: false,
1817
- destructiveHint: false,
1818
- idempotentHint: false,
1819
- openWorldHint: false,
1820
- },
1821
- description: `Simple camera zoom animation.
1822
-
1823
- USE WHEN:
1824
- - Quick zoom in to focus on something
1825
- - Zoom out to show full canvas
1826
- - Simple zoom effects without complex keyframes`,
1827
- inputSchema: {
1828
- type: 'object',
1829
- properties: {
1830
- direction: {
1831
- type: 'string',
1832
- enum: ['in', 'out'],
1833
- description: 'Zoom direction',
1834
- },
1835
- level: {
1836
- type: 'number',
1837
- description: 'Target zoom level (default: 2 for in, 0.5 for out)',
1838
- },
1839
- duration: {
1840
- type: 'number',
1841
- description: 'Animation duration in seconds (default: 0.5)',
1842
- },
1843
- },
1844
- required: ['direction'],
1845
- },
1846
- },
1847
- {
1848
- name: 'pinepaper_camera_pan',
2017
+ name: 'pinepaper_camera',
1849
2018
  annotations: {
1850
- title: 'Camera Pan',
2019
+ title: 'Camera Control',
1851
2020
  readOnlyHint: false,
1852
2021
  destructiveHint: false,
1853
2022
  idempotentHint: false,
1854
2023
  openWorldHint: false,
1855
2024
  },
1856
- description: `Pan camera in a direction or to specific coordinates.
2025
+ description: `Camera control: zoom, pan, move, reset, stop, get state. Single action-dispatched tool replaces six thin wrappers. For keyframe walkthroughs / 3D pitch+yaw / curved paths, use pinepaper_camera_animate (a separate, richer tool).
1857
2026
 
1858
- USE WHEN:
1859
- - Moving view to different part of canvas
1860
- - Directional panning (left, right, up, down)
1861
- - Centering on specific coordinates
2027
+ ACTIONS:
2028
+ - zoom — { direction: "in"|"out", level?: number, duration?: number }
2029
+ level defaults to 2 (in) or 0.5 (out). duration default 0.5s.
2030
+ - pan — { direction?: "left"|"right"|"up"|"down", amount?: number, x?: number, y?: number, duration?: number }
2031
+ Either direction+amount (default 100px) OR x+y for panTo.
2032
+ - move_to — { x, y, zoom, duration?: number }
2033
+ Combined zoom + pan in one motion.
2034
+ - reset — { duration?: number }
2035
+ Back to center + zoom 1.
2036
+ - stop — {}
2037
+ Cancel any active animation.
2038
+ - state — {}
2039
+ Returns { zoom, center, isAnimating }.
2040
+ - fit_view — {}
2041
+ Fit canvas content to the viewport (calls app.fitView()).
1862
2042
 
1863
2043
  EXAMPLES:
1864
- // Pan left 200 pixels
1865
- { "direction": "left", "amount": 200 }
1866
-
1867
- // Pan to specific coordinates
1868
- { "x": 200, "y": 200, "duration": 1 }`,
2044
+ { action: "zoom", direction: "in", level: 2.5 }
2045
+ { action: "pan", x: 200, y: 200, duration: 1 }
2046
+ { action: "move_to", x: 600, y: 400, zoom: 2 }
2047
+ { action: "reset" }
2048
+ { action: "state" }`,
1869
2049
  inputSchema: {
1870
2050
  type: 'object',
1871
2051
  properties: {
1872
- direction: {
2052
+ action: {
1873
2053
  type: 'string',
1874
- enum: ['left', 'right', 'up', 'down'],
1875
- description: 'Pan direction (use with amount)',
1876
- },
1877
- amount: {
1878
- type: 'number',
1879
- description: 'Pixels to pan (default: 100)',
1880
- },
1881
- x: {
1882
- type: 'number',
1883
- description: 'Target X coordinate (use with y for panTo)',
2054
+ enum: ['zoom', 'pan', 'move_to', 'reset', 'stop', 'state', 'fit_view'],
2055
+ description: 'Camera action to perform',
1884
2056
  },
1885
- y: {
1886
- type: 'number',
1887
- description: 'Target Y coordinate (use with x for panTo)',
1888
- },
1889
- duration: {
1890
- type: 'number',
1891
- description: 'Animation duration in seconds (default: 0.5)',
2057
+ direction: {
2058
+ type: 'string',
2059
+ description: 'For zoom: "in"|"out". For pan: "left"|"right"|"up"|"down".',
1892
2060
  },
2061
+ level: { type: 'number', description: 'Zoom level (zoom action; default 2 for in, 0.5 for out)' },
2062
+ amount: { type: 'number', description: 'Pixels to pan (pan action with direction; default 100)' },
2063
+ x: { type: 'number', description: 'Target X coordinate (pan with x+y, or move_to)' },
2064
+ y: { type: 'number', description: 'Target Y coordinate (pan with x+y, or move_to)' },
2065
+ zoom: { type: 'number', description: 'Target zoom level (move_to)' },
2066
+ duration: { type: 'number', description: 'Animation duration in seconds (default 0.5)' },
1893
2067
  },
1894
- },
1895
- },
1896
- {
1897
- name: 'pinepaper_camera_move_to',
1898
- annotations: {
1899
- title: 'Camera Move To',
1900
- readOnlyHint: false,
1901
- destructiveHint: false,
1902
- idempotentHint: false,
1903
- openWorldHint: false,
1904
- },
1905
- description: `Combined camera zoom and pan to a specific location.
1906
-
1907
- USE WHEN:
1908
- - Moving to and zooming on a specific point in one motion
1909
- - Focusing on an item with appropriate zoom level`,
1910
- inputSchema: {
1911
- type: 'object',
1912
- properties: {
1913
- x: { type: 'number', description: 'Target X coordinate' },
1914
- y: { type: 'number', description: 'Target Y coordinate' },
1915
- zoom: { type: 'number', description: 'Target zoom level' },
1916
- duration: { type: 'number', description: 'Animation duration in seconds (default: 0.5)' },
1917
- },
1918
- required: ['x', 'y', 'zoom'],
1919
- },
1920
- },
1921
- {
1922
- name: 'pinepaper_camera_reset',
1923
- annotations: {
1924
- title: 'Camera Reset',
1925
- readOnlyHint: false,
1926
- destructiveHint: false,
1927
- idempotentHint: false,
1928
- openWorldHint: false,
1929
- },
1930
- description: `Reset camera to default state (center of canvas, zoom 1).
1931
-
1932
- USE WHEN:
1933
- - Returning to default view after camera movements
1934
- - Resetting before starting new sequence`,
1935
- inputSchema: {
1936
- type: 'object',
1937
- properties: {
1938
- duration: { type: 'number', description: 'Animation duration in seconds (default: 0.5)' },
1939
- },
1940
- },
1941
- },
1942
- {
1943
- name: 'pinepaper_camera_stop',
1944
- annotations: {
1945
- title: 'Camera Stop',
1946
- readOnlyHint: false,
1947
- destructiveHint: false,
1948
- idempotentHint: true,
1949
- openWorldHint: false,
1950
- },
1951
- description: `Stop current camera animation.`,
1952
- inputSchema: {
1953
- type: 'object',
1954
- properties: {},
1955
- },
1956
- },
1957
- {
1958
- name: 'pinepaper_camera_state',
1959
- annotations: {
1960
- title: 'Camera State',
1961
- readOnlyHint: true,
1962
- destructiveHint: false,
1963
- idempotentHint: true,
1964
- openWorldHint: false,
1965
- },
1966
- description: `Get current camera state (zoom level, center position, animation status).`,
1967
- inputSchema: {
1968
- type: 'object',
1969
- properties: {},
2068
+ required: ['action'],
1970
2069
  },
1971
2070
  },
1972
2071
  // ---------------------------------------------------------------------------
@@ -2034,7 +2133,7 @@ EXAMPLE - Bouncing Balls:
2034
2133
  }
2035
2134
 
2036
2135
  SUPPORTED ITEM TYPES: text, circle, star, rectangle, triangle, polygon, ellipse, path, line, arc
2037
- SUPPORTED RELATIONS: orbits, follows, attached_to, maintains_distance, points_at, mirrors, parallax, bounds_to, animates, grows_from, staggered_with, indicates, circumscribes, wave_through, camera_follows, camera_animates, morphs_to
2136
+ SUPPORTED RELATIONS: orbits, follows, attached_to, maintains_distance, points_at, mirrors, parallax, bounds_to, animates, grows_from, staggered_with, indicates, circumscribes, wave_through, camera_follows, camera_animates, morphs_to, group_morphs_to, moves_along_path
2038
2137
  SUPPORTED ANIMATIONS: pulse, rotate, bounce, fade, wobble, slide, typewriter`,
2039
2138
  inputSchema: {
2040
2139
  type: 'object',
@@ -2080,7 +2179,7 @@ SUPPORTED ANIMATIONS: pulse, rotate, bounce, fade, wobble, slide, typewriter`,
2080
2179
  target: { type: 'string', description: 'Name of target item' },
2081
2180
  type: {
2082
2181
  type: 'string',
2083
- enum: ['orbits', 'follows', 'attached_to', 'maintains_distance', 'points_at', 'mirrors', 'parallax', 'bounds_to', 'animates', 'grows_from', 'staggered_with', 'indicates', 'circumscribes', 'wave_through', 'camera_follows', 'camera_animates', 'morphs_to'],
2182
+ enum: ['orbits', 'follows', 'attached_to', 'maintains_distance', 'points_at', 'mirrors', 'parallax', 'bounds_to', 'animates', 'grows_from', 'staggered_with', 'indicates', 'circumscribes', 'wave_through', 'camera_follows', 'camera_animates', 'morphs_to', 'group_morphs_to', 'moves_along_path'],
2084
2183
  },
2085
2184
  params: {
2086
2185
  type: 'object',
@@ -2492,38 +2591,6 @@ ACTIONS:
2492
2591
  required: ['action'],
2493
2592
  },
2494
2593
  },
2495
- {
2496
- name: 'pinepaper_view',
2497
- annotations: {
2498
- title: 'View',
2499
- readOnlyHint: false,
2500
- destructiveHint: false,
2501
- idempotentHint: false,
2502
- openWorldHint: false,
2503
- },
2504
- description: `View control — fit view to content or get current view state.
2505
-
2506
- ACTIONS:
2507
- - fit: Fit view to content or canvas bounds. Params: mode (content|canvas), padding (number)
2508
- - get_state: Get current view state (zoom, center, bounds)`,
2509
- inputSchema: {
2510
- type: 'object',
2511
- properties: {
2512
- action: {
2513
- type: 'string',
2514
- enum: ['fit', 'get_state'],
2515
- description: 'View action',
2516
- },
2517
- mode: {
2518
- type: 'string',
2519
- enum: ['content', 'canvas'],
2520
- description: 'Fit mode (for fit action)',
2521
- },
2522
- padding: { type: 'number', description: 'Padding around content in pixels (default: 20)' },
2523
- },
2524
- required: ['action'],
2525
- },
2526
- },
2527
2594
  {
2528
2595
  name: 'pinepaper_background',
2529
2596
  annotations: {
@@ -2596,94 +2663,291 @@ ACTIONS:
2596
2663
  },
2597
2664
  },
2598
2665
  // ---------------------------------------------------------------------------
2599
- // LAYER 5 — BLUEPRINTS: TEMPLATE TOOLS
2666
+ // DEFORMATION, SPRITE SHEETS, INTERACTION
2600
2667
  // ---------------------------------------------------------------------------
2601
2668
  {
2602
- name: 'pinepaper_apply_template',
2669
+ name: 'pinepaper_deform',
2603
2670
  annotations: {
2604
- title: 'Apply Template',
2671
+ title: 'Deformation',
2605
2672
  readOnlyHint: false,
2606
- destructiveHint: true,
2673
+ destructiveHint: false,
2607
2674
  idempotentHint: false,
2608
2675
  openWorldHint: false,
2609
2676
  },
2610
- description: `Load a pre-built template design onto the canvas, or list available templates.
2677
+ description: `Apply vertex deformation presets to items for organic motion effects.
2611
2678
 
2612
- USE WHEN:
2613
- - User wants to start from a pre-made design
2614
- - User asks for a template, preset, or starter layout
2615
- - User wants to see what templates are available
2616
- - Need a quick starting point for social media, presentations, etc.
2617
-
2618
- ⚠️ DESTRUCTIVE: Loading a template replaces the current canvas content.
2619
-
2620
- MODES:
2621
- 1. LIST MODE: Set listOnly: true (or omit templateId) to browse available templates
2622
- - Optionally filter by category
2623
- 2. LOAD MODE: Provide a templateId to apply that template
2679
+ ACTIONS:
2680
+ - apply: Apply looping deformation. Params: itemId, preset, frequency, amplitude (0-1), phase, loop, axis, turns, waves, maxDisplacement, speed, steps
2681
+ - trigger: One-shot deformation (auto-removes). Params: itemId, preset, amplitude, speed
2682
+ - remove: Restore original geometry. Params: itemId
2624
2683
 
2625
- TEMPLATE CATEGORIES (13):
2626
- - social-media: Social media post/story layouts
2627
- - meme: Meme templates and formats
2628
- - business: Business cards, letterheads, presentations
2629
- - education: Educational diagrams, worksheets
2630
- - creative: Artistic and creative compositions
2631
- - tech: Technology-themed designs
2632
- - global: International and multicultural designs
2633
- - indigenous: Indigenous art-inspired patterns
2634
- - seasonal: Holiday and seasonal themes
2635
- - masking: Mask reveal effect demonstrations
2636
- - scenes: Pre-built animated scenes
2637
- - diagrams: Flowchart and diagram starters
2638
- - maps: Geographic visualization templates
2684
+ PRESETS: fold, squeeze, squash, pinch, bulge, twist, ripple, wave, breathe, melt, shear, inflate, wobble
2639
2685
 
2640
- EXAMPLES:
2641
- - List all templates: { "listOnly": true }
2642
- - List by category: { "category": "social-media", "listOnly": true }
2643
- - Load template: { "templateId": "solar-system" }`,
2686
+ PHASES: sin, blink, linear, pingpong, once, elastic, heartbeat, stepped`,
2644
2687
  inputSchema: {
2645
2688
  type: 'object',
2646
2689
  properties: {
2647
- templateId: {
2690
+ action: {
2648
2691
  type: 'string',
2649
- description: 'Template ID to load (omit to list templates)',
2692
+ enum: ['apply', 'trigger', 'remove'],
2693
+ description: 'Deformation action',
2650
2694
  },
2651
- category: {
2695
+ itemId: { type: 'string', description: 'Target item ID' },
2696
+ preset: {
2652
2697
  type: 'string',
2653
- enum: ['social-media', 'meme', 'business', 'education', 'creative', 'tech', 'global', 'indigenous', 'seasonal', 'masking', 'scenes', 'diagrams', 'maps'],
2654
- description: 'Filter templates by category',
2698
+ enum: ['fold', 'squeeze', 'squash', 'pinch', 'bulge', 'twist', 'ripple', 'wave', 'breathe', 'melt', 'shear', 'inflate', 'wobble'],
2699
+ description: 'Deformation preset name',
2655
2700
  },
2656
- listOnly: {
2657
- type: 'boolean',
2658
- description: 'If true, only list available templates without loading (default: false)',
2701
+ frequency: { type: 'number', description: 'Oscillation speed (default: 1)' },
2702
+ amplitude: { type: 'number', description: 'Deformation strength 0-1 (default: 1)' },
2703
+ phase: {
2704
+ type: 'string',
2705
+ enum: ['sin', 'blink', 'linear', 'pingpong', 'once', 'elastic', 'heartbeat', 'stepped'],
2706
+ description: 'Phase driver for animation timing',
2659
2707
  },
2708
+ loop: { type: 'boolean', description: 'Loop the deformation (default: true)' },
2709
+ axis: { type: 'string', enum: ['horizontal', 'vertical'], description: 'Axis for fold/wave presets' },
2710
+ turns: { type: 'number', description: 'Rotation amount for twist preset' },
2711
+ waves: { type: 'number', description: 'Wave count for ripple/wave presets' },
2712
+ maxDisplacement: { type: 'number', description: 'Maximum displacement in pixels' },
2713
+ speed: { type: 'number', description: 'Animation speed multiplier' },
2714
+ steps: { type: 'number', description: 'Quantization levels for stepped phase' },
2660
2715
  },
2716
+ required: ['action'],
2661
2717
  },
2662
2718
  },
2663
- // ---------------------------------------------------------------------------
2664
- // DOMAIN: DIAGRAM TOOLS
2665
- // ---------------------------------------------------------------------------
2666
2719
  {
2667
- name: 'pinepaper_create_diagram_shape',
2720
+ name: 'pinepaper_sprite_sheet',
2668
2721
  annotations: {
2669
- title: 'Create Diagram Shape',
2722
+ title: 'Sprite Sheet',
2670
2723
  readOnlyHint: false,
2671
2724
  destructiveHint: false,
2672
2725
  idempotentHint: false,
2673
2726
  openWorldHint: false,
2674
2727
  },
2675
- description: `Create a diagram shape on the canvas. Diagram shapes are specialized shapes for flowcharts, UML diagrams, network diagrams, and similar technical drawings.
2676
-
2677
- USE WHEN:
2678
- - Creating flowcharts, process diagrams, or workflows
2679
- - Building UML class diagrams, use case diagrams, or sequence diagrams
2680
- - Designing network topology diagrams
2681
- - Making organizational charts or decision trees
2682
- - Any technical or architectural diagram
2683
-
2684
- SHAPE TYPES:
2728
+ description: `Generate, play, and export sprite sheets from skeleton poses.
2685
2729
 
2686
- Flowchart shapes:
2730
+ ACTIONS:
2731
+ - generate: Create sprite sheet from skeleton. Params: skeletonId, poses, transition, bakedAnimation, animations, padding, name
2732
+ - play: Play sprite animation on canvas. Params: spriteSheetId, x, y, animation, fps, scale
2733
+ - export: Export sprite sheet as image + metadata. Params: spriteSheetId, format (png|webp)`,
2734
+ inputSchema: {
2735
+ type: 'object',
2736
+ properties: {
2737
+ action: {
2738
+ type: 'string',
2739
+ enum: ['generate', 'play', 'export'],
2740
+ description: 'Sprite sheet action',
2741
+ },
2742
+ skeletonId: { type: 'string', description: 'Skeleton ID (for generate)' },
2743
+ spriteSheetId: { type: 'string', description: 'Sprite sheet ID (for play/export)' },
2744
+ name: { type: 'string', description: 'Sheet name' },
2745
+ poses: {
2746
+ type: 'array',
2747
+ items: { type: 'object', properties: { name: { type: 'string' }, poseId: { type: 'string' } }, required: ['name', 'poseId'] },
2748
+ description: 'Explicit pose list',
2749
+ },
2750
+ transition: {
2751
+ type: 'object',
2752
+ properties: { poseIdA: { type: 'string' }, poseIdB: { type: 'string' }, frameCount: { type: 'number' }, name: { type: 'string' } },
2753
+ description: 'Interpolate between two poses',
2754
+ },
2755
+ bakedAnimation: {
2756
+ type: 'object',
2757
+ properties: { duration: { type: 'number' }, fps: { type: 'number' }, name: { type: 'string' } },
2758
+ description: 'Bake timeline animation into frames',
2759
+ },
2760
+ animations: {
2761
+ type: 'object',
2762
+ additionalProperties: { type: 'object', properties: { frames: { type: 'array', items: { type: 'string' } }, fps: { type: 'number' }, loop: { type: 'boolean' } } },
2763
+ description: 'Animation definitions mapping name to frame sequences',
2764
+ },
2765
+ padding: { type: 'number', description: 'Padding between frames (default: 1)' },
2766
+ x: { type: 'number', description: 'X position for playback' },
2767
+ y: { type: 'number', description: 'Y position for playback' },
2768
+ animation: { type: 'string', description: 'Animation name to play' },
2769
+ fps: { type: 'number', description: 'Frame rate (default: 12)' },
2770
+ scale: { type: 'number', description: 'Scale factor (default: 1)' },
2771
+ format: { type: 'string', enum: ['png', 'webp'], description: 'Export format (default: png)' },
2772
+ },
2773
+ required: ['action'],
2774
+ },
2775
+ },
2776
+ {
2777
+ name: 'pinepaper_interaction',
2778
+ annotations: {
2779
+ title: 'Interaction',
2780
+ readOnlyHint: false,
2781
+ destructiveHint: false,
2782
+ idempotentHint: false,
2783
+ openWorldHint: false,
2784
+ },
2785
+ description: `Add continuous physics behaviors and trigger interaction actions.
2786
+
2787
+ ACTIONS:
2788
+ - add_behavior: Attach a continuous behavior. Params: itemId, behaviorType, params
2789
+ - remove_behavior: Remove a behavior. Params: itemId, behaviorId
2790
+ - trigger_action: Fire an interaction action. Params: actionType, params
2791
+ - get_state: Get interaction state (score, progress, step)
2792
+
2793
+ BEHAVIOR TYPES: repel, attract, follow, orbit, slingshot, physics_body, draggable_constrained
2794
+
2795
+ ACTION TYPES: navigate, show, hide, animate, stopAnimation, setState, incrementScore, playTimeline, pauseTimeline, seekTimeline, showFeedback, complete`,
2796
+ inputSchema: {
2797
+ type: 'object',
2798
+ properties: {
2799
+ action: {
2800
+ type: 'string',
2801
+ enum: ['add_behavior', 'remove_behavior', 'trigger_action', 'get_state'],
2802
+ description: 'Interaction action',
2803
+ },
2804
+ itemId: { type: 'string', description: 'Target item ID' },
2805
+ behaviorType: {
2806
+ type: 'string',
2807
+ enum: ['repel', 'attract', 'follow', 'orbit', 'slingshot', 'physics_body', 'draggable_constrained'],
2808
+ description: 'Continuous behavior type',
2809
+ },
2810
+ behaviorId: { type: 'string', description: 'Behavior ID (for remove_behavior)' },
2811
+ actionType: {
2812
+ type: 'string',
2813
+ enum: ['navigate', 'show', 'hide', 'animate', 'stopAnimation', 'setState', 'incrementScore', 'playTimeline', 'pauseTimeline', 'seekTimeline', 'showFeedback', 'complete'],
2814
+ description: 'Interaction action type (for trigger_action)',
2815
+ },
2816
+ params: {
2817
+ type: 'object',
2818
+ description: 'Action-specific or behavior-specific parameters',
2819
+ },
2820
+ },
2821
+ required: ['action'],
2822
+ },
2823
+ },
2824
+ // ---------------------------------------------------------------------------
2825
+ // WIDGET EXPORT
2826
+ // ---------------------------------------------------------------------------
2827
+ {
2828
+ name: 'pinepaper_export_widget',
2829
+ annotations: {
2830
+ title: 'Export Widget',
2831
+ readOnlyHint: true,
2832
+ destructiveHint: false,
2833
+ idempotentHint: true,
2834
+ openWorldHint: false,
2835
+ },
2836
+ description: `Export current scene as a PineWidget (pp:PinePaper ontology JSON v0.4.3).
2837
+
2838
+ Returns portable scene data with items, relations, animations, masks, and interactions serialized in the pp:PinePaper semantic format. Includes embed code snippet for external sites.
2839
+
2840
+ Params: download (bool), filename, includeInteractions (bool, default true), minify (bool)`,
2841
+ inputSchema: {
2842
+ type: 'object',
2843
+ properties: {
2844
+ download: { type: 'boolean', description: 'Trigger browser download (default: false)' },
2845
+ filename: { type: 'string', description: 'Output filename (default: widget-scene.json)' },
2846
+ includeInteractions: { type: 'boolean', description: 'Include interaction triggers (default: true)' },
2847
+ minify: { type: 'boolean', description: 'Minify JSON output (default: false)' },
2848
+ },
2849
+ },
2850
+ },
2851
+ {
2852
+ name: 'pinepaper_export_widget_html',
2853
+ annotations: {
2854
+ title: 'Export Widget HTML',
2855
+ readOnlyHint: true,
2856
+ destructiveHint: false,
2857
+ idempotentHint: true,
2858
+ openWorldHint: false,
2859
+ },
2860
+ description: `Export current scene as a self-contained HTML page with tree-shaken PineWidget runtime.
2861
+
2862
+ Generates a single HTML file (<20KB typical) with inline scene data and only the JavaScript code needed for the specific items, relations, and features used. No external dependencies.
2863
+
2864
+ Params: title (page title), download (bool)`,
2865
+ inputSchema: {
2866
+ type: 'object',
2867
+ properties: {
2868
+ title: { type: 'string', description: 'HTML page title (default: PinePaper Widget)' },
2869
+ download: { type: 'boolean', description: 'Trigger browser download (default: false)' },
2870
+ },
2871
+ },
2872
+ },
2873
+ // ---------------------------------------------------------------------------
2874
+ // DOMAIN: TEMPLATE TOOL
2875
+ // ---------------------------------------------------------------------------
2876
+ {
2877
+ name: 'pinepaper_apply_template',
2878
+ annotations: {
2879
+ title: 'Apply Template',
2880
+ readOnlyHint: false,
2881
+ destructiveHint: true,
2882
+ idempotentHint: false,
2883
+ openWorldHint: false,
2884
+ },
2885
+ description: `Load a pre-built template design onto the canvas, or list available templates.
2886
+
2887
+ USE WHEN:
2888
+ - User wants to start from a pre-made design
2889
+ - User asks for a template, preset, or starter layout
2890
+ - User wants to see what templates are available
2891
+ - Need a quick starting point for social media, presentations, etc.
2892
+
2893
+ ⚠️ DESTRUCTIVE: Loading a template replaces the current canvas content.
2894
+
2895
+ MODES:
2896
+ 1. LIST MODE: Set listOnly: true (or omit templateId) to browse available templates
2897
+ - Optionally filter by category
2898
+ 2. LOAD MODE: Provide a templateId to apply that template
2899
+
2900
+ TEMPLATE CATEGORIES (13):
2901
+ - social-media, meme, business, education, creative, tech, global,
2902
+ indigenous, seasonal, masking, scenes, diagrams, maps
2903
+
2904
+ EXAMPLES:
2905
+ - List all templates: { "listOnly": true }
2906
+ - List by category: { "category": "social-media", "listOnly": true }
2907
+ - Load template: { "templateId": "solar-system" }`,
2908
+ inputSchema: {
2909
+ type: 'object',
2910
+ properties: {
2911
+ templateId: {
2912
+ type: 'string',
2913
+ description: 'Template ID to load (omit to list templates)',
2914
+ },
2915
+ category: {
2916
+ type: 'string',
2917
+ enum: ['social-media', 'meme', 'business', 'education', 'creative', 'tech', 'global', 'indigenous', 'seasonal', 'masking', 'scenes', 'diagrams', 'maps'],
2918
+ description: 'Filter templates by category',
2919
+ },
2920
+ listOnly: {
2921
+ type: 'boolean',
2922
+ description: 'If true, only list available templates without loading (default: false)',
2923
+ },
2924
+ },
2925
+ },
2926
+ },
2927
+ // ---------------------------------------------------------------------------
2928
+ // DOMAIN: DIAGRAM TOOLS
2929
+ // ---------------------------------------------------------------------------
2930
+ {
2931
+ name: 'pinepaper_create_diagram_shape',
2932
+ annotations: {
2933
+ title: 'Create Diagram Shape',
2934
+ readOnlyHint: false,
2935
+ destructiveHint: false,
2936
+ idempotentHint: false,
2937
+ openWorldHint: false,
2938
+ },
2939
+ description: `Create a diagram shape on the canvas. Diagram shapes are specialized shapes for flowcharts, UML diagrams, network diagrams, and similar technical drawings.
2940
+
2941
+ USE WHEN:
2942
+ - Creating flowcharts, process diagrams, or workflows
2943
+ - Building UML class diagrams, use case diagrams, or sequence diagrams
2944
+ - Designing network topology diagrams
2945
+ - Making organizational charts or decision trees
2946
+ - Any technical or architectural diagram
2947
+
2948
+ SHAPE TYPES:
2949
+
2950
+ Flowchart shapes:
2687
2951
  - process: Rectangle for process steps (default: 120x60)
2688
2952
  - decision: Diamond for yes/no decisions (default: 100x100)
2689
2953
  - terminal: Rounded rectangle for start/end (default: 120x40)
@@ -3340,2209 +3604,614 @@ EXAMPLES:
3340
3604
  },
3341
3605
  },
3342
3606
  // ---------------------------------------------------------------------------
3343
- // DOMAIN: MAP TOOLS
3607
+ // DOMAIN: MAP TOOLS — four action-dispatched tools replace 23 wrappers
3344
3608
  // ---------------------------------------------------------------------------
3345
3609
  {
3346
- name: 'pinepaper_load_map',
3610
+ name: 'pinepaper_map',
3347
3611
  annotations: {
3348
- title: 'Load Map',
3612
+ title: 'Map: Load + Viewport',
3349
3613
  readOnlyHint: false,
3350
3614
  destructiveHint: false,
3351
3615
  idempotentHint: false,
3352
3616
  openWorldHint: false,
3353
3617
  },
3354
- description: `Load a geographic map onto the canvas with specified projection and styling.
3618
+ description: `Load a map and control its viewport. Call action: "load" first to set up; subsequent calls control pan / zoom / config import-export.
3355
3619
 
3356
- USE WHEN:
3357
- - Creating world maps or country visualizations
3358
- - Building choropleth data visualizations
3359
- - Making infographics with geographic data
3360
- - Creating animated map reveals
3361
-
3362
- AVAILABLE MAPS:
3363
- - world: World countries (110m resolution, faster)
3364
- - worldHighRes: World countries (50m resolution, more detailed)
3365
- - usa: US states map
3366
-
3367
- PROJECTIONS:
3368
- - naturalEarth: Natural Earth projection (recommended for world maps)
3369
- - mercator: Standard web mercator
3370
- - equalEarth: Equal-area projection
3371
- - orthographic: Globe/3D sphere view
3372
- - albers: Conic projection (good for USA)
3373
- - stereographic: Stereographic projection
3374
-
3375
- QUALITY SETTINGS:
3376
- - fast: Aggressive simplification (prototyping)
3377
- - balanced: Moderate detail (most uses)
3378
- - professional: No simplification (publications)
3379
-
3380
- EXAMPLES:
3381
- - World map: {mapId: "world", projection: "naturalEarth", quality: "balanced"}
3382
- - USA map: {mapId: "usa", projection: "albers", quality: "professional"}
3383
- - Globe view: {mapId: "worldHighRes", projection: "orthographic", rotate: [0, -30, 0]}
3620
+ ACTIONS:
3621
+ - load — { mapId: "usa"|"world"|"worldHighRes"|<custom>, projection?, options? }
3622
+ - pan — { lat, lon, duration? }
3623
+ - zoom — { level, duration? }
3624
+ - export_config — {}
3625
+ - import_custom — { url? | geojson?, projection? }
3384
3626
 
3385
- RETURNS:
3386
- - mapId: Reference ID for the loaded map
3387
- - group: Paper.js group containing all regions
3388
- - regions: Array of region info
3389
- - bounds: Map bounding box`,
3627
+ For region styling/selection use pinepaper_map_regions; for animations use pinepaper_map_animation; for CSV/GeoJSON/source-info use pinepaper_map_data.`,
3390
3628
  inputSchema: {
3391
3629
  type: 'object',
3392
3630
  properties: {
3393
- mapId: {
3394
- type: 'string',
3395
- enum: ['world', 'worldHighRes', 'usa'],
3396
- description: 'Map to load (world=110m, worldHighRes=50m professional quality, usa=US states)',
3397
- },
3398
- projection: {
3399
- type: 'string',
3400
- enum: ['mercator', 'equalEarth', 'naturalEarth', 'orthographic', 'albers', 'stereographic'],
3401
- description: 'Map projection type',
3402
- },
3403
- quality: {
3404
- type: 'string',
3405
- enum: ['fast', 'balanced', 'professional'],
3406
- description: 'Rendering quality (professional=no simplification)',
3407
- },
3408
- fillColor: { type: 'string', description: 'Default fill color for regions' },
3409
- strokeColor: { type: 'string', description: 'Border/stroke color' },
3410
- strokeWidth: { type: 'number', description: 'Border width in pixels' },
3411
- scale: { type: 'number', description: 'Scale multiplier' },
3412
- center: {
3413
- type: 'array',
3414
- items: { type: 'number' },
3415
- description: 'Center coordinates [longitude, latitude]',
3416
- },
3417
- rotate: {
3418
- type: 'array',
3419
- items: { type: 'number' },
3420
- description: 'Rotation angles [x, y, z]',
3421
- },
3422
- enableHover: { type: 'boolean', description: 'Enable hover effects on regions' },
3423
- enableClick: { type: 'boolean', description: 'Enable click events on regions' },
3424
- hoverFill: { type: 'string', description: 'Fill color on hover' },
3425
- hoverStroke: { type: 'string', description: 'Stroke color on hover' },
3631
+ action: { type: 'string', enum: ['load', 'pan', 'zoom', 'export_config', 'import_custom'], description: 'Map action' },
3632
+ mapId: { type: 'string', description: 'Map identifier (load)' },
3633
+ projection: { type: 'string', description: 'Projection (load / import_custom)' },
3634
+ options: { type: 'object', description: 'Map options (load)', additionalProperties: true },
3635
+ lat: { type: 'number', description: 'Latitude (pan)' },
3636
+ lon: { type: 'number', description: 'Longitude (pan)' },
3637
+ level: { type: 'number', description: 'Zoom level (zoom)' },
3638
+ duration: { type: 'number', description: 'Animation duration (pan, zoom; default 0.5)' },
3639
+ url: { type: 'string', description: 'GeoJSON/TopoJSON URL (import_custom)' },
3640
+ geojson: { type: 'object', description: 'Inline GeoJSON (import_custom)' },
3426
3641
  },
3427
- required: ['mapId'],
3642
+ required: ['action'],
3428
3643
  },
3429
3644
  },
3430
3645
  {
3431
- name: 'pinepaper_highlight_regions',
3646
+ name: 'pinepaper_map_regions',
3432
3647
  annotations: {
3433
- title: 'Highlight Regions',
3648
+ title: 'Map: Region Styling + Selection',
3434
3649
  readOnlyHint: false,
3435
3650
  destructiveHint: false,
3436
- idempotentHint: true,
3651
+ idempotentHint: false,
3437
3652
  openWorldHint: false,
3438
3653
  },
3439
- description: `Highlight specific regions on a loaded map with custom styling.
3440
-
3441
- USE WHEN:
3442
- - Emphasizing specific countries or states
3443
- - Creating interactive map highlights
3444
- - Building step-by-step map reveals
3445
- - Showing geographic data points
3654
+ description: `Highlight, color, label, and select map regions. Requires a map loaded via pinepaper_map { action: "load" } first.
3446
3655
 
3447
- REGION ID FORMATS:
3448
- - World maps: Full country names ("United States of America", "France", "Japan")
3449
- - USA map: State codes ("CA", "TX", "NY", "FL")
3450
-
3451
- STYLING OPTIONS:
3452
- - fillColor: Highlight fill color
3453
- - strokeColor: Highlight stroke color
3454
- - strokeWidth: Border width for highlighted regions
3455
- - animate: Whether to animate the highlight transition
3456
-
3457
- EXAMPLES:
3458
- - Highlight countries: {regionIds: ["United States of America", "Canada", "Mexico"], options: {fillColor: "#3b82f6"}}
3459
- - Highlight US states: {regionIds: ["CA", "TX", "NY"], options: {fillColor: "#22c55e", animate: true}}
3460
- - Custom styling: {regionIds: ["Japan"], options: {fillColor: "#ef4444", strokeColor: "#dc2626", strokeWidth: 2}}`,
3656
+ ACTIONS:
3657
+ - highlight — { regionIds: string[], color?, opacity? }
3658
+ - unhighlight — { regionIds?: string[] } omit to clear all
3659
+ - apply_colors — { data: Record<regionId, value>, options? } choropleth coloring
3660
+ - add_marker — { lat, lon, label?, color?, size? }
3661
+ - add_labels — { regions?: string[], style?, formatter? }
3662
+ - get_at_point — { x, y } region at canvas coords
3663
+ - select — { regionIds: string[] }
3664
+ - deselect — { regionIds?: string[] } omit to deselect all
3665
+ - get_highlighted — {}`,
3461
3666
  inputSchema: {
3462
3667
  type: 'object',
3463
3668
  properties: {
3464
- regionIds: {
3465
- type: 'array',
3466
- items: { type: 'string' },
3467
- description: 'Array of region IDs to highlight (country names or state codes)',
3468
- },
3469
- options: {
3470
- type: 'object',
3471
- properties: {
3472
- fillColor: { type: 'string', description: 'Highlight fill color' },
3473
- strokeColor: { type: 'string', description: 'Highlight stroke color' },
3474
- strokeWidth: { type: 'number', description: 'Highlight stroke width' },
3475
- animate: { type: 'boolean', description: 'Animate the highlight transition' },
3476
- },
3477
- description: 'Highlight styling options',
3478
- },
3669
+ action: { type: 'string', enum: ['highlight', 'unhighlight', 'apply_colors', 'add_marker', 'add_labels', 'get_at_point', 'select', 'deselect', 'get_highlighted'], description: 'Region action' },
3670
+ regionIds: { type: 'array', items: { type: 'string' } },
3671
+ color: { type: 'string' },
3672
+ opacity: { type: 'number' },
3673
+ data: { type: 'object', description: 'Region → value (apply_colors)', additionalProperties: true },
3674
+ options: { type: 'object', additionalProperties: true },
3675
+ lat: { type: 'number' },
3676
+ lon: { type: 'number' },
3677
+ label: { type: 'string' },
3678
+ size: { type: 'number' },
3679
+ regions: { type: 'array', items: { type: 'string' } },
3680
+ style: { type: 'object', additionalProperties: true },
3681
+ formatter: { type: 'string' },
3682
+ x: { type: 'number' },
3683
+ y: { type: 'number' },
3479
3684
  },
3480
- required: ['regionIds'],
3685
+ required: ['action'],
3481
3686
  },
3482
3687
  },
3483
3688
  {
3484
- name: 'pinepaper_unhighlight_regions',
3689
+ name: 'pinepaper_map_animation',
3485
3690
  annotations: {
3486
- title: 'Unhighlight Regions',
3691
+ title: 'Map: Region Animations',
3487
3692
  readOnlyHint: false,
3488
3693
  destructiveHint: false,
3489
- idempotentHint: true,
3694
+ idempotentHint: false,
3490
3695
  openWorldHint: false,
3491
3696
  },
3492
- description: `Remove highlights from specific regions or all regions on the map.
3493
-
3494
- USE WHEN:
3495
- - Resetting map to original state
3496
- - Removing specific region highlights
3497
- - Cycling through different highlight states
3697
+ description: `Animate map regions with keyframes or wave effects.
3498
3698
 
3499
- EXAMPLES:
3500
- - Remove all highlights: {regionIds: "all"}
3501
- - Remove specific: {regionIds: ["CA", "TX"]}`,
3699
+ ACTIONS:
3700
+ - animate_regions — { regions: Record<regionId, keyframes[]>, duration?, loop? }
3701
+ - animate_wave — { regions?: string[], waveDirection?, speed?, color?, duration?, loop? }
3702
+ - stop — { regionIds?: string[] }
3703
+ - get_animated — {}`,
3502
3704
  inputSchema: {
3503
3705
  type: 'object',
3504
3706
  properties: {
3505
- regionIds: {
3506
- oneOf: [
3507
- { type: 'array', items: { type: 'string' } },
3508
- { type: 'string', enum: ['all'] },
3509
- ],
3510
- description: 'Region IDs to unhighlight, or "all" for all regions',
3511
- },
3707
+ action: { type: 'string', enum: ['animate_regions', 'animate_wave', 'stop', 'get_animated'], description: 'Animation action' },
3708
+ regions: { type: 'object', description: 'Keyframes per region (animate_regions) or list (animate_wave)', additionalProperties: true },
3709
+ regionIds: { type: 'array', items: { type: 'string' } },
3710
+ waveDirection: { type: 'string', enum: ['horizontal', 'vertical', 'radial'] },
3711
+ speed: { type: 'number' },
3712
+ color: { type: 'string' },
3713
+ duration: { type: 'number' },
3714
+ loop: { type: 'boolean' },
3512
3715
  },
3513
- required: ['regionIds'],
3716
+ required: ['action'],
3514
3717
  },
3515
3718
  },
3516
3719
  {
3517
- name: 'pinepaper_apply_data_colors',
3720
+ name: 'pinepaper_map_data',
3518
3721
  annotations: {
3519
- title: 'Apply Data Colors',
3722
+ title: 'Map: Data Import + Export',
3520
3723
  readOnlyHint: false,
3521
3724
  destructiveHint: false,
3522
3725
  idempotentHint: true,
3523
3726
  openWorldHint: false,
3524
3727
  },
3525
- description: `Apply data-driven coloring to map regions (choropleth visualization).
3526
-
3527
- USE WHEN:
3528
- - Visualizing statistics by region (population, GDP, etc.)
3529
- - Creating heat maps
3530
- - Showing data distribution across geography
3531
- - Building infographics with data overlays
3532
-
3533
- COLOR SCALES:
3534
- - blues: Light to dark blue gradient
3535
- - greens: Light to dark green gradient
3536
- - reds: Light to dark red gradient
3537
- - oranges: Light to dark orange gradient
3538
- - purples: Light to dark purple gradient
3539
- - heat: Yellow to red heat map gradient
3540
-
3541
- DATA FORMAT:
3542
- Keys must match region IDs exactly (country names for world maps, state codes for USA).
3728
+ description: `CSV / GeoJSON import-export and source-info introspection.
3543
3729
 
3544
- EXAMPLES:
3545
- - Population data: {data: {"California": 39538223, "Texas": 29145505, "New York": 20201249}, options: {colorScale: "blues", showLegend: true}}
3546
- - GDP heat map: {data: {"United States of America": 21000, "China": 15000, "Japan": 5000}, options: {colorScale: "heat"}}
3547
- - Custom range: {data: {"CA": 85, "TX": 72}, options: {colorScale: "greens", minValue: 0, maxValue: 100}}`,
3730
+ ACTIONS:
3731
+ - export_csv — { regionIds?, columns?, download?, filename? }
3732
+ - import_csv — { csv: string, mapping?: { region?, value?, color? } }
3733
+ - export_geojson — { includeStyles?, includeMetadata?, selectedOnly?, download?, filename? }
3734
+ - export_original_geojson — { download?, filename? } source GeoJSON before styling
3735
+ - source_info — {} { source, projection, quality, regionCount, hasOriginalGeoJSON, isCustomImport }`,
3548
3736
  inputSchema: {
3549
3737
  type: 'object',
3550
3738
  properties: {
3551
- data: {
3552
- type: 'object',
3553
- additionalProperties: { type: 'number' },
3554
- description: 'Object mapping region IDs to numeric values',
3555
- },
3556
- options: {
3557
- type: 'object',
3558
- properties: {
3559
- colorScale: {
3560
- type: 'string',
3561
- enum: ['blues', 'greens', 'reds', 'oranges', 'purples', 'heat'],
3562
- description: 'Color scale to use',
3563
- },
3564
- minValue: { type: 'number', description: 'Minimum value for scale' },
3565
- maxValue: { type: 'number', description: 'Maximum value for scale' },
3566
- showLegend: { type: 'boolean', description: 'Display color legend' },
3567
- legendPosition: {
3568
- type: 'string',
3569
- enum: ['top-left', 'top-right', 'bottom-left', 'bottom-right'],
3570
- description: 'Legend position',
3571
- },
3572
- legendTitle: { type: 'string', description: 'Title for the legend' },
3573
- },
3574
- description: 'Choropleth styling options',
3575
- },
3739
+ action: { type: 'string', enum: ['export_csv', 'import_csv', 'export_geojson', 'export_original_geojson', 'source_info'], description: 'Data action' },
3740
+ regionIds: { type: 'array', items: { type: 'string' } },
3741
+ columns: { type: 'array', items: { type: 'string' } },
3742
+ csv: { type: 'string' },
3743
+ mapping: { type: 'object', additionalProperties: true },
3744
+ includeStyles: { type: 'boolean' },
3745
+ includeMetadata: { type: 'boolean' },
3746
+ selectedOnly: { type: 'boolean' },
3747
+ download: { type: 'boolean' },
3748
+ filename: { type: 'string' },
3576
3749
  },
3577
- required: ['data'],
3750
+ required: ['action'],
3578
3751
  },
3579
3752
  },
3753
+ // ---------------------------------------------------------------------------
3754
+ // DOMAIN: FONT TOOLS — single action-dispatched tool replaces 16 wrappers
3755
+ // ---------------------------------------------------------------------------
3580
3756
  {
3581
- name: 'pinepaper_add_marker',
3757
+ name: 'pinepaper_font',
3582
3758
  annotations: {
3583
- title: 'Add Map Marker',
3759
+ title: 'Font Studio',
3584
3760
  readOnlyHint: false,
3585
3761
  destructiveHint: false,
3586
3762
  idempotentHint: false,
3587
3763
  openWorldHint: false,
3588
3764
  },
3589
- description: `Add a marker to the map at specified coordinates.
3590
-
3591
- USE WHEN:
3592
- - Marking cities or points of interest
3593
- - Creating location-based visualizations
3594
- - Adding data points with geographic coordinates
3595
- - Building interactive map annotations
3596
-
3597
- MARKER OPTIONS:
3598
- - lat, lon: Geographic coordinates (required)
3599
- - label: Text label for the marker
3600
- - color: Marker color
3601
- - size: Marker size in pixels
3602
- - pulse: Enable animated pulse effect
3603
- - shape: Marker shape (circle, pin, star)
3765
+ description: `Font Studio control — single action-dispatched tool covering the full Studio API. Sixteen previous thin wrappers collapse into this one entry to reduce the tool list footprint without losing capability.
3604
3766
 
3605
- EXAMPLES:
3606
- - City marker: {lat: 37.7749, lon: -122.4194, label: "San Francisco", color: "#ef4444", pulse: true}
3607
- - Simple point: {lat: 40.7128, lon: -74.0060, size: 8, color: "#3b82f6"}
3608
- - Pin marker: {lat: 51.5074, lon: -0.1278, label: "London", shape: "pin"}`,
3767
+ ACTIONS:
3768
+ - show_studio — {} open the Font Studio UI
3769
+ - set_name — { name } name the in-progress font
3770
+ - get_required_chars — { set?: string } list chars to draw (default: minimum)
3771
+ - get_status — {} completion status
3772
+ - create_glyph — { character, pathId } attach a path as a glyph
3773
+ - create_space — { width? } create a space glyph
3774
+ - remove_glyph — { character }
3775
+ - set_metrics — { metrics: { unitsPerEm?, ascender?, descender?, xHeight?, capHeight? } } (or top-level keys)
3776
+ - export — { download?: boolean } export as OTF
3777
+ - load_into_document — {} load the font for use in this canvas
3778
+ - export_data — { download?: boolean } export as JSON
3779
+ - import_data — { data: object } import from JSON
3780
+ - clear — {} reset everything
3781
+ - remove_overlap — { pathId } path cleanup
3782
+ - correct_direction — { pathId } path cleanup
3783
+ - cleanup_path — { pathId, removeOverlap?, correctDirection?, smooth?, smoothTolerance? }`,
3609
3784
  inputSchema: {
3610
3785
  type: 'object',
3611
3786
  properties: {
3612
- lat: { type: 'number', description: 'Latitude' },
3613
- lon: { type: 'number', description: 'Longitude' },
3614
- label: { type: 'string', description: 'Marker label text' },
3615
- color: { type: 'string', description: 'Marker color' },
3616
- size: { type: 'number', description: 'Marker size in pixels' },
3617
- pulse: { type: 'boolean', description: 'Enable pulse animation' },
3618
- shape: {
3787
+ action: {
3619
3788
  type: 'string',
3620
- enum: ['circle', 'pin', 'star'],
3621
- description: 'Marker shape',
3789
+ enum: [
3790
+ 'show_studio', 'set_name', 'get_required_chars', 'get_status',
3791
+ 'create_glyph', 'create_space', 'remove_glyph', 'set_metrics',
3792
+ 'export', 'load_into_document', 'export_data', 'import_data',
3793
+ 'clear', 'remove_overlap', 'correct_direction', 'cleanup_path',
3794
+ ],
3795
+ description: 'Font Studio action',
3796
+ },
3797
+ name: { type: 'string', description: 'Font name (set_name)' },
3798
+ set: { type: 'string', description: 'Character set name (get_required_chars; default "minimum")' },
3799
+ character: { type: 'string', description: 'Single-character glyph identifier (create_glyph, remove_glyph)' },
3800
+ pathId: { type: 'string', description: 'Item id of the path source (create_glyph, remove_overlap, correct_direction, cleanup_path)' },
3801
+ width: { type: 'number', description: 'Space-glyph width (create_space)' },
3802
+ download: { type: 'boolean', description: 'Trigger browser download (export, export_data); default true' },
3803
+ metrics: {
3804
+ type: 'object',
3805
+ description: 'Font metrics (set_metrics)',
3806
+ properties: {
3807
+ unitsPerEm: { type: 'number' },
3808
+ ascender: { type: 'number' },
3809
+ descender: { type: 'number' },
3810
+ xHeight: { type: 'number' },
3811
+ capHeight: { type: 'number' },
3812
+ },
3622
3813
  },
3814
+ data: { type: 'object', description: 'Font JSON payload (import_data)' },
3815
+ removeOverlap: { type: 'boolean', description: 'cleanup_path option' },
3816
+ correctDirection: { type: 'boolean', description: 'cleanup_path option' },
3817
+ smooth: { type: 'boolean', description: 'cleanup_path option (default true)' },
3818
+ smoothTolerance: { type: 'number', description: 'cleanup_path tolerance (default 2.5)' },
3623
3819
  },
3624
- required: ['lat', 'lon'],
3820
+ required: ['action'],
3625
3821
  },
3626
3822
  },
3823
+ // ---------------------------------------------------------------------------
3824
+ // DOMAIN: LETTER COLLAGE TOOLS (Text Design)
3825
+ // ---------------------------------------------------------------------------
3627
3826
  {
3628
- name: 'pinepaper_add_map_labels',
3827
+ name: 'pinepaper_create_letter_collage',
3629
3828
  annotations: {
3630
- title: 'Add Map Labels',
3829
+ title: 'Create Letter Collage',
3631
3830
  readOnlyHint: false,
3632
3831
  destructiveHint: false,
3633
- idempotentHint: true,
3832
+ idempotentHint: false,
3634
3833
  openWorldHint: false,
3635
3834
  },
3636
- description: `Add text labels to map regions.
3835
+ description: `Create stylized text with per-letter customization. Perfect for word games, ransom notes, gradient text, and creative typography.
3637
3836
 
3638
3837
  USE WHEN:
3639
- - Labeling countries or states
3640
- - Adding region names to visualizations
3641
- - Creating annotated maps
3642
- - Showing data values on regions
3838
+ - Creating Wordle-style word displays
3839
+ - Making magazine cutout/ransom note text
3840
+ - Designing gradient-filled text
3841
+ - Building creative typography effects
3842
+ - Creating paper craft style lettering
3643
3843
 
3644
- LABEL TYPES:
3645
- - name: Full region name
3646
- - code: Region code (e.g., "CA" for California)
3647
- - value: Data value (if applyDataColors was used)
3844
+ STYLE TYPES:
3845
+ - tile: Wordle/Scrabble colored backgrounds (use with tile palettes)
3846
+ - magazine: Mixed fonts/colors like cutouts
3847
+ - paperCut: Shadow/depth like cut paper
3848
+ - fold: Origami-style folded letters
3849
+ - gradient: Each letter with gradient fill (use with gradient palettes)
3850
+ - image: Letters filled with image
3648
3851
 
3649
- EXAMPLES:
3650
- - Label all visible: {options: {fontSize: 10, fontColor: "#374151"}}
3651
- - Label specific regions: {regions: ["California", "Texas"], options: {labelType: "code"}}
3652
- - Show data values: {options: {labelType: "value", fontSize: 12}}`,
3653
- inputSchema: {
3654
- type: 'object',
3655
- properties: {
3656
- regions: {
3657
- type: 'array',
3658
- items: { type: 'string' },
3659
- description: 'Specific regions to label (null for all visible)',
3660
- },
3661
- options: {
3662
- type: 'object',
3663
- properties: {
3664
- fontSize: { type: 'number', description: 'Label font size' },
3665
- fontColor: { type: 'string', description: 'Label text color' },
3666
- labelType: {
3667
- type: 'string',
3668
- enum: ['name', 'code', 'value'],
3669
- description: 'Type of label content',
3670
- },
3671
- backgroundColor: { type: 'string', description: 'Label background color' },
3672
- },
3673
- description: 'Label styling options',
3674
- },
3675
- },
3676
- },
3677
- },
3678
- {
3679
- name: 'pinepaper_pan_map',
3680
- annotations: {
3681
- title: 'Pan Map',
3682
- readOnlyHint: false,
3683
- destructiveHint: false,
3684
- idempotentHint: true,
3685
- openWorldHint: false,
3686
- },
3687
- description: `Pan the map view to center on specific coordinates.
3688
-
3689
- USE WHEN:
3690
- - Navigating to a specific location
3691
- - Creating animated map transitions
3692
- - Focusing on a region of interest
3693
-
3694
- EXAMPLES:
3695
- - Pan to New York: {lat: 40.7128, lon: -74.0060}
3696
- - Pan to Europe: {lat: 50, lon: 10}`,
3697
- inputSchema: {
3698
- type: 'object',
3699
- properties: {
3700
- lat: { type: 'number', description: 'Target latitude' },
3701
- lon: { type: 'number', description: 'Target longitude' },
3702
- animate: { type: 'boolean', description: 'Animate the pan transition' },
3703
- duration: { type: 'number', description: 'Animation duration in seconds' },
3704
- },
3705
- required: ['lat', 'lon'],
3706
- },
3707
- },
3708
- {
3709
- name: 'pinepaper_zoom_map',
3710
- annotations: {
3711
- title: 'Zoom Map',
3712
- readOnlyHint: false,
3713
- destructiveHint: false,
3714
- idempotentHint: true,
3715
- openWorldHint: false,
3716
- },
3717
- description: `Set the map zoom level.
3718
-
3719
- USE WHEN:
3720
- - Zooming in on specific areas
3721
- - Creating zoom animations
3722
- - Adjusting map scale
3723
-
3724
- ZOOM LEVELS:
3725
- - 1: Full view (default)
3726
- - 2-5: Moderate zoom
3727
- - 5+: Close-up view
3728
-
3729
- EXAMPLES:
3730
- - Zoom in: {level: 2}
3731
- - Animated zoom: {level: 3, animate: true, duration: 1}`,
3732
- inputSchema: {
3733
- type: 'object',
3734
- properties: {
3735
- level: { type: 'number', description: 'Zoom level (1 = full view)' },
3736
- animate: { type: 'boolean', description: 'Animate the zoom transition' },
3737
- duration: { type: 'number', description: 'Animation duration in seconds' },
3738
- },
3739
- required: ['level'],
3740
- },
3741
- },
3742
- {
3743
- name: 'pinepaper_export_map',
3744
- annotations: {
3745
- title: 'Export Map',
3746
- readOnlyHint: true,
3747
- destructiveHint: false,
3748
- idempotentHint: true,
3749
- openWorldHint: false,
3750
- },
3751
- description: `Export the current map configuration and state.
3752
-
3753
- USE WHEN:
3754
- - Saving map state for later restoration
3755
- - Exporting map data for external use
3756
- - Creating shareable map configurations
3757
-
3758
- RETURNS:
3759
- - mapId: Current map identifier
3760
- - projection: Active projection
3761
- - regions: Region states and highlights
3762
- - markers: All added markers
3763
- - dataColors: Applied data coloring configuration`,
3764
- inputSchema: {
3765
- type: 'object',
3766
- properties: {},
3767
- },
3768
- },
3769
- {
3770
- name: 'pinepaper_import_custom_map',
3771
- annotations: {
3772
- title: 'Import Custom Map',
3773
- readOnlyHint: false,
3774
- destructiveHint: false,
3775
- idempotentHint: false,
3776
- openWorldHint: true,
3777
- },
3778
- description: `Import a custom GeoJSON or TopoJSON map.
3779
-
3780
- USE WHEN:
3781
- - Loading custom geographic boundaries
3782
- - Using detailed country/region maps from GADM
3783
- - Importing custom shapes or territories
3784
- - Working with non-standard geographic data
3785
-
3786
- SUPPORTED FORMATS:
3787
- - GeoJSON: Standard geographic JSON format
3788
- - TopoJSON: Compressed topology format
3789
-
3790
- SOURCES:
3791
- - GADM: Detailed country subdivisions (gadm.org)
3792
- - Natural Earth: Public domain maps (naturalearthdata.com)
3793
- - Census: Official boundary files
3794
- - Custom: Your own GeoJSON files
3795
-
3796
- EXAMPLES:
3797
- - Import from URL: {url: "https://example.com/custom.geojson", options: {projection: "mercator"}}
3798
- - Import GeoJSON object: {geoJson: {...}, options: {projection: "naturalEarth"}}`,
3799
- inputSchema: {
3800
- type: 'object',
3801
- properties: {
3802
- url: { type: 'string', description: 'URL to GeoJSON/TopoJSON file' },
3803
- geoJson: {
3804
- type: 'object',
3805
- description: 'GeoJSON object to import directly',
3806
- },
3807
- options: {
3808
- type: 'object',
3809
- properties: {
3810
- projection: {
3811
- type: 'string',
3812
- enum: ['mercator', 'equalEarth', 'naturalEarth', 'orthographic', 'albers', 'stereographic'],
3813
- description: 'Projection to use for rendering',
3814
- },
3815
- fillColor: { type: 'string' },
3816
- strokeColor: { type: 'string' },
3817
- strokeWidth: { type: 'number' },
3818
- },
3819
- description: 'Import options',
3820
- },
3821
- },
3822
- },
3823
- },
3824
- {
3825
- name: 'pinepaper_get_region_at_point',
3826
- annotations: {
3827
- title: 'Get Region at Point',
3828
- readOnlyHint: true,
3829
- destructiveHint: false,
3830
- idempotentHint: true,
3831
- openWorldHint: false,
3832
- },
3833
- description: `[Utility] Get the region at a specific canvas point (hit testing).
3834
-
3835
- USE WHEN:
3836
- - Implementing click interactions
3837
- - Finding which region is at a coordinate
3838
- - Building interactive map features
3839
-
3840
- EXAMPLES:
3841
- - Check point: {x: 400, y: 300}
3842
-
3843
- RETURNS:
3844
- - regionId: ID of the region at point (or null)
3845
- - regionName: Display name
3846
- - properties: Region properties from GeoJSON`,
3847
- inputSchema: {
3848
- type: 'object',
3849
- properties: {
3850
- x: { type: 'number', description: 'Canvas X coordinate' },
3851
- y: { type: 'number', description: 'Canvas Y coordinate' },
3852
- },
3853
- required: ['x', 'y'],
3854
- },
3855
- },
3856
- {
3857
- name: 'pinepaper_animate_map_regions',
3858
- annotations: {
3859
- title: 'Animate Map Regions',
3860
- readOnlyHint: false,
3861
- destructiveHint: false,
3862
- idempotentHint: false,
3863
- openWorldHint: false,
3864
- },
3865
- description: `Animate specific map regions with timeline-integrated keyframe color animations.
3866
-
3867
- USE WHEN:
3868
- - Creating animated choropleth transitions
3869
- - Showing data changes over time
3870
- - Building story-based map visualizations
3871
- - Adding visual emphasis to regions
3872
-
3873
- KEYFRAME PROPERTIES:
3874
- - time: Time in seconds for this keyframe
3875
- - fillColor: Fill color at this keyframe (required)
3876
- - strokeColor: Optional stroke color
3877
- - opacity: Optional opacity (0-1)
3878
-
3879
- EXAMPLES:
3880
- - Simple color transition: {duration: 5, loop: true, regions: {"USA": [{"time": 0, "fillColor": "#ef4444"}, {"time": 5, "fillColor": "#22c55e"}]}}
3881
- - Multi-region animation: {duration: 8, regions: {"USA": [...], "France": [...], "Japan": [...]}}`,
3882
- inputSchema: {
3883
- type: 'object',
3884
- properties: {
3885
- duration: {
3886
- type: 'number',
3887
- description: 'Total animation duration in seconds (default: 5)',
3888
- },
3889
- loop: {
3890
- type: 'boolean',
3891
- description: 'Loop the animation (default: true)',
3892
- },
3893
- regions: {
3894
- type: 'object',
3895
- additionalProperties: {
3896
- type: 'array',
3897
- items: {
3898
- type: 'object',
3899
- properties: {
3900
- time: { type: 'number', description: 'Time in seconds' },
3901
- fillColor: { type: 'string', description: 'Fill color at this keyframe' },
3902
- strokeColor: { type: 'string', description: 'Stroke color (optional)' },
3903
- opacity: { type: 'number', description: 'Opacity 0-1 (optional)' },
3904
- },
3905
- required: ['time', 'fillColor'],
3906
- },
3907
- },
3908
- description: 'Object mapping region IDs to arrays of keyframes',
3909
- },
3910
- },
3911
- required: ['regions'],
3912
- },
3913
- },
3914
- {
3915
- name: 'pinepaper_animate_map_wave',
3916
- annotations: {
3917
- title: 'Animate Map Wave',
3918
- readOnlyHint: false,
3919
- destructiveHint: false,
3920
- idempotentHint: false,
3921
- openWorldHint: false,
3922
- },
3923
- description: `Create a wave animation across all map regions based on geographic position.
3924
-
3925
- USE WHEN:
3926
- - Creating dramatic visual effects
3927
- - Showing global spread patterns
3928
- - Adding ambient map animations
3929
- - Building attention-grabbing transitions
3930
-
3931
- WAVE DIRECTIONS:
3932
- - horizontal: Wave sweeps left to right
3933
- - vertical: Wave sweeps top to bottom
3934
- - radial: Wave radiates from center outward
3935
-
3936
- EXAMPLES:
3937
- - Rainbow wave: {duration: 10, colors: ["#ef4444", "#fbbf24", "#22c55e", "#3b82f6"], waveDirection: "horizontal"}
3938
- - Fast radial pulse: {duration: 3, colors: ["#ffffff", "#3b82f6"], waveDirection: "radial", loop: true}`,
3939
- inputSchema: {
3940
- type: 'object',
3941
- properties: {
3942
- duration: {
3943
- type: 'number',
3944
- description: 'Total wave duration in seconds (default: 10)',
3945
- },
3946
- loop: {
3947
- type: 'boolean',
3948
- description: 'Loop the animation (default: true)',
3949
- },
3950
- colors: {
3951
- type: 'array',
3952
- items: { type: 'string' },
3953
- description: 'Array of colors for the wave (default: red, yellow, green, blue)',
3954
- },
3955
- waveDirection: {
3956
- type: 'string',
3957
- enum: ['horizontal', 'vertical', 'radial'],
3958
- description: 'Direction of the wave effect (default: horizontal)',
3959
- },
3960
- },
3961
- },
3962
- },
3963
- {
3964
- name: 'pinepaper_stop_map_animations',
3965
- annotations: {
3966
- title: 'Stop Map Animations',
3967
- readOnlyHint: false,
3968
- destructiveHint: false,
3969
- idempotentHint: true,
3970
- openWorldHint: false,
3971
- },
3972
- description: `Stop all or specific map region animations.
3973
-
3974
- USE WHEN:
3975
- - Ending animated sequences
3976
- - Resetting map to static state
3977
- - Pausing for user interaction
3978
- - Transitioning to different visualization
3979
-
3980
- EXAMPLES:
3981
- - Stop all: {}
3982
- - Stop specific regions: {regions: ["USA", "France"]}
3983
- - Stop and reset colors: {resetColors: true}`,
3984
- inputSchema: {
3985
- type: 'object',
3986
- properties: {
3987
- regions: {
3988
- type: 'array',
3989
- items: { type: 'string' },
3990
- description: 'Specific region IDs to stop (omit for all)',
3991
- },
3992
- resetColors: {
3993
- type: 'boolean',
3994
- description: 'Reset regions to default colors (default: true)',
3995
- },
3996
- },
3997
- },
3998
- },
3999
- {
4000
- name: 'pinepaper_get_animated_map_regions',
4001
- annotations: {
4002
- title: 'Get Animated Map Regions',
4003
- readOnlyHint: true,
4004
- destructiveHint: false,
4005
- idempotentHint: true,
4006
- openWorldHint: false,
4007
- },
4008
- description: `[Utility] Get list of currently animated map regions with their animation data.
4009
-
4010
- USE WHEN:
4011
- - Debugging animations
4012
- - Checking animation state
4013
- - Building animation controls
4014
- - Inspecting current timeline
4015
-
4016
- RETURNS:
4017
- - animatedRegions: Array of region animation info
4018
- - count: Total number of animated regions`,
4019
- inputSchema: {
4020
- type: 'object',
4021
- properties: {},
4022
- },
4023
- },
4024
- {
4025
- name: 'pinepaper_export_map_region_csv',
4026
- annotations: {
4027
- title: 'Export Map Region CSV',
4028
- readOnlyHint: true,
4029
- destructiveHint: false,
4030
- idempotentHint: true,
4031
- openWorldHint: false,
4032
- },
4033
- description: `Export map region data as CSV including colors, highlight, and selection status.
4034
-
4035
- USE WHEN:
4036
- - Saving map state for later
4037
- - Creating data-driven workflows
4038
- - Integrating with spreadsheet tools
4039
- - Building export features
4040
-
4041
- CSV COLUMNS:
4042
- - regionId: Region identifier
4043
- - name: Display name
4044
- - highlighted: 1 or 0
4045
- - selected: 1 or 0
4046
- - fillColor: Current fill color
4047
- - strokeColor: Current stroke color
4048
-
4049
- EXAMPLES:
4050
- - Full export: {}
4051
- - Colors only: {includeHighlighted: false, includeSelected: false}
4052
- - Auto-download: {download: true, filename: "map-export.csv"}`,
4053
- inputSchema: {
4054
- type: 'object',
4055
- properties: {
4056
- includeHighlighted: {
4057
- type: 'boolean',
4058
- description: 'Include highlight status column (default: true)',
4059
- },
4060
- includeSelected: {
4061
- type: 'boolean',
4062
- description: 'Include selection status column (default: true)',
4063
- },
4064
- includeColors: {
4065
- type: 'boolean',
4066
- description: 'Include fill/stroke color columns (default: true)',
4067
- },
4068
- download: {
4069
- type: 'boolean',
4070
- description: 'Auto-download the CSV file (default: false)',
4071
- },
4072
- filename: {
4073
- type: 'string',
4074
- description: 'Filename for download (default: map-regions.csv)',
4075
- },
4076
- },
4077
- },
4078
- },
4079
- {
4080
- name: 'pinepaper_import_map_region_csv',
4081
- annotations: {
4082
- title: 'Import Map Region CSV',
4083
- readOnlyHint: false,
4084
- destructiveHint: false,
4085
- idempotentHint: true,
4086
- openWorldHint: false,
4087
- },
4088
- description: `Import CSV data to update map region states (colors, highlight, selection).
4089
-
4090
- USE WHEN:
4091
- - Restoring saved map state
4092
- - Applying data from spreadsheets
4093
- - Batch updating region properties
4094
- - Building data-driven visualizations
4095
-
4096
- CSV FORMAT:
4097
- Must have 'regionId' column. Optional columns:
4098
- - fillColor: Hex color for fill
4099
- - strokeColor: Hex color for stroke
4100
- - highlighted: 1 or 0
4101
- - selected: 1 or 0
4102
-
4103
- EXAMPLES:
4104
- - Import full CSV: {csvText: "regionId,fillColor,highlighted\\nUSA,#22c55e,1\\nFrance,#3b82f6,0"}
4105
- - Colors only: {csvText: "...", applyHighlight: false, applySelection: false}`,
4106
- inputSchema: {
4107
- type: 'object',
4108
- properties: {
4109
- csvText: {
4110
- type: 'string',
4111
- description: 'CSV text content to import',
4112
- },
4113
- applyColors: {
4114
- type: 'boolean',
4115
- description: 'Apply fill/stroke colors from CSV (default: true)',
4116
- },
4117
- applyHighlight: {
4118
- type: 'boolean',
4119
- description: 'Update highlight status from CSV (default: true)',
4120
- },
4121
- applySelection: {
4122
- type: 'boolean',
4123
- description: 'Update selection status from CSV (default: true)',
4124
- },
4125
- },
4126
- required: ['csvText'],
4127
- },
4128
- },
4129
- {
4130
- name: 'pinepaper_select_map_regions',
4131
- annotations: {
4132
- title: 'Select Map Regions',
4133
- readOnlyHint: false,
4134
- destructiveHint: false,
4135
- idempotentHint: true,
4136
- openWorldHint: false,
4137
- },
4138
- description: `Programmatically select map regions.
4139
-
4140
- USE WHEN:
4141
- - Building interactive map features
4142
- - Responding to user input
4143
- - Creating selection-based workflows
4144
- - Highlighting user choices
4145
-
4146
- EXAMPLES:
4147
- - Select countries: {regionIds: ["USA", "Canada", "Mexico"]}
4148
- - Select US states: {regionIds: ["CA", "TX", "NY"]}`,
4149
- inputSchema: {
4150
- type: 'object',
4151
- properties: {
4152
- regionIds: {
4153
- type: 'array',
4154
- items: { type: 'string' },
4155
- description: 'Array of region IDs to select',
4156
- },
4157
- },
4158
- required: ['regionIds'],
4159
- },
4160
- },
4161
- {
4162
- name: 'pinepaper_deselect_map_regions',
4163
- annotations: {
4164
- title: 'Deselect Map Regions',
4165
- readOnlyHint: false,
4166
- destructiveHint: false,
4167
- idempotentHint: true,
4168
- openWorldHint: false,
4169
- },
4170
- description: `Programmatically deselect map regions.
4171
-
4172
- USE WHEN:
4173
- - Clearing user selections
4174
- - Resetting map state
4175
- - Implementing toggle behavior
4176
- - Building selection management
4177
-
4178
- EXAMPLES:
4179
- - Deselect specific: {regionIds: ["USA", "France"]}
4180
- - Deselect all: {} (omit regionIds)`,
4181
- inputSchema: {
4182
- type: 'object',
4183
- properties: {
4184
- regionIds: {
4185
- type: 'array',
4186
- items: { type: 'string' },
4187
- description: 'Array of region IDs to deselect (omit for all)',
4188
- },
4189
- },
4190
- },
4191
- },
4192
- {
4193
- name: 'pinepaper_get_highlighted_map_regions',
4194
- annotations: {
4195
- title: 'Get Highlighted Map Regions',
4196
- readOnlyHint: true,
4197
- destructiveHint: false,
4198
- idempotentHint: true,
4199
- openWorldHint: false,
4200
- },
4201
- description: `[Utility] Get list of currently highlighted map regions.
4202
-
4203
- USE WHEN:
4204
- - Checking current highlight state
4205
- - Building conditional logic
4206
- - Creating highlight summaries
4207
- - Debugging map state
4208
-
4209
- RETURNS:
4210
- - highlighted: Array of highlighted region IDs
4211
- - count: Total number of highlighted regions`,
4212
- inputSchema: {
4213
- type: 'object',
4214
- properties: {},
4215
- },
4216
- },
4217
- {
4218
- name: 'pinepaper_export_map_geojson',
4219
- annotations: {
4220
- title: 'Export Map GeoJSON',
4221
- readOnlyHint: true,
4222
- destructiveHint: false,
4223
- idempotentHint: true,
4224
- openWorldHint: false,
4225
- },
4226
- description: `Export the current map as GeoJSON (with current colors/modifications).
4227
-
4228
- USE WHEN:
4229
- - Saving map state with custom styling
4230
- - Exporting for use in other mapping tools
4231
- - Creating styled GeoJSON for external applications
4232
- - Archiving map customizations
4233
-
4234
- EXAMPLES:
4235
- - Export with styles: {includeStyles: true}
4236
- - Selected regions only: {selectedOnly: true}
4237
- - Auto-download: {download: true, filename: "my-map.geojson"}`,
4238
- inputSchema: {
4239
- type: 'object',
4240
- properties: {
4241
- includeStyles: {
4242
- type: 'boolean',
4243
- description: 'Include fill/stroke colors as properties (default: true)',
4244
- },
4245
- includeMetadata: {
4246
- type: 'boolean',
4247
- description: 'Include region names and IDs (default: true)',
4248
- },
4249
- selectedOnly: {
4250
- type: 'boolean',
4251
- description: 'Only export selected regions (default: false)',
4252
- },
4253
- download: {
4254
- type: 'boolean',
4255
- description: 'Auto-download the file (default: false)',
4256
- },
4257
- filename: {
4258
- type: 'string',
4259
- description: 'Filename for download (default: "map-export.geojson")',
4260
- },
4261
- },
4262
- },
4263
- },
4264
- {
4265
- name: 'pinepaper_export_original_map_geojson',
4266
- annotations: {
4267
- title: 'Export Original Map GeoJSON',
4268
- readOnlyHint: true,
4269
- destructiveHint: false,
4270
- idempotentHint: true,
4271
- openWorldHint: false,
4272
- },
4273
- description: `Export the original source GeoJSON (unmodified boundaries). Returns the exact data used to load the map, allowing users to edit boundaries externally and re-import.
4274
-
4275
- USE WHEN:
4276
- - Extracting original map data for external editing
4277
- - Getting clean boundaries without customizations
4278
- - Creating a baseline for map modifications
4279
- - Re-importing after external boundary edits
4280
-
4281
- EXAMPLES:
4282
- - Get original data: {}
4283
- - Auto-download: {download: true, filename: "map-source.geojson"}`,
4284
- inputSchema: {
4285
- type: 'object',
4286
- properties: {
4287
- download: {
4288
- type: 'boolean',
4289
- description: 'Auto-download the file (default: false)',
4290
- },
4291
- filename: {
4292
- type: 'string',
4293
- description: 'Filename for download (default: "map-source.geojson")',
4294
- },
4295
- },
4296
- },
4297
- },
4298
- {
4299
- name: 'pinepaper_get_map_source_info',
4300
- annotations: {
4301
- title: 'Get Map Source Info',
4302
- readOnlyHint: true,
4303
- destructiveHint: false,
4304
- idempotentHint: true,
4305
- openWorldHint: false,
4306
- },
4307
- description: `[Utility] Get information about the currently loaded map source.
4308
-
4309
- USE WHEN:
4310
- - Checking what map is currently loaded
4311
- - Debugging map loading issues
4312
- - Getting map metadata
4313
- - Verifying map configuration
4314
-
4315
- RETURNS:
4316
- - source: Map source identifier (e.g., "world", "worldHighRes", "usa", or custom)
4317
- - projection: Current projection type
4318
- - quality: Rendering quality setting
4319
- - regionCount: Total number of regions
4320
- - hasOriginalGeoJSON: Whether original GeoJSON is available
4321
- - isCustomImport: Whether this is a custom imported map`,
4322
- inputSchema: {
4323
- type: 'object',
4324
- properties: {},
4325
- },
4326
- },
4327
- // ---------------------------------------------------------------------------
4328
- // DOMAIN: FONT TOOLS
4329
- // ---------------------------------------------------------------------------
4330
- {
4331
- name: 'pinepaper_font_show_studio',
4332
- annotations: {
4333
- title: 'Font Show Studio',
4334
- readOnlyHint: false,
4335
- destructiveHint: false,
4336
- idempotentHint: true,
4337
- openWorldHint: false,
4338
- },
4339
- description: `Open the Font Studio UI for interactive font creation.
4340
-
4341
- USE WHEN:
4342
- - Starting a custom font creation workflow
4343
- - Need the interactive Font Studio interface with guide lines
4344
- - Want to create a hand-drawn font from scratch
4345
-
4346
- WORKFLOW:
4347
- 1. Open Font Studio → pinepaper_font_show_studio
4348
- 2. Set font name → pinepaper_font_set_name
4349
- 3. Check required chars → pinepaper_font_get_required_chars
4350
- 4. For each character: draw path, cleanup, create glyph
4351
- 5. Check progress → pinepaper_font_get_status
4352
- 6. Export when complete → pinepaper_font_export`,
4353
- inputSchema: {
4354
- type: 'object',
4355
- properties: {},
4356
- },
4357
- },
4358
- {
4359
- name: 'pinepaper_font_set_name',
4360
- annotations: {
4361
- title: 'Font Set Name',
4362
- readOnlyHint: false,
4363
- destructiveHint: false,
4364
- idempotentHint: true,
4365
- openWorldHint: false,
4366
- },
4367
- description: `Set the font family name for the current font being created.`,
4368
- inputSchema: {
4369
- type: 'object',
4370
- properties: {
4371
- name: {
4372
- type: 'string',
4373
- description: "Font family name (e.g., 'MyHandwriting')",
4374
- },
4375
- },
4376
- required: ['name'],
4377
- },
4378
- },
4379
- {
4380
- name: 'pinepaper_font_get_required_chars',
4381
- annotations: {
4382
- title: 'Font Get Required Chars',
4383
- readOnlyHint: true,
4384
- destructiveHint: false,
4385
- idempotentHint: true,
4386
- openWorldHint: false,
4387
- },
4388
- description: `Get the list of characters needed for a complete font.
4389
-
4390
- CHARACTER SETS:
4391
- - minimum: A-Z, a-z, 0-9, space (63 chars) - enough for basic text
4392
- - standard: adds punctuation and symbols (90+ chars) - full typography`,
4393
- inputSchema: {
4394
- type: 'object',
4395
- properties: {
4396
- set: {
4397
- type: 'string',
4398
- enum: ['minimum', 'standard'],
4399
- description: 'minimum: A-Z, a-z, 0-9, space (63 chars). standard: adds punctuation (90+ chars)',
4400
- },
4401
- },
4402
- },
4403
- },
4404
- {
4405
- name: 'pinepaper_font_get_status',
4406
- annotations: {
4407
- title: 'Font Get Status',
4408
- readOnlyHint: true,
4409
- destructiveHint: false,
4410
- idempotentHint: true,
4411
- openWorldHint: false,
4412
- },
4413
- description: `Get font completion status including progress percentage, completed/pending characters.
4414
-
4415
- USE WHEN:
4416
- - Checking progress during font creation
4417
- - Determining which characters still need to be drawn
4418
- - Verifying font is complete before export`,
4419
- inputSchema: {
4420
- type: 'object',
4421
- properties: {},
4422
- },
4423
- },
4424
- {
4425
- name: 'pinepaper_font_create_glyph',
4426
- annotations: {
4427
- title: 'Font Create Glyph',
4428
- readOnlyHint: false,
4429
- destructiveHint: false,
4430
- idempotentHint: false,
4431
- openWorldHint: false,
4432
- },
4433
- description: `Create a glyph from a Paper.js path. Converts a drawn path into an OpenType glyph with calculated advance width.
4434
-
4435
- USE WHEN:
4436
- - Converting a drawn character path to a font glyph
4437
- - Adding a new character to the font
4438
-
4439
- WORKFLOW:
4440
- 1. Draw the character as a Paper.js path on the canvas
4441
- 2. Optionally clean up the path (pinepaper_font_cleanup_path)
4442
- 3. Use the path's registry ID to create the glyph`,
4443
- inputSchema: {
4444
- type: 'object',
4445
- properties: {
4446
- character: {
4447
- type: 'string',
4448
- description: "Single character (e.g., 'A', 'a', '1', ' ')",
4449
- },
4450
- pathId: {
4451
- type: 'string',
4452
- description: 'Registry ID of the Paper.js path to use as glyph shape',
4453
- },
4454
- },
4455
- required: ['character', 'pathId'],
4456
- },
4457
- },
4458
- {
4459
- name: 'pinepaper_font_create_space',
4460
- annotations: {
4461
- title: 'Font Create Space',
4462
- readOnlyHint: false,
4463
- destructiveHint: false,
4464
- idempotentHint: true,
4465
- openWorldHint: false,
4466
- },
4467
- description: `Create the space glyph (no visible shape, just advance width).
4468
-
4469
- USE WHEN:
4470
- - Adding the space character to the font
4471
- - Space needs no drawn path, only a width value`,
4472
- inputSchema: {
4473
- type: 'object',
4474
- properties: {
4475
- width: {
4476
- type: 'number',
4477
- description: 'Space width in font units (default: 250)',
4478
- },
4479
- },
4480
- },
4481
- },
4482
- {
4483
- name: 'pinepaper_font_remove_glyph',
4484
- annotations: {
4485
- title: 'Font Remove Glyph',
4486
- readOnlyHint: false,
4487
- destructiveHint: true,
4488
- idempotentHint: true,
4489
- openWorldHint: false,
4490
- },
4491
- description: `Remove a glyph from the font. Use when a character needs to be redrawn.`,
4492
- inputSchema: {
4493
- type: 'object',
4494
- properties: {
4495
- character: {
4496
- type: 'string',
4497
- description: 'Character to remove',
4498
- },
4499
- },
4500
- required: ['character'],
4501
- },
4502
- },
4503
- {
4504
- name: 'pinepaper_font_set_metrics',
4505
- annotations: {
4506
- title: 'Font Set Metrics',
4507
- readOnlyHint: false,
4508
- destructiveHint: false,
4509
- idempotentHint: true,
4510
- openWorldHint: false,
4511
- },
4512
- description: `Set font metrics (advanced). Controls the coordinate grid and vertical measurements.
4513
-
4514
- METRICS:
4515
- - unitsPerEm: Coordinate grid size (default: 1000)
4516
- - ascender: Height above baseline (default: 800)
4517
- - descender: Depth below baseline, negative (default: -200)
4518
- - xHeight: Lowercase letter height (default: 500)
4519
- - capHeight: Capital letter height (default: 700)`,
4520
- inputSchema: {
4521
- type: 'object',
4522
- properties: {
4523
- unitsPerEm: {
4524
- type: 'number',
4525
- description: 'Coordinate grid size (default: 1000)',
4526
- },
4527
- ascender: {
4528
- type: 'number',
4529
- description: 'Height above baseline (default: 800)',
4530
- },
4531
- descender: {
4532
- type: 'number',
4533
- description: 'Depth below baseline, negative (default: -200)',
4534
- },
4535
- xHeight: {
4536
- type: 'number',
4537
- description: 'Lowercase letter height (default: 500)',
4538
- },
4539
- capHeight: {
4540
- type: 'number',
4541
- description: 'Capital letter height (default: 700)',
4542
- },
4543
- },
4544
- },
4545
- },
4546
- {
4547
- name: 'pinepaper_font_export',
4548
- annotations: {
4549
- title: 'Font Export',
4550
- readOnlyHint: true,
4551
- destructiveHint: false,
4552
- idempotentHint: true,
4553
- openWorldHint: false,
4554
- },
4555
- description: `Export the font as an OTF file. Triggers browser download of the completed font.
4556
-
4557
- USE WHEN:
4558
- - Font is complete and ready for download
4559
- - User wants to save the font as a file`,
4560
- inputSchema: {
4561
- type: 'object',
4562
- properties: {
4563
- download: {
4564
- type: 'boolean',
4565
- description: 'Trigger browser download (default: true)',
4566
- },
4567
- },
4568
- },
4569
- },
4570
- {
4571
- name: 'pinepaper_font_load_into_document',
4572
- annotations: {
4573
- title: 'Font Load Into Document',
4574
- readOnlyHint: false,
4575
- destructiveHint: false,
4576
- idempotentHint: true,
4577
- openWorldHint: false,
4578
- },
4579
- description: `Load the custom font into the document for immediate use in PinePaper text items.
4580
-
4581
- USE WHEN:
4582
- - Want to use the created font immediately in the current document
4583
- - Testing how the font looks in actual text items`,
4584
- inputSchema: {
4585
- type: 'object',
4586
- properties: {},
4587
- },
4588
- },
4589
- {
4590
- name: 'pinepaper_font_export_data',
4591
- annotations: {
4592
- title: 'Font Export Data',
4593
- readOnlyHint: true,
4594
- destructiveHint: false,
4595
- idempotentHint: true,
4596
- openWorldHint: false,
4597
- },
4598
- description: `Export font data as JSON for saving progress. Use to save work-in-progress fonts.
4599
-
4600
- USE WHEN:
4601
- - Saving font progress for later continuation
4602
- - Backing up font data`,
4603
- inputSchema: {
4604
- type: 'object',
4605
- properties: {
4606
- download: {
4607
- type: 'boolean',
4608
- description: 'Trigger browser download (default: true)',
4609
- },
4610
- },
4611
- },
4612
- },
4613
- {
4614
- name: 'pinepaper_font_import_data',
4615
- annotations: {
4616
- title: 'Font Import Data',
4617
- readOnlyHint: false,
4618
- destructiveHint: false,
4619
- idempotentHint: false,
4620
- openWorldHint: false,
4621
- },
4622
- description: `Import font data from previously saved JSON. Restores a font from exported data.
4623
-
4624
- USE WHEN:
4625
- - Resuming work on a previously saved font
4626
- - Loading font data exported with pinepaper_font_export_data`,
4627
- inputSchema: {
4628
- type: 'object',
4629
- properties: {
4630
- data: {
4631
- type: 'object',
4632
- description: 'Font data object from pinepaper_font_export_data',
4633
- },
4634
- },
4635
- required: ['data'],
4636
- },
4637
- },
4638
- {
4639
- name: 'pinepaper_font_clear',
4640
- annotations: {
4641
- title: 'Font Clear',
4642
- readOnlyHint: false,
4643
- destructiveHint: true,
4644
- idempotentHint: true,
4645
- openWorldHint: false,
4646
- },
4647
- description: `Clear all glyphs and reset the font. Removes all drawn characters.
4648
-
4649
- WARNING: This is destructive - all glyph progress will be lost.`,
4650
- inputSchema: {
4651
- type: 'object',
4652
- properties: {},
4653
- },
4654
- },
4655
- {
4656
- name: 'pinepaper_font_remove_overlap',
4657
- annotations: {
4658
- title: 'Font Remove Overlap',
4659
- readOnlyHint: false,
4660
- destructiveHint: false,
4661
- idempotentHint: true,
4662
- openWorldHint: false,
4663
- },
4664
- description: `Remove overlapping areas from a path (like FontForge's RemoveOverlap). Merges multiple overlapping paths into a single clean outline.
4665
-
4666
- USE WHEN:
4667
- - Path has overlapping strokes that need merging
4668
- - Preparing a glyph path for clean font output`,
4669
- inputSchema: {
4670
- type: 'object',
4671
- properties: {
4672
- pathId: {
4673
- type: 'string',
4674
- description: 'Registry ID of the Paper.js path to process',
4675
- },
4676
- },
4677
- required: ['pathId'],
4678
- },
4679
- },
4680
- {
4681
- name: 'pinepaper_font_correct_direction',
4682
- annotations: {
4683
- title: 'Font Correct Direction',
4684
- readOnlyHint: false,
4685
- destructiveHint: false,
4686
- idempotentHint: true,
4687
- openWorldHint: false,
4688
- },
4689
- description: `Correct path winding direction for proper fill rendering (like FontForge's CorrectDirection). Ensures outer contours are clockwise and inner holes are counter-clockwise.
4690
-
4691
- USE WHEN:
4692
- - Glyph fills are rendering incorrectly (holes appear filled)
4693
- - Preparing paths for font export`,
4694
- inputSchema: {
4695
- type: 'object',
4696
- properties: {
4697
- pathId: {
4698
- type: 'string',
4699
- description: 'Registry ID of the Paper.js path to process',
4700
- },
4701
- },
4702
- required: ['pathId'],
4703
- },
4704
- },
4705
- {
4706
- name: 'pinepaper_font_cleanup_path',
4707
- annotations: {
4708
- title: 'Font Cleanup Path',
4709
- readOnlyHint: false,
4710
- destructiveHint: false,
4711
- idempotentHint: true,
4712
- openWorldHint: false,
4713
- },
4714
- description: `Apply all path cleanup operations in the correct order: removeOverlap -> correctDirection -> smooth. Convenience tool that combines all path preparation steps.
4715
-
4716
- USE WHEN:
4717
- - Preparing a drawn path before creating a glyph
4718
- - Quick one-step path cleanup instead of calling individual operations`,
4719
- inputSchema: {
4720
- type: 'object',
4721
- properties: {
4722
- pathId: {
4723
- type: 'string',
4724
- description: 'Registry ID of the Paper.js path to process',
4725
- },
4726
- removeOverlap: {
4727
- type: 'boolean',
4728
- description: 'Merge overlapping strokes (default: true)',
4729
- },
4730
- correctDirection: {
4731
- type: 'boolean',
4732
- description: 'Fix winding direction for fills (default: true)',
4733
- },
4734
- smooth: {
4735
- type: 'boolean',
4736
- description: 'Apply path smoothing (default: true)',
4737
- },
4738
- smoothTolerance: {
4739
- type: 'number',
4740
- description: 'Smoothing tolerance - higher = more simplification (default: 2.5)',
4741
- },
4742
- },
4743
- required: ['pathId'],
4744
- },
4745
- },
4746
- // ---------------------------------------------------------------------------
4747
- // DOMAIN: LETTER COLLAGE TOOLS (Text Design)
4748
- // ---------------------------------------------------------------------------
4749
- {
4750
- name: 'pinepaper_create_letter_collage',
4751
- annotations: {
4752
- title: 'Create Letter Collage',
4753
- readOnlyHint: false,
4754
- destructiveHint: false,
4755
- idempotentHint: false,
4756
- openWorldHint: false,
4757
- },
4758
- description: `Create stylized text with per-letter customization. Perfect for word games, ransom notes, gradient text, and creative typography.
4759
-
4760
- USE WHEN:
4761
- - Creating Wordle-style word displays
4762
- - Making magazine cutout/ransom note text
4763
- - Designing gradient-filled text
4764
- - Building creative typography effects
4765
- - Creating paper craft style lettering
4766
-
4767
- STYLE TYPES:
4768
- - tile: Wordle/Scrabble colored backgrounds (use with tile palettes)
4769
- - magazine: Mixed fonts/colors like cutouts
4770
- - paperCut: Shadow/depth like cut paper
4771
- - fold: Origami-style folded letters
4772
- - gradient: Each letter with gradient fill (use with gradient palettes)
4773
- - image: Letters filled with image
4774
-
4775
- TILE PALETTES:
4776
- - Game: wordle, scrabble
4777
- - Vibrant: candy, neon, rainbow
4778
- - Soft: pastel, cotton
4779
- - Natural: earth, ocean, forest, sunset
4780
- - Professional: corporate, minimal, slate
4781
- - Seasonal: christmas, halloween, spring
4782
- - Magazine: magazine, newspaper, vintage
4783
- - Paper Craft: paperCraft, origami, craftPaper
4784
-
4785
- GRADIENT PALETTES:
4786
- rainbow, sunset, ocean, fire, gold, rose, ice, cyberpunk, neonGlow, purplePink
4787
-
4788
- EXAMPLES:
4789
- - Wordle style: {text: "HELLO", style: "tile", palette: "wordle"}
4790
- - Ransom note: {text: "SECRET", style: "magazine", palette: "newspaper"}
4791
- - Gradient text: {text: "RAINBOW", style: "gradient", gradientPalette: "rainbow"}
4792
- - Neon style: {text: "GLOW", style: "tile", palette: "neon"}`,
4793
- inputSchema: {
4794
- type: 'object',
4795
- properties: {
4796
- text: {
4797
- type: 'string',
4798
- description: 'The text to stylize',
4799
- },
4800
- style: {
4801
- type: 'string',
4802
- enum: ['tile', 'magazine', 'paperCut', 'fold', 'gradient', 'image'],
4803
- description: 'Style type (default: tile)',
4804
- },
4805
- palette: {
4806
- type: 'string',
4807
- enum: [
4808
- 'wordle', 'scrabble',
4809
- 'candy', 'neon', 'rainbow',
4810
- 'pastel', 'cotton',
4811
- 'earth', 'ocean', 'forest', 'sunset',
4812
- 'corporate', 'minimal', 'slate',
4813
- 'christmas', 'halloween', 'spring',
4814
- 'magazine', 'newspaper', 'vintage',
4815
- 'paperCraft', 'origami', 'craftPaper',
4816
- ],
4817
- description: 'Color palette for tile/magazine styles',
4818
- },
4819
- position: {
4820
- type: 'object',
4821
- properties: {
4822
- x: { type: 'number' },
4823
- y: { type: 'number' },
4824
- },
4825
- description: 'Position on canvas (defaults to center)',
4826
- },
4827
- fontSize: {
4828
- type: 'number',
4829
- description: 'Base font size in pixels (default: 48)',
4830
- },
4831
- fontFamily: {
4832
- type: 'string',
4833
- description: 'Font family (default: Inter, sans-serif)',
4834
- },
4835
- spacing: {
4836
- type: 'number',
4837
- description: 'Letter spacing multiplier (default: 1.1)',
4838
- },
4839
- gradientPalette: {
4840
- type: 'string',
4841
- enum: ['rainbow', 'sunset', 'ocean', 'fire', 'gold', 'rose', 'ice', 'cyberpunk', 'neonGlow', 'purplePink'],
4842
- description: 'Gradient palette (for style="gradient")',
4843
- },
4844
- gradientDirection: {
4845
- type: 'string',
4846
- enum: ['vertical', 'horizontal', 'diagonal', 'radial'],
4847
- description: 'Gradient direction (default: vertical)',
4848
- },
4849
- cornerRadius: {
4850
- type: 'number',
4851
- description: 'Corner radius for tile backgrounds (default: 4)',
4852
- },
4853
- shadowEnabled: {
4854
- type: 'boolean',
4855
- description: 'Enable drop shadows (default: true)',
4856
- },
4857
- },
4858
- required: ['text'],
4859
- },
4860
- },
4861
- {
4862
- name: 'pinepaper_animate_letter_collage',
4863
- annotations: {
4864
- title: 'Animate Letter Collage',
4865
- readOnlyHint: false,
4866
- destructiveHint: false,
4867
- idempotentHint: true,
4868
- openWorldHint: false,
4869
- },
4870
- description: `Apply animation to all letters in a collage with staggered timing.
4871
-
4872
- USE WHEN:
4873
- - Adding entrance animations to text
4874
- - Creating typewriter-style reveals
4875
- - Making text bounce or pulse
4876
- - Adding dynamic effects to lettering
4877
-
4878
- ANIMATION TYPES:
4879
- - pulse: Scale up and down rhythmically
4880
- - bounce: Bouncing motion
4881
- - fade: Fade in/out
4882
- - wobble: Side-to-side wobble
4883
- - rotate: Spinning rotation
4884
-
4885
- STAGGER EFFECT:
4886
- Use staggerDelay to create wave-like animations where each letter starts slightly after the previous one. 0.1s is a good default for smooth wave effects.
4887
-
4888
- EXAMPLES:
4889
- - Wave entrance: {collageId: "collage_1", animationType: "bounce", staggerDelay: 0.1}
4890
- - Pulsing text: {collageId: "collage_1", animationType: "pulse", staggerDelay: 0.05}
4891
- - Fast typewriter: {collageId: "collage_1", animationType: "fade", staggerDelay: 0.15}`,
4892
- inputSchema: {
4893
- type: 'object',
4894
- properties: {
4895
- collageId: {
4896
- type: 'string',
4897
- description: 'Collage ID from create_letter_collage',
4898
- },
4899
- animationType: {
4900
- type: 'string',
4901
- enum: ['pulse', 'bounce', 'fade', 'wobble', 'rotate'],
4902
- description: 'Animation type to apply',
4903
- },
4904
- staggerDelay: {
4905
- type: 'number',
4906
- description: 'Delay between each letter animation start in seconds (default: 0.1)',
4907
- },
4908
- animationSpeed: {
4909
- type: 'number',
4910
- description: 'Animation speed multiplier (default: 1)',
4911
- },
4912
- },
4913
- required: ['collageId', 'animationType'],
4914
- },
4915
- },
4916
- {
4917
- name: 'pinepaper_get_letter_collage_options',
4918
- annotations: {
4919
- title: 'Get Letter Collage Options',
4920
- readOnlyHint: true,
4921
- destructiveHint: false,
4922
- idempotentHint: true,
4923
- openWorldHint: false,
4924
- },
4925
- description: `[Utility] Get available styles, palettes, and gradient options for letter collages.
4926
-
4927
- USE WHEN:
4928
- - Learning available letter collage styles
4929
- - Discovering palette options
4930
- - Exploring gradient possibilities
4931
- - Building UI for collage creation
4932
-
4933
- RETURNS:
4934
- - styles: All available style types
4935
- - tilePalettes: Grouped by category (game, vibrant, soft, natural, etc.)
4936
- - gradientPalettes: Available gradient color schemes
4937
- - gradientDirections: Direction options for gradients`,
4938
- inputSchema: {
4939
- type: 'object',
4940
- properties: {},
4941
- },
4942
- },
4943
- // ---------------------------------------------------------------------------
4944
- // DOMAIN: GENERATOR TOOLS
4945
- // ---------------------------------------------------------------------------
4946
- {
4947
- name: 'pinepaper_execute_generator',
4948
- annotations: {
4949
- title: 'Execute Generator',
4950
- readOnlyHint: false,
4951
- destructiveHint: false,
4952
- idempotentHint: false,
4953
- openWorldHint: false,
4954
- },
4955
- description: `Execute a background generator to create procedural patterns.
4956
-
4957
- USE WHEN:
4958
- - "add a sunburst background", "bokeh effect", "gradient mesh"
4959
- - "create wave pattern", "wind field", "fluid flow"
4960
- - "grid background", "geometric abstract", "noise texture"
4961
- - Creating dynamic procedural backgrounds
4962
-
4963
- GENERATORS (15 total):
4964
-
4965
- Classic:
4966
- - drawSunburst: Radial rays from center (rayCount, colors, bgColor, opacity, rayGap, gradientRays)
4967
- - drawSunsetScene: Animated sunset with clouds (sunColor, skyColors, cloudCount, skyOpacity, starCount, starColor, reflectionEnabled, reflectionOpacity)
4968
- - drawGrid: Lines/dots/squares (gridType, spacing, lineColor, opacity, gap, randomRotation, colorMode: checkerboard|gradient|random|rows|columns, strokeColor, strokeWidth)
4969
- - drawStackedCircles: Overlapping circles (count, colors, distribution: random|poisson|golden, opacityMin, opacityMax, blendMode, strokeWidth, strokeColor, sizeGradient, animationType: pulse|float|none)
4970
- - drawCircuit: Tech circuit board (lineColor, nodeColor, density, traceOpacity, nodeOpacity, diagonalPaths, chipDensity: auto|none|low|medium|high)
4971
- - drawWaves: Layered wave pattern (waveCount, colors, amplitude, frequency, opacity, fill, fillOpacity, amplitudeVariation, blendMode)
4972
- - drawPattern: Geometric shapes in orbit (patternType, size, color, opacity, blendMode, layers: 1-5, layerScaleDecay)
4973
-
4974
- New — Effects:
4975
- - drawBokeh: Soft-focus circles (count, colors, minRadius, maxRadius, shadowBlur, distribution: random|poisson, driftAnimation)
4976
-
4977
- New — Organic:
4978
- - drawGradientMesh: Radial gradient blobs with screen blending (colors, blobCount, blendMode, drift)
4979
- - drawFluidFlow: Sinusoidal stream paths with depth (streamCount, colors, depthLayers, speed)
4980
- - drawOrganicFlow: Aurora/silk layers with fill-to-bottom (layerCount, colors, blendMode, fillToBottom)
4981
-
4982
- New — Geometric:
4983
- - drawGeometricAbstract: Mixed translucent shapes (colors, shapeCount, blendMode, rotation)
4984
-
4985
- New — Particles:
4986
- - drawWindField: Directional wind particles with noise turbulence (particleCount, colors, direction, turbulence, trailLength, speed)
4987
-
4988
- New — Textures:
4989
- - drawNoiseTexture: Perlin/grain/stipple noise (noiseType: perlin|grain|stipple, colors, scale, density, animated)
4990
-
4991
- New — Tech:
4992
- - drawGlobeWireframe: Vercel-style wireframe globe (bgColor, wireColor, glowColor, highlightColor, meridianCount, latitudeCount, globeRadius, nodeCount, nodeSize, animationEnabled, animationSpeed, strokeWidth, gridOpacity)`,
4993
- inputSchema: {
4994
- type: 'object',
4995
- properties: {
4996
- generatorName: {
4997
- type: 'string',
4998
- enum: [
4999
- 'drawSunburst', 'drawSunsetScene', 'drawGrid', 'drawStackedCircles',
5000
- 'drawCircuit', 'drawWaves', 'drawPattern',
5001
- 'drawBokeh', 'drawGradientMesh', 'drawGeometricAbstract', 'drawWindField',
5002
- 'drawFluidFlow', 'drawOrganicFlow', 'drawNoiseTexture',
5003
- 'drawGlobeWireframe',
5004
- ],
5005
- description: 'Generator name',
5006
- },
5007
- params: {
5008
- type: 'object',
5009
- description: 'Generator-specific parameters',
5010
- additionalProperties: true,
5011
- },
5012
- },
5013
- required: ['generatorName'],
5014
- },
5015
- },
5016
- {
5017
- name: 'pinepaper_list_generators',
5018
- annotations: {
5019
- title: 'List Generators',
5020
- readOnlyHint: true,
5021
- destructiveHint: false,
5022
- idempotentHint: true,
5023
- openWorldHint: false,
5024
- },
5025
- description: `[Utility] Get a list of all available background generators with their parameters.
5026
-
5027
- USE WHEN:
5028
- - User asks "what backgrounds are available?"
5029
- - Need to show generator options
5030
- - Discovering generator capabilities`,
5031
- inputSchema: {
5032
- type: 'object',
5033
- properties: {},
5034
- },
5035
- },
5036
- // ---------------------------------------------------------------------------
5037
- // DOMAIN: EFFECT TOOLS
5038
- // ---------------------------------------------------------------------------
5039
- {
5040
- name: 'pinepaper_apply_effect',
5041
- annotations: {
5042
- title: 'Apply Effect',
5043
- readOnlyHint: false,
5044
- destructiveHint: false,
5045
- idempotentHint: false,
5046
- openWorldHint: false,
5047
- },
5048
- description: `Apply a visual effect to an item.
5049
-
5050
- USE WHEN:
5051
- - Adding sparkle/glitter effects
5052
- - Creating burst/explosion, fire, smoke effects
5053
- - Weather effects (rain, snow)
5054
- - Celebration effects (confetti)
5055
- - Enhancing visual impact (ripple, glow, electric)
5056
-
5057
- EFFECTS (10 total):
5058
- - sparkle: Glitter/sparkle particles (color, speed, size)
5059
- - blast: Explosion burst effect (color, radius, count)
5060
- - smoke: Rising smoke plumes (color, speed, size, drift, height, growthRate)
5061
- - fire: Animated fire/flames (color, colors, speed, size, height, turbulence)
5062
- - rain: Falling rain drops (color, count, speed, angle, spread)
5063
- - snow: Falling snowflakes (color, count, speed, spread, particleLife)
5064
- - confetti: Celebration confetti (colors, count, radius, gravity, size, spread, interval, repeat)
5065
- - ripple: Expanding ring ripples (color, speed, maxRadius, ringCount, strokeWidth)
5066
- - glow: Pulsing glow aura (color, speed, intensity, size)
5067
- - electric: Lightning bolts (color, speed, boltCount, length, flickerRate)`,
5068
- inputSchema: {
5069
- type: 'object',
5070
- properties: {
5071
- itemId: { type: 'string', description: 'Registry ID of the item' },
5072
- effectType: {
5073
- type: 'string',
5074
- enum: ['sparkle', 'blast', 'smoke', 'fire', 'rain', 'snow', 'confetti', 'ripple', 'glow', 'electric'],
5075
- description: 'Type of effect',
5076
- },
5077
- params: {
5078
- type: 'object',
5079
- description: 'Effect parameters',
5080
- additionalProperties: true,
5081
- },
5082
- },
5083
- required: ['itemId', 'effectType'],
5084
- },
5085
- },
5086
- // ---------------------------------------------------------------------------
5087
- // DOMAIN: FILTER TOOLS
5088
- // ---------------------------------------------------------------------------
5089
- {
5090
- name: 'pinepaper_add_filter',
5091
- annotations: {
5092
- title: 'Add Filter',
5093
- readOnlyHint: false,
5094
- destructiveHint: false,
5095
- idempotentHint: false,
5096
- openWorldHint: false,
5097
- },
5098
- description: `Add a visual filter effect to the canvas. Filters are scene-wide effects that can be stacked.
5099
-
5100
- USE WHEN:
5101
- - User wants visual effects like blur, grayscale, vintage look
5102
- - Creating mood or atmosphere (cinematic, dreamy, noir)
5103
- - Post-processing the entire scene
5104
- - User says "make it look vintage", "add blur", "black and white"
5105
-
5106
- AVAILABLE FILTERS:
5107
- - grayscale: Convert to black and white (params: intensity 0-1)
5108
- - sepia: Warm vintage brownish tone (params: intensity 0-1)
5109
- - blur: Gaussian blur effect (params: radius 0-20)
5110
- - brightness: Adjust brightness (params: value -100 to 100)
5111
- - contrast: Adjust contrast (params: value -100 to 100)
5112
- - saturate: Adjust color saturation (params: value -100 to 100)
5113
- - invert: Invert colors (params: intensity 0-1)
5114
- - noise: Add film grain (params: intensity 0-100, monochrome: true/false)
5115
- - vignette: Darken edges (params: intensity 0-1, radius 0-1)
5116
- - vintage: Preset combining sepia, vignette, noise
5117
- - colorOverlay: Add color tint (params: color, intensity, blendMode)
5118
- - sharpen: Increase sharpness (params: intensity 0-100)
5119
- - posterize: Reduce color levels (params: levels 2-32)
5120
-
5121
- EXAMPLES:
5122
- - "Make it black and white" → filterType: "grayscale"
5123
- - "Add vintage look" → filterType: "vintage", params: {intensity: 0.8}
5124
- - "Blur the background" → filterType: "blur", params: {radius: 5}
5125
- - "Increase contrast" → filterType: "contrast", params: {value: 30}
5126
-
5127
- Filters can be stacked - call multiple times to combine effects.`,
5128
- inputSchema: {
5129
- type: 'object',
5130
- properties: {
5131
- filterType: {
5132
- type: 'string',
5133
- enum: ['grayscale', 'sepia', 'blur', 'brightness', 'contrast', 'saturate', 'invert', 'noise', 'vignette', 'vintage', 'colorOverlay', 'sharpen', 'posterize'],
5134
- description: 'Type of filter to apply',
5135
- },
5136
- params: {
5137
- type: 'object',
5138
- description: 'Filter-specific parameters',
5139
- additionalProperties: true,
5140
- },
5141
- },
5142
- required: ['filterType'],
5143
- },
5144
- },
5145
- // ---------------------------------------------------------------------------
5146
- // DOMAIN: INTERACTIVE TRIGGER TOOLS
5147
- // ---------------------------------------------------------------------------
5148
- {
5149
- name: 'pinepaper_add_trigger',
5150
- annotations: {
5151
- title: 'Add Trigger',
5152
- readOnlyHint: false,
5153
- destructiveHint: false,
5154
- idempotentHint: false,
5155
- openWorldHint: false,
5156
- },
5157
- description: `Add an interactive trigger to an item. Triggers execute actions when events occur.
3852
+ TILE PALETTES:
3853
+ - Game: wordle, scrabble
3854
+ - Vibrant: candy, neon, rainbow
3855
+ - Soft: pastel, cotton
3856
+ - Natural: earth, ocean, forest, sunset
3857
+ - Professional: corporate, minimal, slate
3858
+ - Seasonal: christmas, halloween, spring
3859
+ - Magazine: magazine, newspaper, vintage
3860
+ - Paper Craft: paperCraft, origami, craftPaper
5158
3861
 
5159
- USE WHEN:
5160
- - Making items clickable
5161
- - Adding hover effects
5162
- - Creating drag interactions
5163
- - Building interactive tutorials/quizzes
5164
- - Timeline-based triggers
5165
-
5166
- TRIGGER EVENTS:
5167
- - click: When item is clicked
5168
- - hover_enter: When mouse enters item
5169
- - hover_exit: When mouse leaves item
5170
- - drag_start: When item drag begins
5171
- - drag_move: While item is being dragged
5172
- - drag_end: When item drag ends
5173
- - timeline: At specific time in animation
5174
- - scene_enter: When scene becomes active
5175
- - scene_exit: When scene deactivates
5176
- - animation_end: When item's animation completes
5177
- - quiz_answer: When quiz answer is submitted
5178
-
5179
- ACTION TYPES:
5180
- - show: Make target item visible
5181
- - hide: Hide target item
5182
- - toggle_visibility: Toggle target visibility
5183
- - play_animation: Start animation on target
5184
- - stop_animation: Stop animation on target
5185
- - navigate: Navigate to scene or URL
5186
- - update_property: Change item property
5187
- - set_variable: Set a scene variable
5188
- - submit_answer: Submit quiz answer
5189
- - increment_score: Add to quiz score
5190
- - reset_quiz: Reset quiz state
3862
+ GRADIENT PALETTES:
3863
+ rainbow, sunset, ocean, fire, gold, rose, ice, cyberpunk, neonGlow, purplePink
5191
3864
 
5192
3865
  EXAMPLES:
5193
- - Click to show: {itemId: "button_1", event: "click", actions: [{type: "show", targetItemId: "panel_1"}]}
5194
- - Hover to animate: {itemId: "star_1", event: "hover_enter", actions: [{type: "play_animation", targetItemId: "star_1", animationType: "pulse"}]}
5195
- - Click to navigate: {itemId: "next_btn", event: "click", actions: [{type: "navigate", url: "#scene2"}]}`,
3866
+ - Wordle style: {text: "HELLO", style: "tile", palette: "wordle"}
3867
+ - Ransom note: {text: "SECRET", style: "magazine", palette: "newspaper"}
3868
+ - Gradient text: {text: "RAINBOW", style: "gradient", gradientPalette: "rainbow"}
3869
+ - Neon style: {text: "GLOW", style: "tile", palette: "neon"}`,
5196
3870
  inputSchema: {
5197
3871
  type: 'object',
5198
3872
  properties: {
5199
- itemId: {
3873
+ text: {
5200
3874
  type: 'string',
5201
- description: 'Item to attach trigger to',
3875
+ description: 'The text to stylize',
5202
3876
  },
5203
- event: {
3877
+ style: {
5204
3878
  type: 'string',
5205
- enum: ['click', 'hover_enter', 'hover_exit', 'drag_start', 'drag_move', 'drag_end', 'timeline', 'scene_enter', 'scene_exit', 'animation_end', 'quiz_answer'],
5206
- description: 'Event that fires the trigger',
3879
+ enum: ['tile', 'magazine', 'paperCut', 'fold', 'gradient', 'image'],
3880
+ description: 'Style type (default: tile)',
5207
3881
  },
5208
- actions: {
5209
- type: 'array',
5210
- items: {
5211
- type: 'object',
5212
- properties: {
5213
- type: {
5214
- type: 'string',
5215
- enum: ['show', 'hide', 'toggle_visibility', 'play_animation', 'stop_animation', 'navigate', 'update_property', 'set_variable', 'submit_answer', 'increment_score', 'reset_quiz'],
5216
- description: 'Action type',
5217
- },
5218
- targetItemId: {
5219
- type: 'string',
5220
- description: 'Target item for the action',
5221
- },
5222
- animationType: {
5223
- type: 'string',
5224
- description: 'Animation type for play_animation',
5225
- },
5226
- property: {
5227
- type: 'string',
5228
- description: 'Property name for update_property',
5229
- },
5230
- value: {
5231
- description: 'Value for update_property or set_variable',
5232
- },
5233
- variableName: {
5234
- type: 'string',
5235
- description: 'Variable name for set_variable',
5236
- },
5237
- url: {
5238
- type: 'string',
5239
- description: 'URL or scene ID for navigate',
5240
- },
5241
- points: {
5242
- type: 'number',
5243
- description: 'Points for increment_score',
5244
- },
5245
- },
5246
- required: ['type'],
3882
+ palette: {
3883
+ type: 'string',
3884
+ enum: [
3885
+ 'wordle', 'scrabble',
3886
+ 'candy', 'neon', 'rainbow',
3887
+ 'pastel', 'cotton',
3888
+ 'earth', 'ocean', 'forest', 'sunset',
3889
+ 'corporate', 'minimal', 'slate',
3890
+ 'christmas', 'halloween', 'spring',
3891
+ 'magazine', 'newspaper', 'vintage',
3892
+ 'paperCraft', 'origami', 'craftPaper',
3893
+ ],
3894
+ description: 'Color palette for tile/magazine styles',
3895
+ },
3896
+ position: {
3897
+ type: 'object',
3898
+ properties: {
3899
+ x: { type: 'number' },
3900
+ y: { type: 'number' },
5247
3901
  },
5248
- description: 'Actions to execute when triggered',
3902
+ description: 'Position on canvas (defaults to center)',
3903
+ },
3904
+ fontSize: {
3905
+ type: 'number',
3906
+ description: 'Base font size in pixels (default: 48)',
5249
3907
  },
5250
- condition: {
3908
+ fontFamily: {
5251
3909
  type: 'string',
5252
- description: 'Optional condition expression (e.g., "$score > 10")',
3910
+ description: 'Font family (default: Inter, sans-serif)',
5253
3911
  },
5254
- timelineOffset: {
3912
+ spacing: {
5255
3913
  type: 'number',
5256
- description: 'Time offset in ms for timeline triggers',
3914
+ description: 'Letter spacing multiplier (default: 1.1)',
5257
3915
  },
5258
- },
5259
- required: ['itemId', 'event', 'actions'],
5260
- },
5261
- },
5262
- {
5263
- name: 'pinepaper_remove_trigger',
5264
- annotations: {
5265
- title: 'Remove Trigger',
5266
- readOnlyHint: false,
5267
- destructiveHint: true,
5268
- idempotentHint: true,
5269
- openWorldHint: false,
5270
- },
5271
- description: `Remove triggers from an item.
5272
-
5273
- USE WHEN:
5274
- - Disabling interactivity on an item
5275
- - Cleaning up triggers before adding new ones
5276
- - Removing specific event handlers
5277
-
5278
- OPTIONS:
5279
- - Remove specific event: {itemId: "button_1", event: "click"}
5280
- - Remove all triggers: {itemId: "button_1", removeAll: true}`,
5281
- inputSchema: {
5282
- type: 'object',
5283
- properties: {
5284
- itemId: {
3916
+ gradientPalette: {
5285
3917
  type: 'string',
5286
- description: 'Item to remove triggers from',
3918
+ enum: ['rainbow', 'sunset', 'ocean', 'fire', 'gold', 'rose', 'ice', 'cyberpunk', 'neonGlow', 'purplePink'],
3919
+ description: 'Gradient palette (for style="gradient")',
5287
3920
  },
5288
- event: {
3921
+ gradientDirection: {
5289
3922
  type: 'string',
5290
- enum: ['click', 'hover_enter', 'hover_exit', 'drag_start', 'drag_move', 'drag_end', 'timeline', 'scene_enter', 'scene_exit', 'animation_end', 'quiz_answer'],
5291
- description: 'Specific event to remove (optional)',
3923
+ enum: ['vertical', 'horizontal', 'diagonal', 'radial'],
3924
+ description: 'Gradient direction (default: vertical)',
3925
+ },
3926
+ cornerRadius: {
3927
+ type: 'number',
3928
+ description: 'Corner radius for tile backgrounds (default: 4)',
5292
3929
  },
5293
- removeAll: {
3930
+ shadowEnabled: {
5294
3931
  type: 'boolean',
5295
- description: 'Remove all triggers from item',
3932
+ description: 'Enable drop shadows (default: true)',
5296
3933
  },
5297
3934
  },
5298
- required: ['itemId'],
3935
+ required: ['text'],
5299
3936
  },
5300
3937
  },
5301
3938
  {
5302
- name: 'pinepaper_query_triggers',
3939
+ name: 'pinepaper_animate_letter_collage',
5303
3940
  annotations: {
5304
- title: 'Query Triggers',
5305
- readOnlyHint: true,
3941
+ title: 'Animate Letter Collage',
3942
+ readOnlyHint: false,
5306
3943
  destructiveHint: false,
5307
3944
  idempotentHint: true,
5308
3945
  openWorldHint: false,
5309
3946
  },
5310
- description: `[Utility] List all triggers on the canvas or for a specific item.
3947
+ description: `Apply animation to all letters in a collage with staggered timing.
5311
3948
 
5312
3949
  USE WHEN:
5313
- - Inspecting existing interactivity
5314
- - Debugging trigger behavior
5315
- - Understanding scene's interactive elements
3950
+ - Adding entrance animations to text
3951
+ - Creating typewriter-style reveals
3952
+ - Making text bounce or pulse
3953
+ - Adding dynamic effects to lettering
3954
+
3955
+ ANIMATION TYPES:
3956
+ - pulse: Scale up and down rhythmically
3957
+ - bounce: Bouncing motion
3958
+ - fade: Fade in/out
3959
+ - wobble: Side-to-side wobble
3960
+ - rotate: Spinning rotation
3961
+
3962
+ STAGGER EFFECT:
3963
+ Use staggerDelay to create wave-like animations where each letter starts slightly after the previous one. 0.1s is a good default for smooth wave effects.
5316
3964
 
5317
3965
  EXAMPLES:
5318
- - All triggers: {}
5319
- - Triggers on specific item: {itemId: "button_1"}
5320
- - Filter by event type: {event: "click"}`,
3966
+ - Wave entrance: {collageId: "collage_1", animationType: "bounce", staggerDelay: 0.1}
3967
+ - Pulsing text: {collageId: "collage_1", animationType: "pulse", staggerDelay: 0.05}
3968
+ - Fast typewriter: {collageId: "collage_1", animationType: "fade", staggerDelay: 0.15}`,
5321
3969
  inputSchema: {
5322
3970
  type: 'object',
5323
3971
  properties: {
5324
- itemId: {
3972
+ collageId: {
5325
3973
  type: 'string',
5326
- description: 'Filter triggers by item ID',
3974
+ description: 'Collage ID from create_letter_collage',
5327
3975
  },
5328
- event: {
3976
+ animationType: {
5329
3977
  type: 'string',
5330
- enum: ['click', 'hover_enter', 'hover_exit', 'drag_start', 'drag_move', 'drag_end', 'timeline', 'scene_enter', 'scene_exit', 'animation_end', 'quiz_answer'],
5331
- description: 'Filter by event type',
3978
+ enum: ['pulse', 'bounce', 'fade', 'wobble', 'rotate'],
3979
+ description: 'Animation type to apply',
3980
+ },
3981
+ staggerDelay: {
3982
+ type: 'number',
3983
+ description: 'Delay between each letter animation start in seconds (default: 0.1)',
3984
+ },
3985
+ animationSpeed: {
3986
+ type: 'number',
3987
+ description: 'Animation speed multiplier (default: 1)',
5332
3988
  },
5333
3989
  },
3990
+ required: ['collageId', 'animationType'],
5334
3991
  },
5335
3992
  },
5336
3993
  // ---------------------------------------------------------------------------
5337
- // DOMAIN: QUIZ/LMS TOOLS
3994
+ // DOMAIN: GENERATOR TOOLS
5338
3995
  // ---------------------------------------------------------------------------
5339
3996
  {
5340
- name: 'pinepaper_create_quiz',
3997
+ name: 'pinepaper_execute_generator',
5341
3998
  annotations: {
5342
- title: 'Create Quiz',
3999
+ title: 'Execute Generator',
5343
4000
  readOnlyHint: false,
5344
4001
  destructiveHint: false,
5345
4002
  idempotentHint: false,
5346
4003
  openWorldHint: false,
5347
4004
  },
5348
- description: `Create an interactive quiz with questions, answers, and scoring.
4005
+ description: `Execute a background generator to create procedural patterns.
5349
4006
 
5350
4007
  USE WHEN:
5351
- - Building educational content
5352
- - Creating assessments
5353
- - Adding gamification elements
5354
- - Making interactive learning modules
5355
-
5356
- QUESTION TYPES:
5357
- - multiple-choice: Single correct answer from options
5358
- - multiple-select: Multiple correct answers
5359
- - drag-drop: Drag items to correct zones
5360
- - matching: Match pairs of items
5361
- - sequencing: Put items in correct order
5362
- - hotspot: Click correct area on image
5363
- - true-false: True or false question
5364
-
5365
- FEEDBACK:
5366
- Each question can have:
5367
- - correctFeedback: Message shown on correct answer
5368
- - incorrectFeedback: Message shown on wrong answer
5369
- - partialFeedback: Message for partially correct (multi-select)
5370
-
5371
- SCORING:
5372
- - Each question has a points value
5373
- - passingScore: Minimum score to pass
5374
- - showScore: Display score during quiz
5375
- - allowRetry: Allow retrying incorrect answers
4008
+ - "add a sunburst background", "bokeh effect", "gradient mesh"
4009
+ - "create wave pattern", "wind field", "fluid flow"
4010
+ - "grid background", "geometric abstract", "noise texture"
4011
+ - Creating dynamic procedural backgrounds
5376
4012
 
5377
- EXAMPLE:
5378
- {
5379
- "title": "Geography Quiz",
5380
- "questions": [
5381
- {
5382
- "type": "multiple-choice",
5383
- "prompt": "What is the capital of France?",
5384
- "options": [
5385
- {"id": "a", "label": "London"},
5386
- {"id": "b", "label": "Paris", "isCorrect": true},
5387
- {"id": "c", "label": "Berlin"}
5388
- ],
5389
- "points": 10,
5390
- "correctFeedback": "Correct! Paris is the capital.",
5391
- "incorrectFeedback": "Sorry, the correct answer is Paris."
5392
- }
5393
- ],
5394
- "passingScore": 70,
5395
- "showScore": true
5396
- }`,
4013
+ GENERATORS (15 total):
4014
+
4015
+ Classic:
4016
+ - drawSunburst: Radial rays from center (rayCount, colors, bgColor, opacity, rayGap, gradientRays)
4017
+ - drawSunsetScene: Animated sunset with clouds (sunColor, skyColors, cloudCount, skyOpacity, starCount, starColor, reflectionEnabled, reflectionOpacity)
4018
+ - drawGrid: Lines/dots/squares (gridType, spacing, lineColor, opacity, gap, randomRotation, colorMode: checkerboard|gradient|random|rows|columns, strokeColor, strokeWidth)
4019
+ - drawStackedCircles: Overlapping circles (count, colors, distribution: random|poisson|golden, opacityMin, opacityMax, blendMode, strokeWidth, strokeColor, sizeGradient, animationType: pulse|float|none)
4020
+ - drawCircuit: Tech circuit board (lineColor, nodeColor, density, traceOpacity, nodeOpacity, diagonalPaths, chipDensity: auto|none|low|medium|high)
4021
+ - drawWaves: Layered wave pattern (waveCount, colors, amplitude, frequency, opacity, fill, fillOpacity, amplitudeVariation, blendMode)
4022
+ - drawPattern: Geometric shapes in orbit (patternType, size, color, opacity, blendMode, layers: 1-5, layerScaleDecay)
4023
+
4024
+ New — Effects:
4025
+ - drawBokeh: Soft-focus circles (count, colors, minRadius, maxRadius, shadowBlur, distribution: random|poisson, driftAnimation)
4026
+
4027
+ New — Organic:
4028
+ - drawGradientMesh: Radial gradient blobs with screen blending (colors, blobCount, blendMode, drift)
4029
+ - drawFluidFlow: Sinusoidal stream paths with depth (streamCount, colors, depthLayers, speed)
4030
+ - drawOrganicFlow: Aurora/silk layers with fill-to-bottom (layerCount, colors, blendMode, fillToBottom)
4031
+
4032
+ New — Geometric:
4033
+ - drawGeometricAbstract: Mixed translucent shapes (colors, shapeCount, blendMode, rotation)
4034
+
4035
+ New — Particles:
4036
+ - drawWindField: Directional wind particles with noise turbulence (particleCount, colors, direction, turbulence, trailLength, speed)
4037
+
4038
+ New — Textures:
4039
+ - drawNoiseTexture: Perlin/grain/stipple noise (noiseType: perlin|grain|stipple, colors, scale, density, animated)
4040
+
4041
+ New — Tech:
4042
+ - drawGlobeWireframe: Vercel-style wireframe globe (bgColor, wireColor, glowColor, highlightColor, meridianCount, latitudeCount, globeRadius, nodeCount, nodeSize, animationEnabled, animationSpeed, strokeWidth, gridOpacity)
4043
+
4044
+ PineMath — Math/Science:
4045
+ - drawFunctionPlot: Plot y=f(x) (expression, xMin, xMax, yMin, yMax, color, lineWidth, showAxes, showGrid, steps, animate: none|scroll-right|scroll-left|oscillate|bounce|wipe|custom)
4046
+ - drawParametricCurve: Plot (x(t),y(t)) Lissajous/spirals/roses (xExpression, yExpression, tMin, tMax, color, steps, scale, animate: none|linear|slow|fast|wave|bounce, trailFade)
4047
+ - drawSimulation: Dynamic systems with ODE solvers (preset: pendulum|springMass|lorenz|doublePendulum|vanderpol, solver: euler|rk4|rk45, timeScale, showTrail, trailLength, trailColor, objectColor)
4048
+ - drawSpectrumAnalyzer: FFT signal visualization (waveform: sine|square|sawtooth|triangle|noise|composite, frequency, amplitude, sampleRate, window: none|hann|hamming|blackman, waveColor, spectrumColor)
4049
+ - draw3DSurface: 3D surfaces from equations (preset: torus|sphere|wave|klein|mobius|custom, xExpr, yExpr, zExpr, uSteps, vSteps, scale, rotateSpeed)
4050
+
4051
+ COMMON PARAMS (all generators):
4052
+ - bgColor: Background color ("none"/"transparent" for no background)
4053
+ - interactive: Make generated items selectable/draggable (default false)
4054
+ - clipToCanvas: Clip output to canvas bounds (default true, set false for overflow)`,
5397
4055
  inputSchema: {
5398
4056
  type: 'object',
5399
4057
  properties: {
5400
- title: {
4058
+ generatorName: {
5401
4059
  type: 'string',
5402
- description: 'Quiz title',
5403
- },
5404
- questions: {
5405
- type: 'array',
5406
- items: {
5407
- type: 'object',
5408
- properties: {
5409
- type: {
5410
- type: 'string',
5411
- enum: ['multiple-choice', 'multiple-select', 'drag-drop', 'matching', 'sequencing', 'hotspot', 'true-false'],
5412
- description: 'Question type',
5413
- },
5414
- prompt: {
5415
- type: 'string',
5416
- description: 'Question text',
5417
- },
5418
- options: {
5419
- type: 'array',
5420
- items: {
5421
- type: 'object',
5422
- properties: {
5423
- id: { type: 'string' },
5424
- label: { type: 'string' },
5425
- isCorrect: { type: 'boolean' },
5426
- },
5427
- },
5428
- description: 'Answer options',
5429
- },
5430
- points: {
5431
- type: 'number',
5432
- description: 'Points for correct answer',
5433
- },
5434
- correctFeedback: {
5435
- type: 'string',
5436
- description: 'Feedback for correct answer',
5437
- },
5438
- incorrectFeedback: {
5439
- type: 'string',
5440
- description: 'Feedback for incorrect answer',
5441
- },
5442
- draggableItems: {
5443
- type: 'array',
5444
- items: { type: 'string' },
5445
- description: 'Item IDs that can be dragged (for drag-drop)',
5446
- },
5447
- dropZones: {
5448
- type: 'array',
5449
- items: {
5450
- type: 'object',
5451
- properties: {
5452
- id: { type: 'string' },
5453
- correctItems: { type: 'array', items: { type: 'string' } },
5454
- },
5455
- },
5456
- description: 'Drop zones with correct items (for drag-drop)',
5457
- },
5458
- },
5459
- required: ['type', 'prompt', 'points'],
5460
- },
5461
- description: 'Quiz questions',
5462
- },
5463
- passingScore: {
5464
- type: 'number',
5465
- description: 'Minimum percentage to pass (0-100)',
5466
- },
5467
- showScore: {
5468
- type: 'boolean',
5469
- description: 'Display score during quiz',
5470
- },
5471
- allowRetry: {
5472
- type: 'boolean',
5473
- description: 'Allow retrying incorrect answers',
5474
- },
5475
- shuffleQuestions: {
5476
- type: 'boolean',
5477
- description: 'Randomize question order',
4060
+ enum: [
4061
+ 'drawSunburst', 'drawSunsetScene', 'drawGrid', 'drawStackedCircles',
4062
+ 'drawCircuit', 'drawWaves', 'drawPattern',
4063
+ 'drawBokeh', 'drawGradientMesh', 'drawGeometricAbstract', 'drawWindField',
4064
+ 'drawFluidFlow', 'drawOrganicFlow', 'drawNoiseTexture',
4065
+ 'drawGlobeWireframe',
4066
+ 'drawFunctionPlot', 'drawParametricCurve', 'drawSimulation',
4067
+ 'drawSpectrumAnalyzer', 'draw3DSurface',
4068
+ ],
4069
+ description: 'Generator name',
5478
4070
  },
5479
- shuffleOptions: {
5480
- type: 'boolean',
5481
- description: 'Randomize answer options',
4071
+ params: {
4072
+ type: 'object',
4073
+ description: 'Generator-specific parameters',
4074
+ additionalProperties: true,
5482
4075
  },
5483
4076
  },
5484
- required: ['questions'],
4077
+ required: ['generatorName'],
4078
+ },
4079
+ },
4080
+ {
4081
+ name: 'pinepaper_list_generators',
4082
+ annotations: {
4083
+ title: 'List Generators',
4084
+ readOnlyHint: true,
4085
+ destructiveHint: false,
4086
+ idempotentHint: true,
4087
+ openWorldHint: false,
4088
+ },
4089
+ description: `[Utility] Get a list of all available background generators with their parameters.
4090
+
4091
+ USE WHEN:
4092
+ - User asks "what backgrounds are available?"
4093
+ - Need to show generator options
4094
+ - Discovering generator capabilities`,
4095
+ inputSchema: {
4096
+ type: 'object',
4097
+ properties: {},
5485
4098
  },
5486
4099
  },
4100
+ // ---------------------------------------------------------------------------
4101
+ // DOMAIN: EFFECT TOOLS
4102
+ // ---------------------------------------------------------------------------
5487
4103
  {
5488
- name: 'pinepaper_get_quiz_state',
4104
+ name: 'pinepaper_apply_effect',
5489
4105
  annotations: {
5490
- title: 'Get Quiz State',
5491
- readOnlyHint: true,
4106
+ title: 'Apply Effect',
4107
+ readOnlyHint: false,
5492
4108
  destructiveHint: false,
5493
- idempotentHint: true,
4109
+ idempotentHint: false,
5494
4110
  openWorldHint: false,
5495
4111
  },
5496
- description: `[Utility] Get the current state of an active quiz.
4112
+ description: `Apply a visual effect to an item.
5497
4113
 
5498
4114
  USE WHEN:
5499
- - Checking quiz progress
5500
- - Getting current score
5501
- - Reviewing answered questions
5502
- - Debugging quiz behavior
4115
+ - Adding sparkle/glitter effects
4116
+ - Creating burst/explosion, fire, smoke effects
4117
+ - Weather effects (rain, snow)
4118
+ - Celebration effects (confetti)
4119
+ - Enhancing visual impact (ripple, glow, electric)
5503
4120
 
5504
- RETURNS:
5505
- - quizId: Quiz identifier
5506
- - currentQuestion: Current question index
5507
- - totalQuestions: Total number of questions
5508
- - score: Current score
5509
- - maxScore: Maximum possible score
5510
- - answers: Array of submitted answers
5511
- - passed: Whether passing score achieved (if complete)
5512
- - complete: Whether quiz is finished`,
4121
+ EFFECTS (15 total):
4122
+ - sparkle: Glitter/sparkle particles (color, speed, size)
4123
+ - blast: Explosion burst effect (color, radius, count)
4124
+ - smoke: Rising smoke plumes (color, speed, size, drift, height, growthRate)
4125
+ - fire: Animated fire/flames (color, colors, speed, size, height, turbulence)
4126
+ - rain: Falling rain drops (color, count, speed, angle, spread)
4127
+ - snow: Falling snowflakes (color, count, speed, spread, particleLife)
4128
+ - confetti: Celebration confetti (colors, count, radius, gravity, size, spread, interval, repeat)
4129
+ - ripple: Expanding ring ripples (color, speed, maxRadius, ringCount, strokeWidth)
4130
+ - glow: Pulsing glow aura (color drives the shadow halo; speed, intensity, size; optional fill — interior tint decoupled from color; fillOpacity 0..1 multiplies intensity opacity)
4131
+ - electric: Lightning bolts (color, speed, boltCount, length, flickerRate)
4132
+ - bubbles: Rising transparent bubbles (color drives the rim; count, speed, size, spread; optional fill — interior tint, default null = outlined-only; fillOpacity 0..1, default 0.25 when fill is set)
4133
+ - dust: Ambient drifting motes (color, count, speed, size, spread)
4134
+ - fireflies: Glowing wandering dots (color, count, speed, size, spread)
4135
+ - shockwave: Expanding concentric rings — burst type (speed, maxRadius, count, thickness)
4136
+ - trail: Fading afterimages following movement (speed, count, size, fadeRate)
4137
+
4138
+ EXAMPLE — bubbles with magenta interior over a blue rim:
4139
+ { effectType: "bubbles", params: { color: "#93c5fd", fill: "#ff00aa", fillOpacity: 0.4 } }`,
5513
4140
  inputSchema: {
5514
4141
  type: 'object',
5515
4142
  properties: {
5516
- quizId: {
4143
+ itemId: { type: 'string', description: 'Registry ID of the item' },
4144
+ effectType: {
5517
4145
  type: 'string',
5518
- description: 'Quiz ID (optional, uses active quiz if not specified)',
4146
+ enum: ['sparkle', 'blast', 'smoke', 'fire', 'rain', 'snow', 'confetti', 'ripple', 'glow', 'electric', 'bubbles', 'dust', 'fireflies', 'shockwave', 'trail'],
4147
+ description: 'Type of effect',
4148
+ },
4149
+ params: {
4150
+ type: 'object',
4151
+ description: 'Effect parameters',
4152
+ additionalProperties: true,
5519
4153
  },
5520
4154
  },
4155
+ required: ['itemId', 'effectType'],
5521
4156
  },
5522
4157
  },
4158
+ // ---------------------------------------------------------------------------
4159
+ // DOMAIN: FILTER TOOLS
4160
+ // ---------------------------------------------------------------------------
5523
4161
  {
5524
- name: 'pinepaper_reset_quiz',
4162
+ name: 'pinepaper_add_filter',
5525
4163
  annotations: {
5526
- title: 'Reset Quiz',
4164
+ title: 'Add Filter',
5527
4165
  readOnlyHint: false,
5528
- destructiveHint: true,
5529
- idempotentHint: true,
4166
+ destructiveHint: false,
4167
+ idempotentHint: false,
5530
4168
  openWorldHint: false,
5531
4169
  },
5532
- description: `Reset a quiz to its initial state.
4170
+ description: `Add a visual filter effect to the canvas. Filters are scene-wide effects that can be stacked.
5533
4171
 
5534
4172
  USE WHEN:
5535
- - Restarting a quiz
5536
- - Clearing quiz progress
5537
- - Allowing user to retake quiz`,
4173
+ - User wants visual effects like blur, grayscale, vintage look
4174
+ - Creating mood or atmosphere (cinematic, dreamy, noir)
4175
+ - Post-processing the entire scene
4176
+ - User says "make it look vintage", "add blur", "black and white"
4177
+
4178
+ AVAILABLE FILTERS:
4179
+ - grayscale: Convert to black and white (params: intensity 0-1)
4180
+ - sepia: Warm vintage brownish tone (params: intensity 0-1)
4181
+ - blur: Gaussian blur effect (params: radius 0-20)
4182
+ - brightness: Adjust brightness (params: value -100 to 100)
4183
+ - contrast: Adjust contrast (params: value -100 to 100)
4184
+ - saturate: Adjust color saturation (params: value -100 to 100)
4185
+ - invert: Invert colors (params: intensity 0-1)
4186
+ - noise: Add film grain (params: intensity 0-100, monochrome: true/false)
4187
+ - vignette: Darken edges (params: intensity 0-1, radius 0-1)
4188
+ - vintage: Preset combining sepia, vignette, noise
4189
+ - colorOverlay: Add color tint (params: color, intensity, blendMode)
4190
+ - sharpen: Increase sharpness (params: intensity 0-100)
4191
+ - posterize: Reduce color levels (params: levels 2-32)
4192
+
4193
+ EXAMPLES:
4194
+ - "Make it black and white" → filterType: "grayscale"
4195
+ - "Add vintage look" → filterType: "vintage", params: {intensity: 0.8}
4196
+ - "Blur the background" → filterType: "blur", params: {radius: 5}
4197
+ - "Increase contrast" → filterType: "contrast", params: {value: 30}
4198
+
4199
+ Filters can be stacked - call multiple times to combine effects.`,
5538
4200
  inputSchema: {
5539
4201
  type: 'object',
5540
4202
  properties: {
5541
- quizId: {
4203
+ filterType: {
5542
4204
  type: 'string',
5543
- description: 'Quiz ID (optional, uses active quiz if not specified)',
4205
+ enum: ['grayscale', 'sepia', 'blur', 'brightness', 'contrast', 'saturate', 'invert', 'noise', 'vignette', 'vintage', 'colorOverlay', 'sharpen', 'posterize'],
4206
+ description: 'Type of filter to apply',
4207
+ },
4208
+ params: {
4209
+ type: 'object',
4210
+ description: 'Filter-specific parameters',
4211
+ additionalProperties: true,
5544
4212
  },
5545
4213
  },
4214
+ required: ['filterType'],
5546
4215
  },
5547
4216
  },
5548
4217
  // ---------------------------------------------------------------------------
@@ -5723,6 +4392,10 @@ RETURNS:
5723
4392
  type: 'boolean',
5724
4393
  description: 'Run in headless mode (default: false when explicitly called)',
5725
4394
  },
4395
+ url: {
4396
+ type: 'string',
4397
+ description: 'Studio URL to connect to (e.g. "http://localhost:3000" for local dev). Must be http:// or https:// — file:/data:/javascript: are rejected. Overrides the PINEPAPER_STUDIO_URL env var and the prod default. "/editor" and agent-mode params are added automatically. Passing a URL with a different origin/pathname reconnects.',
4398
+ },
5726
4399
  },
5727
4400
  },
5728
4401
  },
@@ -5957,7 +4630,7 @@ PRIVACY: No screenshots, no tool call arguments, no user content — only struct
5957
4630
 
5958
4631
  WORKFLOW: start_job → batch_execute (everything in ONE call) → end_job (screenshot) → show user → iterate if needed.
5959
4632
 
5960
- RETURNS: canvasSize {width, height} — use this to position items within bounds.
4633
+ RETURNS: canvasSize {width, height} — use this to position items within bounds. Also returns ontology: a pp: triples + item summary snapshot of the (typically empty) canvas. Reuse this baseline across the same agent turn instead of calling pinepaper_get_canvas_ontology unless you've mutated the canvas. When clearCanvas is false, the ontology captures whatever's already on the canvas.
5961
4634
 
5962
4635
  CANVAS PRESETS: instagram (1080x1080), instagram-story (1080x1920), tiktok (1080x1920), youtube (1920x1080), youtube-thumbnail (1280x720), twitter (1200x675), linkedin (1200x627), web, print-a4, print-letter`,
5963
4636
  inputSchema: {
@@ -5985,6 +4658,10 @@ CANVAS PRESETS: instagram (1080x1080), instagram-story (1080x1920), tiktok (1080
5985
4658
  type: 'boolean',
5986
4659
  description: 'Clear canvas when starting job (default: true)',
5987
4660
  },
4661
+ includeOntology: {
4662
+ type: 'boolean',
4663
+ description: 'Include canvas ontology snapshot in the result (default: true). Pre-bundles a pp: triples baseline so the agent can reason about composition without a follow-up pinepaper_get_canvas_ontology call.',
4664
+ },
5988
4665
  },
5989
4666
  },
5990
4667
  },
@@ -6112,6 +4789,8 @@ NOTE: For diagrams (flowcharts, UML), use pinepaper_create_diagram_shape + pinep
6112
4789
 
6113
4790
  ⚠️ SIZING: All positions/sizes MUST fit within the canvas. start_job returns canvasSize. Keep items within 5%-95% of canvas width/height. Max canvas: 4096x4096.
6114
4791
 
4792
+ ONTOLOGY PREFLIGHT: Before code generation, this tool validates itemType, relationType, effectType, and generatorName against the canonical PinePaper vocabulary. A typo (e.g. "circel") returns a structured VALIDATION_ERROR with the operation index, the offending field, the canonical valid list, and a suggested fix — fix and retry rather than guessing. Pass skipValidation: true to bypass when intentionally using experimental vocabulary.
4793
+
6115
4794
  WORKFLOW:
6116
4795
  1. pinepaper_agent_start_job → 2. pinepaper_agent_batch_execute (everything) → 3. pinepaper_agent_end_job (screenshot for validation)
6117
4796
  After validation: user reviews screenshot → feedback → modify/recreate as needed.
@@ -6122,7 +4801,8 @@ CANVAS SETUP:
6122
4801
  set_canvas_size — {width, height} or {preset: "instagram"|"youtube"|"tiktok"|...}
6123
4802
  set_background — {backgroundColor: "#hex"}
6124
4803
  execute_generator — {generatorName, generatorParams} → fills canvas with procedural art
6125
- Generators: drawBokeh, drawGradientMesh, drawWaves, drawSunburst, drawSunsetScene, drawGrid, drawCircuit, drawPattern, drawStackedCircles, drawGeometricAbstract, drawWindField, drawFluidFlow, drawOrganicFlow, drawNoiseTexture
4804
+ Generators: drawBokeh, drawGradientMesh, drawWaves, drawSunburst, drawSunsetScene, drawGrid, drawCircuit, drawPattern, drawStackedCircles, drawGeometricAbstract, drawWindField, drawFluidFlow, drawOrganicFlow, drawNoiseTexture, drawGlobeWireframe
4805
+ PineMath: drawFunctionPlot (y=f(x) plots), drawParametricCurve (x(t),y(t)), drawSimulation (pendulum, Lorenz, spring-mass), drawSpectrumAnalyzer (FFT), draw3DSurface (torus, sphere, Klein bottle)
6126
4806
 
6127
4807
  ITEMS:
6128
4808
  create — {itemType, position: {x,y}, properties}
@@ -6140,23 +4820,27 @@ ITEMS:
6140
4820
 
6141
4821
  ANIMATION:
6142
4822
  animate — Loop animation: {itemId, animationType, animationOptions}
6143
- animationType: pulse, rotate, bounce, fade, wobble, slide, typewriter
4823
+ animationType: ${SIMPLE_ANIMATION_TYPES_LIST}
6144
4824
  keyframe_animate — Timed animation: {itemId, keyframes: [{time, properties, easing}], duration, loop}
6145
4825
  Animatable properties: opacity, scale, scaleX, scaleY, x, y, rotation, fillColor, strokeColor, fontSize
6146
4826
  Easing: easeInOut, easeIn, easeOut, easeInCubic, easeOutCubic, easeOutBounce, linear
6147
4827
  relation — Behavioral link: {sourceId, targetId, relationType, relationOptions}
6148
- relationType: orbits, follows, attached_to, points_at, mirrors, parallax, wave_through, morphs_to (+ 9 more in schema)
4828
+ relationType: orbits, follows, attached_to, points_at, mirrors, parallax, wave_through, morphs_to, group_morphs_to, moves_along_path (+ 9 more in schema)
6149
4829
 
6150
4830
  EFFECTS:
6151
4831
  apply_mask — Reveal effect: {itemId, maskPreset, maskOptions}
6152
4832
  maskPreset: wipeLeft, wipeRight, wipeUp, wipeDown, iris, irisOut, star, heart, curtainHorizontal, curtainVertical, cinematic, diagonalWipe, revealUp, revealDown
6153
4833
  apply_effect — Visual effect: {itemId, effectType, effectParams}
6154
- effectType: sparkle, blast
4834
+ effectType: ${EFFECT_TYPES_LIST}
6155
4835
 
6156
4836
  PLAYBACK:
6157
4837
  play_timeline — {action: "play"|"stop"|"seek", duration, loop}
6158
4838
 
6159
- VARIABLE REFERENCES: "$0", "$1" etc. reference items by creation order within the batch.
4839
+ 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.
4840
+
4841
+ ANIMATION NOTES:
4842
+ - 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.
4843
+ - For MP4/GIF export the keyframe timeline is rendered once across the duration; author motion to fill the clip and use loop:false. Looping item-animations (loop:true) are not advanced by the exporter and render frozen.
6160
4844
 
6161
4845
  EXAMPLE — Animated sky scene with timed reveals:
6162
4846
  {operations: [
@@ -6237,7 +4921,7 @@ EXAMPLE — Animated sky scene with timed reveals:
6237
4921
  targetId: { type: 'string', description: 'For relation: target item ID or $N' },
6238
4922
  relationType: {
6239
4923
  type: 'string',
6240
- enum: ['orbits', 'follows', 'attached_to', 'points_at', 'mirrors', 'parallax', 'animates', 'grows_from', 'staggered_with', 'wave_through', 'circumscribes', 'morphs_to', 'maintains_distance', 'bounds_to', 'indicates', 'camera_follows', 'camera_animates'],
4924
+ enum: ['orbits', 'follows', 'attached_to', 'points_at', 'mirrors', 'parallax', 'animates', 'grows_from', 'staggered_with', 'wave_through', 'circumscribes', 'morphs_to', 'group_morphs_to', 'moves_along_path', 'maintains_distance', 'bounds_to', 'indicates', 'camera_follows', 'camera_animates'],
6241
4925
  description: 'For relation: type',
6242
4926
  },
6243
4927
  relationOptions: { type: 'object', description: 'For relation: options' },
@@ -6252,7 +4936,7 @@ EXAMPLE — Animated sky scene with timed reveals:
6252
4936
  // Effects
6253
4937
  effectType: {
6254
4938
  type: 'string',
6255
- enum: ['sparkle', 'blast', 'smoke', 'fire', 'rain', 'snow', 'confetti', 'ripple', 'glow', 'electric'],
4939
+ enum: ['sparkle', 'blast', 'smoke', 'fire', 'rain', 'snow', 'confetti', 'ripple', 'glow', 'electric', 'bubbles', 'dust', 'fireflies', 'shockwave', 'trail'],
6256
4940
  description: 'For apply_effect: effect type',
6257
4941
  },
6258
4942
  effectParams: { type: 'object', description: 'For apply_effect: parameters' },
@@ -6272,6 +4956,10 @@ EXAMPLE — Animated sky scene with timed reveals:
6272
4956
  type: 'boolean',
6273
4957
  description: 'If true, all operations succeed or all fail (default: true)',
6274
4958
  },
4959
+ skipValidation: {
4960
+ type: 'boolean',
4961
+ description: 'Skip the ontology preflight that catches vocabulary typos before browser execution (default: false). Only set true when knowingly using experimental values.',
4962
+ },
6275
4963
  },
6276
4964
  required: ['operations'],
6277
4965
  },
@@ -6299,6 +4987,7 @@ PLATFORMS & OPTIMAL FORMATS:
6299
4987
 
6300
4988
  FORMATS: svg, png, gif, mp4, webm, pdf.
6301
4989
  QUALITY: draft, standard, high.
4990
+ FRAMING: canvas (default, full canvas) | camera (camera_animates first-keyframe viewport — video formats only, requires a keyframe-mode walkthrough on the canvas; camera animation still drives motion within the fixed output frame).
6302
4991
 
6303
4992
  ⚠️ If export fails, do NOT retry with different formats — report the error to the user.
6304
4993
  ⚠️ When user asks for "video", always use format: "mp4".
@@ -6306,7 +4995,8 @@ QUALITY: draft, standard, high.
6306
4995
  EXAMPLES:
6307
4996
  - {platform: "instagram"} — auto-selects best format
6308
4997
  - {platform: "instagram", format: "mp4"} — force MP4
6309
- - {platform: "web", format: "svg"} — animated SVG`,
4998
+ - {platform: "web", format: "svg"} — animated SVG
4999
+ - {platform: "youtube", format: "mp4", framing: "camera"} — render only what the camera frames during the walkthrough`,
6310
5000
  inputSchema: {
6311
5001
  type: 'object',
6312
5002
  properties: {
@@ -6325,6 +5015,17 @@ EXAMPLES:
6325
5015
  enum: ['draft', 'standard', 'high'],
6326
5016
  description: 'Export quality level (default: standard)',
6327
5017
  },
5018
+ framing: {
5019
+ type: 'string',
5020
+ enum: ['canvas', 'camera'],
5021
+ description: 'Output framing. "canvas" (default) renders the full canvas. "camera" renders only the first-keyframe viewport of a camera_animates walkthrough — video formats only.',
5022
+ },
5023
+ duration: {
5024
+ type: 'number',
5025
+ minimum: 0.5,
5026
+ maximum: 60,
5027
+ description: 'Video duration in seconds for mp4/webm/gif (default 5, max 60). Static formats ignore this. If you set play_timeline to N seconds, pass the same N here.',
5028
+ },
6328
5029
  },
6329
5030
  required: ['platform'],
6330
5031
  },
@@ -6385,38 +5086,6 @@ EXAMPLE RESPONSE:
6385
5086
  },
6386
5087
  },
6387
5088
  // ---------------------------------------------------------------------------
6388
- // LAYER 1 — ATOMS: CANVAS PRESETS TOOL
6389
- // ---------------------------------------------------------------------------
6390
- {
6391
- name: 'pinepaper_get_canvas_presets',
6392
- annotations: {
6393
- title: 'Get Canvas Presets',
6394
- readOnlyHint: true,
6395
- destructiveHint: false,
6396
- idempotentHint: true,
6397
- openWorldHint: false,
6398
- },
6399
- description: `[Utility] List all available canvas presets with their dimensions.
6400
-
6401
- USE WHEN:
6402
- - Setting up canvas for specific platforms (YouTube, Instagram, TikTok, etc.)
6403
- - Discovering available size presets
6404
- - Planning content dimensions
6405
- - Building UI for size selection
6406
-
6407
- PRESETS BY CATEGORY:
6408
- - Video: youtube-thumbnail, youtube-short, tiktok, hd-720p, full-hd-1080p
6409
- - Social: instagram-story, instagram-post, facebook-post, twitter-post, linkedin-post, pinterest-pin
6410
- - Presentation: presentation-16x9, presentation-4x3
6411
-
6412
- RETURNS:
6413
- Array of presets with: key, name, width, height, aspectRatio, category`,
6414
- inputSchema: {
6415
- type: 'object',
6416
- properties: {},
6417
- },
6418
- },
6419
- // ---------------------------------------------------------------------------
6420
5089
  // COMPATIBILITY: P5.JS TOOLS
6421
5090
  // ---------------------------------------------------------------------------
6422
5091
  {
@@ -6584,6 +5253,41 @@ EXAMPLES:
6584
5253
  // ---------------------------------------------------------------------------
6585
5254
  // ONTOLOGY TOOLS (Design Knowledge Graph)
6586
5255
  // ---------------------------------------------------------------------------
5256
+ {
5257
+ name: 'pinepaper_get_canvas_ontology',
5258
+ annotations: {
5259
+ title: 'Get Canvas Ontology',
5260
+ readOnlyHint: true,
5261
+ destructiveHint: false,
5262
+ idempotentHint: true,
5263
+ openWorldHint: false,
5264
+ },
5265
+ description: `Capture the live canvas as compact pp: ontology triples + a structured item summary.
5266
+
5267
+ USE THIS instead of pinepaper_get_items when you need to REASON about composition (what's on the canvas, how items relate, what's animated). Typical scenes shrink 3-10× compared to a raw item dump while preserving relations, animations, effects, masks, and collage styling.
5268
+
5269
+ OUTPUT (a snapshot of FxTool's canvas state):
5270
+ - canvasWidth, canvasHeight, canvasPreset
5271
+ - itemCount, itemTypes ([unique]), hasAnimations, relationCount
5272
+ - items: capped item summaries with positions, colors, group structure, collage metadata, keyframes, effects, deformations
5273
+ - triples: a TripleLanguage-serialized pp: triple block (compact tokenized form). Read this for structural reasoning.
5274
+ - viewport (when includeViewport: true): zoom + center + hasCameraAnimation flag
5275
+
5276
+ OPTIONS:
5277
+ - maxItems (default 50): cap on item summaries. Larger scenes are truncated, not paginated — pinepaper_query_ontology and pinepaper_get_items remain available for full enumeration.
5278
+ - maxChildren (default 10): cap on per-group child summaries.
5279
+ - includeViewport (default false): include zoom/pan/camera-animation flag.
5280
+
5281
+ NOTE: Requires FxTool with the canvas-ontology promotion. Returns { success: false, error } with a clear hint when running against an older build.`,
5282
+ inputSchema: {
5283
+ type: 'object',
5284
+ properties: {
5285
+ maxItems: { type: 'number', description: 'Cap on item summaries (default 50, max 500).' },
5286
+ maxChildren: { type: 'number', description: 'Cap on per-group child summaries (default 10, max 50).' },
5287
+ includeViewport: { type: 'boolean', description: 'Include zoom/pan/camera-animation state (default false).' },
5288
+ },
5289
+ },
5290
+ },
6587
5291
  {
6588
5292
  name: 'pinepaper_analyze_design',
6589
5293
  annotations: {
@@ -6727,8 +5431,10 @@ Lookup:
6727
5431
 
6728
5432
  USE WHEN: You need full parameter docs, examples, or workflow guidance — especially in minimal verbosity mode where tool descriptions are short summaries.
6729
5433
 
5434
+ 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.
5435
+
6730
5436
  MODES:
6731
- - No args → returns the full AI Agent Guide (workflow, rules, batch operations, visual composition tips)
5437
+ - No args → returns the full AI Agent Guide (same content as pinepaper://docs/agent-guide)
6732
5438
  - tool: "pinepaper_agent_batch_execute" → returns that tool's full verbose description
6733
5439
  - category: "animation" → returns all tools in that category with full descriptions
6734
5440
 
@@ -6794,6 +5500,224 @@ VERBOSITY:
6794
5500
  },
6795
5501
  },
6796
5502
  },
5503
+ // ---------------------------------------------------------------------------
5504
+ // DATA VISUALIZATION (CHARTS)
5505
+ // ---------------------------------------------------------------------------
5506
+ {
5507
+ name: 'pinepaper_create_chart',
5508
+ annotations: {
5509
+ title: 'Create Chart',
5510
+ readOnlyHint: false,
5511
+ destructiveHint: false,
5512
+ idempotentHint: false,
5513
+ openWorldHint: false,
5514
+ },
5515
+ description: `Create and manage data visualizations on the canvas.
5516
+
5517
+ ACTIONS:
5518
+ - create: Create a chart. Params: chartType, data (array of objects), options
5519
+ - update: Update chart data. Params: chartId, data, options
5520
+ - reconfigure: Change chart styling. Params: chartId, options
5521
+ - remove: Delete a chart. Params: chartId
5522
+
5523
+ CHART TYPES: bar, line, scatter, area
5524
+
5525
+ DATA FORMAT: Array of objects, e.g. [{category: "A", value: 10}, {category: "B", value: 20}]
5526
+
5527
+ OPTIONS (vary by chart type):
5528
+ - Common: title, width, height, x, y, colors, animation, axisColor, labelColor, labelFontSize
5529
+ - Bar: barWidth, barGap, xLabel, yLabel
5530
+ orient: 'horizontal' flips bars to grow rightward from a left Y-axis — best for long category names
5531
+ labelArrangement: 'auto'|'horizontal'|'slanted'|'vertical'|'truncate'|'wrap'
5532
+ auto — smart: measures widest label and picks horizontal → slanted (−45°) → vertical (−90°) by slot width
5533
+ slanted — force −45° rotation
5534
+ vertical — force −90° rotation
5535
+ truncate — ellipsis when label exceeds slot (uses ctx.measureText; override char cap with labelTruncateMaxChars)
5536
+ wrap — split on last space before midpoint, up to two lines
5537
+ Bottom-margin is capped at 25% (slanted) / 35% (vertical) of chart height, so changing labelFontSize shifts labels inside a stable budget rather than shrinking the bars.
5538
+ - Line: lineColor, lineWidth, xLabel, yLabel
5539
+ - Scatter: dotColor, dotRadius
5540
+ - Area: fillColor, lineColor, lineWidth
5541
+
5542
+ Data field mapping: use xField/yField in options to specify which data keys to use for axes.`,
5543
+ inputSchema: {
5544
+ type: 'object',
5545
+ properties: {
5546
+ action: {
5547
+ type: 'string',
5548
+ enum: ['create', 'update', 'reconfigure', 'remove'],
5549
+ description: 'Chart action',
5550
+ },
5551
+ chartType: {
5552
+ type: 'string',
5553
+ enum: ['bar', 'line', 'scatter', 'area'],
5554
+ description: 'Chart type (for create)',
5555
+ },
5556
+ chartId: { type: 'string', description: 'Chart ID (for update/reconfigure/remove)' },
5557
+ data: {
5558
+ type: 'array',
5559
+ items: { type: 'object' },
5560
+ description: 'Data array of objects (for create/update)',
5561
+ },
5562
+ options: {
5563
+ type: 'object',
5564
+ description: 'Chart options (colors, title, dimensions, field mapping, animation)',
5565
+ },
5566
+ },
5567
+ required: ['action'],
5568
+ },
5569
+ },
5570
+ // ---------------------------------------------------------------------------
5571
+ // MAGIC SYSTEM
5572
+ // ---------------------------------------------------------------------------
5573
+ {
5574
+ name: 'pinepaper_magic',
5575
+ annotations: {
5576
+ title: 'Magic',
5577
+ readOnlyHint: false,
5578
+ destructiveHint: false,
5579
+ idempotentHint: false,
5580
+ openWorldHint: false,
5581
+ },
5582
+ description: `Ontology-aware auto-animation and style remixing.
5583
+
5584
+ ACTIONS:
5585
+ - animate: Apply mood-driven animations, effects, and deformations. Params: mood, selectionOnly
5586
+ - remix: Non-destructive style cycling (colors, fonts, shadows). Params: selectionOnly
5587
+
5588
+ MOODS: calm, professional, energetic, dramatic, whimsical
5589
+
5590
+ The magic system analyzes canvas content via the design graph, selects type-appropriate treatments (animations for shapes, collage for text, filters for images), and tracks provenance.`,
5591
+ inputSchema: {
5592
+ type: 'object',
5593
+ properties: {
5594
+ action: {
5595
+ type: 'string',
5596
+ enum: ['animate', 'remix'],
5597
+ description: 'Magic action',
5598
+ },
5599
+ mood: {
5600
+ type: 'string',
5601
+ enum: ['calm', 'professional', 'energetic', 'dramatic', 'whimsical'],
5602
+ description: 'Energy/mood for animation selection',
5603
+ },
5604
+ selectionOnly: { type: 'boolean', description: 'Only affect selected items (default: false)' },
5605
+ },
5606
+ required: ['action'],
5607
+ },
5608
+ },
5609
+ // ---------------------------------------------------------------------------
5610
+ // PHYSICS (RIGID BODY SIMULATION)
5611
+ // ---------------------------------------------------------------------------
5612
+ {
5613
+ name: 'pinepaper_physics',
5614
+ annotations: {
5615
+ title: 'Physics',
5616
+ readOnlyHint: false,
5617
+ destructiveHint: false,
5618
+ idempotentHint: false,
5619
+ openWorldHint: false,
5620
+ },
5621
+ description: `Rigid body physics simulation (Box2D/Planck.js).
5622
+
5623
+ ACTIONS:
5624
+ - init: Start physics world. Params: gravity ({x, y}, default {x:0, y:980})
5625
+ - add_body: Register item as physics body. Params: itemId, bodyType (static|dynamic|kinematic), mass, friction, restitution, fixedRotation, shape (auto|circle|rect)
5626
+ - remove_body: Remove from physics. Params: itemId
5627
+ - apply_force: Continuous force in px/s². Params: itemId, force ({x, y})
5628
+ - apply_impulse: Instant velocity change. Params: itemId, impulse ({x, y})
5629
+ - set_velocity: Set linear velocity. Params: itemId, velocity ({x, y})
5630
+ - get_state: Get body position/velocity/rotation. Params: itemId
5631
+ - create_ground: Static floor plane. Params: y, width
5632
+ - create_joint: Connect two bodies. Params: itemId, targetItemId, jointType (revolute|distance|weld|prismatic), jointParams`,
5633
+ inputSchema: {
5634
+ type: 'object',
5635
+ properties: {
5636
+ action: {
5637
+ type: 'string',
5638
+ enum: ['init', 'add_body', 'remove_body', 'apply_force', 'apply_impulse', 'set_velocity', 'get_state', 'create_ground', 'create_joint'],
5639
+ description: 'Physics action',
5640
+ },
5641
+ itemId: { type: 'string', description: 'Target item ID' },
5642
+ gravity: {
5643
+ type: 'object',
5644
+ properties: { x: { type: 'number' }, y: { type: 'number' } },
5645
+ description: 'Gravity vector (for init)',
5646
+ },
5647
+ bodyType: {
5648
+ type: 'string',
5649
+ enum: ['static', 'dynamic', 'kinematic'],
5650
+ description: 'Physics body type',
5651
+ },
5652
+ mass: { type: 'number', description: 'Body mass (default: 1)' },
5653
+ friction: { type: 'number', description: 'Surface friction (default: 0.3)' },
5654
+ restitution: { type: 'number', description: 'Bounciness 0-1 (default: 0.3)' },
5655
+ fixedRotation: { type: 'boolean', description: 'Prevent rotation' },
5656
+ shape: { type: 'string', enum: ['auto', 'circle', 'rect'], description: 'Collision shape (default: auto)' },
5657
+ force: {
5658
+ type: 'object',
5659
+ properties: { x: { type: 'number' }, y: { type: 'number' } },
5660
+ description: 'Force vector in px/s²',
5661
+ },
5662
+ impulse: {
5663
+ type: 'object',
5664
+ properties: { x: { type: 'number' }, y: { type: 'number' } },
5665
+ description: 'Impulse vector',
5666
+ },
5667
+ velocity: {
5668
+ type: 'object',
5669
+ properties: { x: { type: 'number' }, y: { type: 'number' } },
5670
+ description: 'Velocity vector',
5671
+ },
5672
+ y: { type: 'number', description: 'Ground Y position' },
5673
+ width: { type: 'number', description: 'Ground width' },
5674
+ targetItemId: { type: 'string', description: 'Second item for joint' },
5675
+ jointType: {
5676
+ type: 'string',
5677
+ enum: ['revolute', 'distance', 'weld', 'prismatic'],
5678
+ description: 'Joint type',
5679
+ },
5680
+ jointParams: {
5681
+ type: 'object',
5682
+ description: 'Joint-specific parameters (anchor, enableMotor, motorSpeed, etc.)',
5683
+ },
5684
+ },
5685
+ required: ['action'],
5686
+ },
5687
+ },
5688
+ // ---------------------------------------------------------------------------
5689
+ // MEASUREMENT SYSTEM
5690
+ // ---------------------------------------------------------------------------
5691
+ {
5692
+ name: 'pinepaper_measurement',
5693
+ annotations: {
5694
+ title: 'Measurement',
5695
+ readOnlyHint: false,
5696
+ destructiveHint: false,
5697
+ idempotentHint: true,
5698
+ openWorldHint: false,
5699
+ },
5700
+ description: `Rulers, grid overlay, snap-to-grid, and dimension readout.
5701
+
5702
+ ACTIONS:
5703
+ - set_rulers: Show/hide rulers. Params: enabled (bool)
5704
+ - set_grid: Show/hide unit grid. Params: enabled (bool)
5705
+ - get_dimensions: Get item bounds. Params: itemId → returns {x, y, width, height, rotation}
5706
+ - set_snap: Enable/disable snap-to-grid. Params: enabled (bool)`,
5707
+ inputSchema: {
5708
+ type: 'object',
5709
+ properties: {
5710
+ action: {
5711
+ type: 'string',
5712
+ enum: ['set_rulers', 'set_grid', 'get_dimensions', 'set_snap'],
5713
+ description: 'Measurement action',
5714
+ },
5715
+ enabled: { type: 'boolean', description: 'Enable/disable (for set_rulers, set_grid, set_snap)' },
5716
+ itemId: { type: 'string', description: 'Item ID (for get_dimensions)' },
5717
+ },
5718
+ required: ['action'],
5719
+ },
5720
+ },
6797
5721
  ];
6798
5722
  /**
6799
5723
  * Get a tool definition by name