@pinepaper.studio/mcp-server 1.6.7 → 1.6.9
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.
- package/README.de.md +9 -5
- package/README.es.md +9 -5
- package/README.fr.md +9 -5
- package/README.hi.md +8 -5
- package/README.ja.md +8 -5
- package/README.ko.md +8 -4
- package/README.md +256 -17
- package/README.pt-BR.md +9 -5
- package/README.zh-CN.md +6 -4
- package/dist/browser/index.d.ts +1 -1
- package/dist/browser/index.d.ts.map +1 -1
- package/dist/browser/index.js +1 -1
- package/dist/browser/index.js.map +1 -1
- package/dist/browser/puppeteer-controller.d.ts +86 -2
- package/dist/browser/puppeteer-controller.d.ts.map +1 -1
- package/dist/browser/puppeteer-controller.js +143 -60
- package/dist/browser/puppeteer-controller.js.map +1 -1
- package/dist/character/data/concepts.json +1 -0
- package/dist/character/data/depictions.json +1 -0
- package/dist/character/data/styles.json +1 -0
- package/dist/character/duration-scale.d.ts +13 -0
- package/dist/character/duration-scale.d.ts.map +1 -0
- package/dist/character/duration-scale.js +13 -0
- package/dist/character/duration-scale.js.map +1 -0
- package/dist/character/path-bbox.d.ts +82 -0
- package/dist/character/path-bbox.d.ts.map +1 -0
- package/dist/character/path-bbox.js +496 -0
- package/dist/character/path-bbox.js.map +1 -0
- package/dist/character/perform.d.ts +149 -0
- package/dist/character/perform.d.ts.map +1 -0
- package/dist/character/perform.js +626 -0
- package/dist/character/perform.js.map +1 -0
- package/dist/character/resolve.d.ts +51 -0
- package/dist/character/resolve.d.ts.map +1 -0
- package/dist/character/resolve.js +239 -0
- package/dist/character/resolve.js.map +1 -0
- package/dist/cli.js +12 -0
- package/dist/cli.js.map +1 -1
- package/dist/design/design-systems.d.ts +224 -0
- package/dist/design/design-systems.d.ts.map +1 -0
- package/dist/design/design-systems.js +434 -0
- package/dist/design/design-systems.js.map +1 -0
- package/dist/execution/canvas-state.d.ts +7 -0
- package/dist/execution/canvas-state.d.ts.map +1 -1
- package/dist/execution/canvas-state.js +20 -8
- package/dist/execution/canvas-state.js.map +1 -1
- package/dist/index.d.ts +20 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +12 -4
- package/dist/index.js.map +1 -1
- package/dist/ontology/design-graph.d.ts +9 -0
- package/dist/ontology/design-graph.d.ts.map +1 -1
- package/dist/ontology/design-graph.js +98 -3
- package/dist/ontology/design-graph.js.map +1 -1
- package/dist/ontology/types.d.ts +42 -0
- package/dist/ontology/types.d.ts.map +1 -1
- package/dist/ontology/vocabulary.d.ts.map +1 -1
- package/dist/ontology/vocabulary.js +20 -0
- package/dist/ontology/vocabulary.js.map +1 -1
- package/dist/tools/compact-descriptions.d.ts.map +1 -1
- package/dist/tools/compact-descriptions.js +25 -0
- package/dist/tools/compact-descriptions.js.map +1 -1
- package/dist/tools/definitions.d.ts +1 -1
- package/dist/tools/definitions.d.ts.map +1 -1
- package/dist/tools/definitions.js +404 -25
- package/dist/tools/definitions.js.map +1 -1
- package/dist/tools/engine-methods.d.ts +18 -0
- package/dist/tools/engine-methods.d.ts.map +1 -0
- package/dist/tools/engine-methods.js +241 -0
- package/dist/tools/engine-methods.js.map +1 -0
- package/dist/tools/handlers/character.d.ts +121 -0
- package/dist/tools/handlers/character.d.ts.map +1 -0
- package/dist/tools/handlers/character.js +315 -0
- package/dist/tools/handlers/character.js.map +1 -0
- package/dist/tools/handlers.d.ts +2 -0
- package/dist/tools/handlers.d.ts.map +1 -1
- package/dist/tools/handlers.js +522 -18
- package/dist/tools/handlers.js.map +1 -1
- package/dist/tools/minimal-descriptions.d.ts.map +1 -1
- package/dist/tools/minimal-descriptions.js +15 -3
- package/dist/tools/minimal-descriptions.js.map +1 -1
- package/dist/tools/toolkits.d.ts.map +1 -1
- package/dist/tools/toolkits.js +8 -0
- package/dist/tools/toolkits.js.map +1 -1
- package/dist/types/code-generator.d.ts +106 -1
- package/dist/types/code-generator.d.ts.map +1 -1
- package/dist/types/code-generator.js +1273 -18
- package/dist/types/code-generator.js.map +1 -1
- package/dist/types/schemas.d.ts +6805 -124
- package/dist/types/schemas.d.ts.map +1 -1
- package/dist/types/schemas.js +627 -17
- package/dist/types/schemas.js.map +1 -1
- package/dist/vendor/design/art-deco-generator.d.ts +52 -0
- package/dist/vendor/design/art-deco-generator.d.ts.map +1 -0
- package/dist/vendor/design/art-deco-generator.js +144 -0
- package/dist/vendor/design/art-deco-generator.js.map +1 -0
- package/dist/vendor/design/art-nouveau-generator.d.ts +46 -0
- package/dist/vendor/design/art-nouveau-generator.d.ts.map +1 -0
- package/dist/vendor/design/art-nouveau-generator.js +134 -0
- package/dist/vendor/design/art-nouveau-generator.js.map +1 -0
- package/dist/vendor/design/bauhaus-generator.d.ts +53 -0
- package/dist/vendor/design/bauhaus-generator.d.ts.map +1 -0
- package/dist/vendor/design/bauhaus-generator.js +126 -0
- package/dist/vendor/design/bauhaus-generator.js.map +1 -0
- package/dist/vendor/design/brutalist-generator.d.ts +53 -0
- package/dist/vendor/design/brutalist-generator.d.ts.map +1 -0
- package/dist/vendor/design/brutalist-generator.js +148 -0
- package/dist/vendor/design/brutalist-generator.js.map +1 -0
- package/dist/vendor/design/claymorphism-generator.d.ts +46 -0
- package/dist/vendor/design/claymorphism-generator.d.ts.map +1 -0
- package/dist/vendor/design/claymorphism-generator.js +135 -0
- package/dist/vendor/design/claymorphism-generator.js.map +1 -0
- package/dist/vendor/design/corporate-memphis-generator.d.ts +47 -0
- package/dist/vendor/design/corporate-memphis-generator.d.ts.map +1 -0
- package/dist/vendor/design/corporate-memphis-generator.js +144 -0
- package/dist/vendor/design/corporate-memphis-generator.js.map +1 -0
- package/dist/vendor/design/cyberpunk-generator.d.ts +52 -0
- package/dist/vendor/design/cyberpunk-generator.d.ts.map +1 -0
- package/dist/vendor/design/cyberpunk-generator.js +162 -0
- package/dist/vendor/design/cyberpunk-generator.js.map +1 -0
- package/dist/vendor/design/de-stijl-generator.d.ts +50 -0
- package/dist/vendor/design/de-stijl-generator.d.ts.map +1 -0
- package/dist/vendor/design/de-stijl-generator.js +154 -0
- package/dist/vendor/design/de-stijl-generator.js.map +1 -0
- package/dist/vendor/design/design-style.d.ts +3 -0
- package/dist/vendor/design/design-style.d.ts.map +1 -0
- package/dist/vendor/design/design-style.js +12 -0
- package/dist/vendor/design/design-style.js.map +1 -0
- package/dist/vendor/design/design-systems-dtcg.d.ts +59 -0
- package/dist/vendor/design/design-systems-dtcg.d.ts.map +1 -0
- package/dist/vendor/design/design-systems-dtcg.js +571 -0
- package/dist/vendor/design/design-systems-dtcg.js.map +1 -0
- package/dist/vendor/design/frutiger-aero-generator.d.ts +46 -0
- package/dist/vendor/design/frutiger-aero-generator.d.ts.map +1 -0
- package/dist/vendor/design/frutiger-aero-generator.js +133 -0
- package/dist/vendor/design/frutiger-aero-generator.js.map +1 -0
- package/dist/vendor/design/memphis-generator.d.ts +56 -0
- package/dist/vendor/design/memphis-generator.d.ts.map +1 -0
- package/dist/vendor/design/memphis-generator.js +158 -0
- package/dist/vendor/design/memphis-generator.js.map +1 -0
- package/dist/vendor/design/mid-century-upa-generator.d.ts +46 -0
- package/dist/vendor/design/mid-century-upa-generator.d.ts.map +1 -0
- package/dist/vendor/design/mid-century-upa-generator.js +137 -0
- package/dist/vendor/design/mid-century-upa-generator.js.map +1 -0
- package/dist/vendor/design/neumorphic-generator.d.ts +53 -0
- package/dist/vendor/design/neumorphic-generator.d.ts.map +1 -0
- package/dist/vendor/design/neumorphic-generator.js +182 -0
- package/dist/vendor/design/neumorphic-generator.js.map +1 -0
- package/dist/vendor/design/op-art-generator.d.ts +45 -0
- package/dist/vendor/design/op-art-generator.d.ts.map +1 -0
- package/dist/vendor/design/op-art-generator.js +116 -0
- package/dist/vendor/design/op-art-generator.js.map +1 -0
- package/dist/vendor/design/pixel-art-generator.d.ts +45 -0
- package/dist/vendor/design/pixel-art-generator.d.ts.map +1 -0
- package/dist/vendor/design/pixel-art-generator.js +143 -0
- package/dist/vendor/design/pixel-art-generator.js.map +1 -0
- package/dist/vendor/design/pop-art-generator.d.ts +53 -0
- package/dist/vendor/design/pop-art-generator.d.ts.map +1 -0
- package/dist/vendor/design/pop-art-generator.js +164 -0
- package/dist/vendor/design/pop-art-generator.js.map +1 -0
- package/dist/vendor/design/risograph-generator.d.ts +53 -0
- package/dist/vendor/design/risograph-generator.d.ts.map +1 -0
- package/dist/vendor/design/risograph-generator.js +170 -0
- package/dist/vendor/design/risograph-generator.js.map +1 -0
- package/dist/vendor/design/swiss-style-generator.d.ts +55 -0
- package/dist/vendor/design/swiss-style-generator.d.ts.map +1 -0
- package/dist/vendor/design/swiss-style-generator.js +147 -0
- package/dist/vendor/design/swiss-style-generator.js.map +1 -0
- package/dist/vendor/design/vaporwave-generator.d.ts +51 -0
- package/dist/vendor/design/vaporwave-generator.d.ts.map +1 -0
- package/dist/vendor/design/vaporwave-generator.js +139 -0
- package/dist/vendor/design/vaporwave-generator.js.map +1 -0
- package/manifest.json +33 -1
- package/package.json +13 -5
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
*/
|
|
10
10
|
import { COMPACT_DESCRIPTIONS } from './compact-descriptions.js';
|
|
11
11
|
import { MINIMAL_DESCRIPTIONS } from './minimal-descriptions.js';
|
|
12
|
-
import { EffectTypeSchema, SimpleAnimationTypeSchema, GEOMETRY_OPERATIONS, } from '../types/schemas.js';
|
|
12
|
+
import { EffectTypeSchema, SimpleAnimationTypeSchema, GEOMETRY_OPERATIONS, THREAD_STITCHES, } from '../types/schemas.js';
|
|
13
13
|
/**
|
|
14
14
|
* Vocabulary lists derived from Zod schemas so tool descriptions stay in
|
|
15
15
|
* sync automatically. The description-schema-parity test
|
|
@@ -26,6 +26,11 @@ export const AI_AGENT_GUIDE = `⚠️ You are connected to PinePaper Studio via
|
|
|
26
26
|
NEVER create standalone HTML pages, React components, or web apps as a substitute. Do NOT use frontend design skills or CSS-only animations instead of PinePaper.
|
|
27
27
|
PinePaper tools ARE the implementation — they generate Paper.js/JavaScript code that runs on the canvas and produce Canvas 2D, SVG, MP4, GIF, PNG exports.
|
|
28
28
|
If a tool fails, report the error — do NOT fall back to generating HTML pages.
|
|
29
|
+
|
|
30
|
+
THE DOORS THAT ARE OPEN, because four lines of prohibition above this one will otherwise read as a ban on the capability rather than on the substitution:
|
|
31
|
+
- HTML IS a supported output. \`pinepaper_export_widget_html\` exports the scene as a self-contained HTML page, and \`pinepaper_export_widget\` as an embeddable widget. Asked for a web page or an embed, build the scene with tools and export it — that is the intended path, not a workaround.
|
|
32
|
+
- CODE IS a supported input. \`pinepaper_execute_custom_code\` runs Paper.js against the live canvas, and \`pinepaper_execute_generator\` runs a named generator. Reach for them when no tool fits; they are part of the surface, not an escape from it.
|
|
33
|
+
- The rule above is about SUBSTITUTION — writing a CSS animation instead of calling a tool. It is not a rule against the formats themselves, and a model that reads it as one will refuse work this server can do.
|
|
29
34
|
The generated code is shown in tool responses and can be copied into PinePaper's Code Console.
|
|
30
35
|
|
|
31
36
|
⚠️ KNOWN CONFLICT: The "frontend-design" plugin instructs agents to generate HTML/CSS pages for visual content. This conflicts with PinePaper. If you keep generating HTML instead of calling PinePaper tools, the user should disable the frontend-design plugin.
|
|
@@ -169,7 +174,7 @@ Measurement: pinepaper_measurement — rulers, grid, snap-to-grid, get item dime
|
|
|
169
174
|
─── CANVAS & EXPORT ───
|
|
170
175
|
|
|
171
176
|
Presets: instagram (1080x1080), youtube (1920x1080), tiktok (1080x1920), twitter (1200x675)
|
|
172
|
-
Export: pinepaper_agent_export (SVG/PNG/GIF/MP4/WebM/PDF), pinepaper_export_svg
|
|
177
|
+
Export: pinepaper_agent_export (SVG/PNG/GIF/MP4/WebM/PDF, plus WAV for the soundtrack alone), pinepaper_export_svg
|
|
173
178
|
Widget: pinepaper_export_widget (pp:PinePaper ontology JSON), pinepaper_export_widget_html (self-contained HTML with tree-shaken runtime)`;
|
|
174
179
|
/*
|
|
175
180
|
* The AI_AGENT_GUIDE constant above is included as a comment in verbose/compact modes
|
|
@@ -346,7 +351,9 @@ USE WHEN:
|
|
|
346
351
|
IMPORTANT:
|
|
347
352
|
- Save the returned itemId! You need it for pinepaper_add_relation, pinepaper_modify_item, pinepaper_delete_item, etc.
|
|
348
353
|
- If there's a welcome template on the canvas, use pinepaper_clear_canvas first
|
|
349
|
-
- Position defaults to canvas center (400, 300). Use position: {x, y} or [x, y] (both forms accepted) to place elsewhere.
|
|
354
|
+
- Position defaults to canvas center (400, 300). Use position: {x, y} or [x, y] (both forms accepted) to place elsewhere. Position is the item's bounding-box CENTRE, not its top-left corner.
|
|
355
|
+
- ROTATION is a property, at creation: properties: { rotation: 45 } — degrees, clockwise, about the item's own centre. It does not need a second call, and pinepaper_update_item takes the same property afterwards; keyframe_animate and the driven_by relation both animate it. A radial figure — a sunburst of thin triangles, a clock face, a compass rose — is N creates at rotation: i * (360/N), which is what pinepaper_agent_batch_execute is for. Nothing here needs to be faked with arcs or chevrons.
|
|
356
|
+
⚠️ Rotation applies at create and in keyframes; it is BAKED INTO THE GEOMETRY, so reading item.rotation back returns 0. Verify by geometry or pixels, never by re-reading the property — a 12-ray sunburst has 12 visibly different rays that every report rotation 0, and checking the property is how you conclude a working feature does nothing.
|
|
350
357
|
- 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.
|
|
351
358
|
|
|
352
359
|
⚠️ COMPLEX CHARACTERS/ILLUSTRATIONS:
|
|
@@ -372,6 +379,28 @@ ITEM TYPES:
|
|
|
372
379
|
- diamond: 4-sided diamond/rhombus (properties: radius, color)
|
|
373
380
|
- arrow: Right-pointing block arrow (properties: width, height, color)
|
|
374
381
|
- heart: Heart shape (properties: color)
|
|
382
|
+
- disk: Filled disk — the region inside a circle (properties: radius, color)
|
|
383
|
+
- circle-outline: The circle CURVE — stroked, no interior (properties: radius,
|
|
384
|
+
strokeColor, strokeWidth)
|
|
385
|
+
- arrow-right: Alias for arrow — the same definition under the name the shape
|
|
386
|
+
grids use. Identical output; both are listed because both are accepted.
|
|
387
|
+
|
|
388
|
+
SPEECH AND ANNOTATION SHAPES — the engine draws these; use one instead of
|
|
389
|
+
hand-building an outline from a path. All take width, height and color, and the
|
|
390
|
+
descriptions below are the engine's own. The six with a tail also take
|
|
391
|
+
tailDirection (bottom-left | bottom-right | bottom | top-left | top-right | top
|
|
392
|
+
| left | right) and tailSize (0-1, default 0.35):
|
|
393
|
+
- speech-bubble: Classic round speech bubble with triangular tail.
|
|
394
|
+
- speech-bubble-square: Rectangular speech bubble with sharp corners and
|
|
395
|
+
pointed tail.
|
|
396
|
+
- speech-bubble-pointed: Tooltip-style bubble with arrow pointer (tail defaults
|
|
397
|
+
to "bottom").
|
|
398
|
+
- thought-bubble: Cloud-like thought bubble with trailing dots.
|
|
399
|
+
- comment-box: Modern chat message bubble with high corner radius.
|
|
400
|
+
- callout-box: Annotation callout with narrow arrow (tail defaults to "left").
|
|
401
|
+
- double-bubble: Two overlapping bubbles for conversation (properties:
|
|
402
|
+
secondaryColor).
|
|
403
|
+
- quote-bubble: Stylized bubble with quotation marks.
|
|
375
404
|
|
|
376
405
|
PATH FOR CUSTOM SHAPES:
|
|
377
406
|
Use itemType: "path" with either:
|
|
@@ -427,7 +456,7 @@ For glossy 3D spheres, use pinepaper_create_glossy_sphere instead. For diagonal
|
|
|
427
456
|
properties: {
|
|
428
457
|
itemType: {
|
|
429
458
|
type: 'string',
|
|
430
|
-
enum: ['text', 'circle', 'star', 'rectangle', 'triangle', 'polygon', 'ellipse', 'path', 'line', 'arc', 'pentagon', 'hexagon', 'diamond', 'arrow', 'heart', 'shader', 'field'],
|
|
459
|
+
enum: ['text', 'circle', 'star', 'rectangle', 'triangle', 'polygon', 'ellipse', 'path', 'line', 'arc', 'pentagon', 'hexagon', 'diamond', 'arrow', 'heart', 'disk', 'circle-outline', 'arrow-right', 'speech-bubble', 'speech-bubble-square', 'speech-bubble-pointed', 'thought-bubble', 'double-bubble', 'quote-bubble', 'comment-box', 'callout-box', 'shader', 'field'],
|
|
431
460
|
description: "Type of item to create. 'shader' and 'field' are RENDER-TIME SURFACES drawn per pixel by the cloud renderer — locally they stand in as a flat plate. See the shader/field properties below.",
|
|
432
461
|
},
|
|
433
462
|
position: {
|
|
@@ -460,7 +489,7 @@ Without these every item is on screen for the whole render, which is what makes
|
|
|
460
489
|
a long piece read as one crowded frame instead of a sequence of shots.
|
|
461
490
|
|
|
462
491
|
SHADER (itemType 'shader') — a lit surface, drawn per pixel:
|
|
463
|
-
- shader: 'water' (open sea, lit swell) | 'liquid_metal' (chrome) | 'heatmap' (thermal halo) | 'gem_smoke' (smoke) | 'electric_arc' (branching discharge, stepped flicker) | 'vortex' (hollow bright RING, sheared by differential rotation) | 'rain_veil' | 'caustics'
|
|
492
|
+
- shader: 'water' (open sea, lit swell) | 'liquid_metal' (chrome) | 'heatmap' (thermal halo) | 'gem_smoke' (smoke) | 'electric_arc' (branching discharge, stepped flicker) | 'vortex' (hollow bright RING, sheared by differential rotation) | 'rain_veil' | 'caustics' | 'ink_bleed'
|
|
464
493
|
- width, height: the quad it fills
|
|
465
494
|
- shaderIntensity: 0..2, the effect's amplitude (water: chop)
|
|
466
495
|
- shaderPalette: 0 day | 1 low sun | 2 night
|
|
@@ -1448,6 +1477,7 @@ EXAMPLES:
|
|
|
1448
1477
|
y: { type: 'number', description: 'Canvas origin y (default: canvas center)' },
|
|
1449
1478
|
flipY: { type: 'boolean', description: 'Math y-up → screen y-down (default true)' },
|
|
1450
1479
|
style: { type: 'object', description: 'Path style forwarded to create (strokeColor, strokeWidth, fillColor, …)' },
|
|
1480
|
+
solveOde: { type: 'object', description: "Integrate an ODE instead of plotting a closed form, and return the SOLUTION rather than drawing it: { equations, initialState, tEnd?, dt?, method? ('rk4' default, or 'euler' — faster and visibly wrong on anything stiff) }. The trajectory comes back as data, to inspect, feed to a path, or drive keyframes with." },
|
|
1451
1481
|
warp: {
|
|
1452
1482
|
anyOf: [{ type: 'object' }, { type: 'array', items: { type: 'object' } }],
|
|
1453
1483
|
description: 'Chained parametric warp(s): { dx, dy } expressions of x, y, t — one object or an array',
|
|
@@ -1900,7 +1930,11 @@ EXAMPLE: { action: 'apply_style', itemId: 'title_1', styleKey: 'arcade', fontFam
|
|
|
1900
1930
|
inputSchema: {
|
|
1901
1931
|
type: 'object',
|
|
1902
1932
|
properties: {
|
|
1903
|
-
action: { type: 'string', enum: ['apply_style', 'set_font_axes', 'list_styles'], description:
|
|
1933
|
+
action: { type: 'string', enum: ['apply_style', 'set_font_axes', 'list_styles', 'cursive', 'wrap', 'unwrap', 'to_collage'], description: "Text style operation. 'cursive' draws text as STROKED handwriting — a path, not a glyph, so draw-on animation and outline_stroke both apply. 'wrap'/'unwrap' break a text item to a width, reversibly. 'to_collage' converts an EXISTING text item into a letter collage in place." },
|
|
1934
|
+
text: { type: 'string', description: 'cursive: the words to write. to_collage: the text to build from, if it differs from the item.' },
|
|
1935
|
+
maxWidth: { type: 'number', description: 'wrap: the width to break at, in canvas units. unwrap restores the original, so this is not destructive.' },
|
|
1936
|
+
cursiveOptions: { type: 'object', description: 'cursive: { x?, y?, scale?, strokeColor?, strokeWidth? }.' },
|
|
1937
|
+
collageOptions: { type: 'object', description: 'to_collage: style, palette and the rest — same vocabulary as pinepaper_create_letter_collage.' },
|
|
1904
1938
|
itemId: { type: 'string', description: 'Text item id — apply_style / set_font_axes.' },
|
|
1905
1939
|
styleKey: { type: 'string', description: 'apply_style: style name from list_styles.' },
|
|
1906
1940
|
palette: {
|
|
@@ -1970,9 +2004,9 @@ EXAMPLE — a stitched leaf:
|
|
|
1970
2004
|
type: 'object',
|
|
1971
2005
|
properties: {
|
|
1972
2006
|
action: { type: 'string', enum: ['list_media', 'resolve', 'list_stitches', 'apply_thread', 'apply_hatch', 'list_flow_fields', 'list_hatch_options'], description: 'Medium operation' },
|
|
1973
|
-
medium: { type: 'string', description: 'resolve: vector | thread | ink | cutPaper | charcoal | oil | encaustic' },
|
|
2007
|
+
medium: { type: 'string', description: 'resolve: vector | thread | ink | watercolor | hatch | cutPaper | charcoal | oil | encaustic. Six are native (vector, thread, ink, watercolor, hatch, cutPaper), two stylised, one absent — call list_media for the live table rather than trusting this line.' },
|
|
1974
2008
|
itemId: { type: 'string', description: 'apply_thread / apply_hatch: a closed path, compound path, or a group of them.' },
|
|
1975
|
-
stitch: { type: 'string', enum: [
|
|
2009
|
+
stitch: { type: 'string', enum: [...THREAD_STITCHES], description: "apply_thread: default longAndShort. These six are the stitches the engine publishes; call 'list_stitches' for each one's description and its own parameters. An unknown name is refused rather than quietly stitched as a default fill." },
|
|
1976
2010
|
field: { type: 'object', description: "apply_thread: { kind: 'radial'|'spine'|'constant', cx, cy, angle, spine[], across } — default radial from the shape centre." },
|
|
1977
2011
|
stitchLen: { type: 'number', description: 'apply_thread: nominal stitch length px (default 18).' },
|
|
1978
2012
|
rowGap: { type: 'number', description: 'apply_thread: row spacing px; defaults from thread width so rows abut.' },
|
|
@@ -1982,6 +2016,12 @@ EXAMPLE — a stitched leaf:
|
|
|
1982
2016
|
color: { type: 'string', description: "apply_thread: thread colour (defaults to the item's fill)." },
|
|
1983
2017
|
seed: { type: 'number', description: 'apply_thread: PRNG seed (default 1) — same seed stitches the same way.' },
|
|
1984
2018
|
count: { type: 'number', description: 'apply_thread: stitch count for seed/satin.' },
|
|
2019
|
+
slant: { type: 'number', description: 'apply_thread: stitch slant in DEGREES — satin (default 0) and stem (default 22).' },
|
|
2020
|
+
overlap: { type: 'number', description: 'apply_thread: how far consecutive stem stitches overlap (default 0.4) — what makes a stem outline read as rope.' },
|
|
2021
|
+
stagger: { type: 'number', description: 'apply_thread: offsets alternate longAndShort rows (default 0.5) — stops stitch ends lining up into seams.' },
|
|
2022
|
+
gapLen: { type: 'number', description: 'apply_thread: gap between runningSeam stitches, px (default 4) — with stitchLen, the dash rhythm of a machine seam.' },
|
|
2023
|
+
gridSize: { type: 'number', description: 'apply_thread: crossStitch grid pitch, px (default 12) — the size of each X, and so the resolution of the fill.' },
|
|
2024
|
+
roughness: { type: 'number', description: 'apply_thread: hand wobble. Jitters every point of every stitch after the engine lays them, so the fill reads as sewn rather than plotted. 0 is machine-exact; reproducible for a given seed. Applied by the tool, not the engine.' },
|
|
1985
2025
|
distance: { type: 'number', description: 'apply_hatch: line spacing px (default 6). THE VALUE CONTROL — 6 vs 3 is light vs dark.' },
|
|
1986
2026
|
angle: { type: 'number', description: 'apply_hatch: ruling angle in DEGREES (default 45).' },
|
|
1987
2027
|
gradient: { type: 'number', description: 'apply_hatch: 0..1 spacing growth per line (default 0, even) — a shaded ramp rather than a flat tone.' },
|
|
@@ -2214,6 +2254,233 @@ RECIPE — a playable maze: create_tilemap with wall fills → batch_create colo
|
|
|
2214
2254
|
required: ['action'],
|
|
2215
2255
|
},
|
|
2216
2256
|
},
|
|
2257
|
+
{
|
|
2258
|
+
name: 'pinepaper_design_system',
|
|
2259
|
+
description: `The design vocabulary, as data you can read — and eighteen styles that can build a scene.
|
|
2260
|
+
|
|
2261
|
+
TWO DIFFERENT THINGS, kept apart on purpose:
|
|
2262
|
+
|
|
2263
|
+
A DESIGN SYSTEM is a real, licensed, versioned product — Material Design 3, IBM Carbon, Shopify Polaris, Fluent 2, Adobe Spectrum, GitHub Primer, USWDS, GOV.UK, Shadcn/Radix, SLDS 2, Tailwind, Chakra and more. Its tokens are facts with a licence attached, in the W3C DTCG format ($value, $type, $description). Twenty-one of them are here. Where a motion curve had to be filled in because the published system does not specify one, the token is marked "pinepaper:authored" — so you can tell a vendor's curve from ours instead of treating both as equally official.
|
|
2264
|
+
|
|
2265
|
+
An AESTHETIC STYLE is a look: Bauhaus, Art Deco, Swiss typographic, De Stijl, vaporwave, risograph, brutalist, Memphis, claymorphism, op art, pixel art. No licence, no vendor. Thirty-one are named; eighteen can COMPOSE a scene rather than only be described, and 'list_styles' says which.
|
|
2266
|
+
|
|
2267
|
+
- list_systems / get_system: the licensed systems and their tokens, filterable by token type.
|
|
2268
|
+
- list_easings: every motion curve across every system as a named easing, with its licence and whether it was authored here. Use these to make a motion match a system it has to sit beside.
|
|
2269
|
+
- list_motion: those curves AND the duration scale sitting beside them — the other half of a motion token, published nowhere until now. A curve is a shape; a motion is a shape over a length, and matching a system's easing while inventing its timing gets only the easy half right. Durations come back in ms and in seconds, because every animation tool here takes seconds. These are the licensed SYSTEMS' motion scales: an aesthetic style carries no upstream motion data, so pair one of these with a style rather than expecting the style to name its own.
|
|
2270
|
+
- list_styles: every style with its TOKENS — palette, background, font stacks, type sizes and any variants — derived by composing it, so they are what the generator will actually draw. Read these to hand-build in a style rather than reverse-engineering its colours.
|
|
2271
|
+
- compose: build a titled scene in a style. Layout is decided in this server by a pure function, so 'compose' with draw:false returns the scene and the ops as DATA and draws nothing — read it before committing, the same way pinepaper_story's distill works. Element boxes are converted to the centre anchor app.create wants, and text carries its alignment, so a left-aligned headline starts at its x instead of centring on it.
|
|
2272
|
+
|
|
2273
|
+
A partial composition reports as a failure with the elements that did not create, rather than as a success with half a poster.`,
|
|
2274
|
+
inputSchema: {
|
|
2275
|
+
type: 'object',
|
|
2276
|
+
properties: {
|
|
2277
|
+
action: { type: 'string', enum: ['list_systems', 'get_system', 'list_easings', 'list_motion', 'list_styles', 'compose'], description: 'Which design-system operation.' },
|
|
2278
|
+
systemId: { type: 'string', description: "get_system: e.g. 'material_3', 'ibm_carbon', 'uswds'. Call list_systems for ids." },
|
|
2279
|
+
tokenType: { type: 'string', enum: ['dimension', 'duration', 'cubicBezier', 'color', 'fontFamily', 'fontWeight', 'number', 'shadow', 'grid'], description: 'get_system: return only tokens of this DTCG type.' },
|
|
2280
|
+
style: { type: 'string', description: "compose: the aesthetic style, e.g. 'bauhaus_geometric'. Call list_styles for the composable ones." },
|
|
2281
|
+
title: { type: 'string', description: 'compose: the headline most styles build around.' },
|
|
2282
|
+
subtitle: { type: 'string', description: 'compose: the supporting line.' },
|
|
2283
|
+
body: { type: 'string', description: 'compose: body copy, where the style has room for it.' },
|
|
2284
|
+
width: { type: 'number', description: 'compose: canvas width (the style picks its own default otherwise).' },
|
|
2285
|
+
height: { type: 'number', description: 'compose: canvas height.' },
|
|
2286
|
+
variant: { type: 'string', description: "compose: a style-specific variant, e.g. art deco's 'emerald'." },
|
|
2287
|
+
draw: { type: 'boolean', description: 'compose: draw it (default true). false returns the scene and ops as data and draws nothing.' },
|
|
2288
|
+
authoredOnly: { type: 'boolean', description: 'list_easings: true for only the curves authored here, false for only what vendors publish.' },
|
|
2289
|
+
},
|
|
2290
|
+
required: ['action'],
|
|
2291
|
+
},
|
|
2292
|
+
},
|
|
2293
|
+
{
|
|
2294
|
+
name: 'pinepaper_stick',
|
|
2295
|
+
description: `The vendored stick-figure kit — a rigged figure posed, walking, travelling, holding a prop, with a garment and hair, plus the set it stands on and among.
|
|
2296
|
+
|
|
2297
|
+
A different construction from pinepaper_character, which places a figure from the DESIGN GRAPH by concept ("pp:Pigeon"). This is the stick kit specifically, and its options — pose, walk, travel, prop, garment, trouser, hair, expression and a timeline of expressions — were discoverable only by reading the engine's source.
|
|
2298
|
+
|
|
2299
|
+
action 'figure' builds the figure. action 'set' builds the floor, the wall and the objects around it, so a figure has somewhere to be.
|
|
2300
|
+
|
|
2301
|
+
The geometry is vendored from mcp-cloud, which makes this a three-repo artifact: a change to the kit lands there first and is re-vendored into the engine.`,
|
|
2302
|
+
inputSchema: {
|
|
2303
|
+
type: 'object',
|
|
2304
|
+
properties: {
|
|
2305
|
+
action: { type: 'string', enum: ['figure', 'set'], description: "'figure' or 'set'." },
|
|
2306
|
+
id: { type: 'string', description: 'Prefix for the created items.' },
|
|
2307
|
+
kind: { type: 'string', description: 'figure: which figure. set: which piece of the kit.' },
|
|
2308
|
+
at: { type: 'object', description: '{ x?, y? } — where it goes.' },
|
|
2309
|
+
scale: { type: 'number', description: 'Size multiplier.' },
|
|
2310
|
+
facing: { type: 'string', enum: ['left', 'right'], description: 'Which way the figure looks.' },
|
|
2311
|
+
pose: { type: 'string', description: "figure: a named pose from the kit's POSES." },
|
|
2312
|
+
poseAt: { type: 'number', description: 'figure: seconds at which that pose is struck.' },
|
|
2313
|
+
expression: { type: 'string', description: 'figure: one facial expression.' },
|
|
2314
|
+
expressions: { type: 'array', items: { type: 'object' }, description: 'figure: [{ at, name }] — expressions over time.' },
|
|
2315
|
+
walk: { anyOf: [{ type: 'boolean' }, { type: 'object' }], description: 'figure: a walk cycle.' },
|
|
2316
|
+
travel: { type: 'object', description: 'figure: move across the scene while walking, rather than walking in place.' },
|
|
2317
|
+
prop: { type: 'string', description: 'figure: something held in hand.' },
|
|
2318
|
+
propSide: { type: 'string', enum: ['left', 'right'], description: 'figure: which hand.' },
|
|
2319
|
+
garment: { type: 'string', description: 'figure: clothing.' },
|
|
2320
|
+
trouser: { type: 'string', description: 'figure: legwear.' },
|
|
2321
|
+
hair: { type: 'string', description: 'figure: hair style.' },
|
|
2322
|
+
withHair: { type: 'boolean', description: 'figure: draw hair at all.' },
|
|
2323
|
+
groundY: { type: 'number', description: 'The y the figure stands on.' },
|
|
2324
|
+
surfaceY: { type: 'number', description: 'The y a set object sits on.' },
|
|
2325
|
+
durationSeconds: { type: 'number', description: 'figure: length of the performance.' },
|
|
2326
|
+
object: { type: 'object', description: 'set: the object spec.' },
|
|
2327
|
+
items: { type: 'array', items: { type: 'object' }, description: 'set: several pieces at once.' },
|
|
2328
|
+
floor: { anyOf: [{ type: 'boolean' }, { type: 'object' }], description: 'set: draw a floor.' },
|
|
2329
|
+
wall: { anyOf: [{ type: 'boolean' }, { type: 'object' }], description: 'set: draw a wall.' },
|
|
2330
|
+
},
|
|
2331
|
+
required: ['action'],
|
|
2332
|
+
},
|
|
2333
|
+
},
|
|
2334
|
+
{
|
|
2335
|
+
name: 'pinepaper_story',
|
|
2336
|
+
description: `A piece of prose becomes a scene.
|
|
2337
|
+
|
|
2338
|
+
- distill: reduce an article to its story beats and draw NOTHING. This is the half worth having on its own — a caller can read what the distiller made of the text, edit the beats, and only then assemble. Discovering the reading by looking at a finished scene is the expensive way round.
|
|
2339
|
+
- from_text: distill and assemble in one call, when the reading does not need checking.
|
|
2340
|
+
- apply_spec: assemble a spec you already have, usually a distilled one you edited.
|
|
2341
|
+
- plan_book: lay images out as pages.`,
|
|
2342
|
+
inputSchema: {
|
|
2343
|
+
type: 'object',
|
|
2344
|
+
properties: {
|
|
2345
|
+
action: { type: 'string', enum: ['distill', 'from_text', 'apply_spec', 'plan_book'], description: 'Which story operation.' },
|
|
2346
|
+
text: { type: 'string', description: 'distill / from_text: the prose.' },
|
|
2347
|
+
spec: { type: 'object', description: 'apply_spec: the story spec, usually a distilled one you edited.' },
|
|
2348
|
+
images: { type: 'array', items: { anyOf: [{ type: 'string' }, { type: 'object' }] }, description: 'plan_book: images as ids or specs.' },
|
|
2349
|
+
options: { type: 'object', description: 'Assembly or layout options.' },
|
|
2350
|
+
},
|
|
2351
|
+
required: ['action'],
|
|
2352
|
+
},
|
|
2353
|
+
},
|
|
2354
|
+
{
|
|
2355
|
+
name: 'pinepaper_interchange',
|
|
2356
|
+
description: `The formats other tools read and write — Lottie, dotLottie, GLB, BVH, PNG sequence.
|
|
2357
|
+
|
|
2358
|
+
pinepaper_agent_export covers the PLATFORM formats: png, svg, mp4, webm, gif, pdf, sized for Instagram or YouTube. These are the interchange ones — a Lottie an app plays, a GLB a 3D tool opens, a BVH a rig imports, a PNG sequence an editor ingests. Import is here too, because a format you can only write is half a bridge.
|
|
2359
|
+
|
|
2360
|
+
Three of these refuse quietly in the engine: exportGLB with no perspective objects and exportBVH with no rigging system both warn to the console and return nothing, and the production build strips the console. Over MCP there is no console to read, so the precondition is checked BEFORE the call and named — "no perspective objects to export — create one with createObject3D first" rather than an empty result and a guess.`,
|
|
2361
|
+
inputSchema: {
|
|
2362
|
+
type: 'object',
|
|
2363
|
+
properties: {
|
|
2364
|
+
action: { type: 'string', enum: ['export_lottie', 'export_dotlottie', 'import_lottie', 'export_glb', 'export_bvh', 'export_png_sequence'], description: 'Which interchange operation.' },
|
|
2365
|
+
options: { type: 'object', description: 'Format options passed through to the exporter: frame range, dimensions, fps, naming.' },
|
|
2366
|
+
data: { anyOf: [{ type: 'string' }, { type: 'object' }], description: 'import_lottie: the Lottie JSON — object, JSON string, or URL.' },
|
|
2367
|
+
skeletonId: { type: 'string', description: "export_bvh: which skeleton to write. A BVH is one skeleton's motion." },
|
|
2368
|
+
},
|
|
2369
|
+
required: ['action'],
|
|
2370
|
+
},
|
|
2371
|
+
},
|
|
2372
|
+
{
|
|
2373
|
+
name: 'pinepaper_sound',
|
|
2374
|
+
description: `Synthesis — and the drawing that is the same object.
|
|
2375
|
+
|
|
2376
|
+
The engine carries a full audio graph, and none of it was reachable. pinepaper_audio_beats ANALYSES audio that already exists; this MAKES audio.
|
|
2377
|
+
|
|
2378
|
+
- Catalogues: list_instruments, list_percussion, list_sfx. Call one before naming a drum or effect — the names are the engine's.
|
|
2379
|
+
- Play: play_tone ('A4'), play_chord (root + kind: major, minor, maj7, dim…), play_percussion, play_sfx (beep, pop, wind, whoosh, zap), play_spec, play_from_text.
|
|
2380
|
+
- Read without playing: chord_frequencies (the Hz a chord resolves to), from_text (a plain-language description — "a soft warm bell on A4" — resolved to a spec you can inspect or edit before committing), timbre_from_path.
|
|
2381
|
+
|
|
2382
|
+
THE PART WORTH KNOWING: sound and drawing are the same object here, both ways.
|
|
2383
|
+
- create draws a sound AS a waveform path on the canvas. Edit the path and the timbre changes with it — it is not a picture of the sound, it is the sound.
|
|
2384
|
+
- timbre_from_path reads ANY drawn path back as harmonic content. A curve someone drew by hand becomes the partials of a note.
|
|
2385
|
+
|
|
2386
|
+
A path with no length cannot be a timbre, and the engine answers a flat single-partial timbre for anything that is not one — a real answer and a refusal look identical — so the item is checked before the call and a non-path is refused by name.
|
|
2387
|
+
|
|
2388
|
+
THE CATALOGUE IS A STARTING SET, NOT THE LIMIT. Six instruments, five drums and six effects are what the engine ships with; that is not a claim about how many instruments exist. define_instrument, define_percussion and define_sfx register a new one at runtime — a rhodes, a koto, a taiko, a specific synth patch — and it is first-class from then on: it appears in the list_* catalogues and plays by name like any built-in.
|
|
2389
|
+
- A melodic instrument needs a partial table, because one with no partials renders silence. Percussion and SFX may be pure noise instead, because a hat and a whoosh are.
|
|
2390
|
+
- For a drum, pass pitch: { from, tau }. The glide is what makes a kick a kick; without it you get a beep.
|
|
2391
|
+
- Names are normalised to [a-z][a-z0-9_-]. Register 'Rhodes' and the response returns canonicalName 'rhodes' — play THAT.
|
|
2392
|
+
|
|
2393
|
+
render_soundtrack mixes every placed sound to a WAV and writes it to a file. It runs offline, with no Web Audio and no playback, so it works in a headless studio. An empty scene is refused by name rather than producing a silent file, and any sound that could not be mixed is reported as dropped — a soundtrack missing a track otherwise looks exactly like a complete one.`,
|
|
2394
|
+
inputSchema: {
|
|
2395
|
+
type: 'object',
|
|
2396
|
+
properties: {
|
|
2397
|
+
action: { type: 'string', enum: ['list_instruments', 'list_percussion', 'list_sfx', 'play_tone', 'play_chord', 'chord_frequencies', 'play_percussion', 'play_sfx', 'play_spec', 'from_text', 'play_from_text', 'create', 'timbre_from_path', 'set_placement', 'remove', 'stop_all', 'define_instrument', 'define_percussion', 'define_sfx', 'render_soundtrack'], description: 'Which sound operation.' },
|
|
2398
|
+
partials: { type: 'array', items: { type: 'object' }, description: 'define_*: [{ h, amp }] — the harmonic table that IS the timbre. Required for define_instrument.' },
|
|
2399
|
+
envelope: { type: 'object', description: 'define_*: { attack, decay, sustain, release } — seconds, except sustain which is a level 0-1.' },
|
|
2400
|
+
gain: { type: 'number', description: 'define_*: output level 0-1 (0.8 instrument, 0.85 percussion, 0.65 sfx).' },
|
|
2401
|
+
aliases: { type: 'array', items: { type: 'string' }, description: "define_*: extra names for the same sound. An alias never shadows a real catalogue entry." },
|
|
2402
|
+
noise: { type: 'number', description: 'define_percussion / define_sfx: noise content 0-1. A hat and a clap are pure noise, so these kinds take partials OR noise.' },
|
|
2403
|
+
noiseFreq: { type: 'number', description: 'define_percussion / define_sfx: noise band centre in Hz.' },
|
|
2404
|
+
hz: { type: 'number', description: 'define_percussion / define_sfx: base frequency in Hz.' },
|
|
2405
|
+
pitch: { type: 'object', description: 'define_percussion / define_sfx: { from, tau } pitch glide. The glide IS the drum — omit it and a kick comes out a beep.' },
|
|
2406
|
+
sampleRate: { type: 'number', description: 'render_soundtrack: samples per second (default 48000).' },
|
|
2407
|
+
bitDepth: { type: 'number', enum: [16, 32], description: 'render_soundtrack: 16 (default) or 32-bit float.' },
|
|
2408
|
+
note: { type: 'string', description: "play_tone: scientific pitch, e.g. 'A4'." },
|
|
2409
|
+
root: { type: 'string', description: "play_chord / chord_frequencies: root note, e.g. 'C4'." },
|
|
2410
|
+
chord: { type: 'string', description: "play_chord / chord_frequencies: chord kind (default 'major')." },
|
|
2411
|
+
name: { type: 'string', description: 'play_percussion / play_sfx: the named drum or effect — list them first.' },
|
|
2412
|
+
text: { type: 'string', description: "from_text / play_from_text: a plain-language description. 'from_text' resolves WITHOUT playing." },
|
|
2413
|
+
spec: { type: 'object', description: 'play_spec / create: the sound spec, usually one from from_text or a catalogue.' },
|
|
2414
|
+
options: { type: 'object', description: 'Playback options for the play_* actions.' },
|
|
2415
|
+
itemId: { type: 'string', description: 'timbre_from_path: the path whose shape becomes the timbre. set_placement / remove: the sound item.' },
|
|
2416
|
+
samples: { type: 'number', description: 'timbre_from_path: points sampled along the path (default 256).' },
|
|
2417
|
+
placement: { type: 'object', description: 'set_placement: where and when the sound sits on the timeline.' },
|
|
2418
|
+
visual: { type: 'object', description: 'create: { width?, height?, position?, color? } for the waveform path.' },
|
|
2419
|
+
},
|
|
2420
|
+
required: ['action'],
|
|
2421
|
+
},
|
|
2422
|
+
},
|
|
2423
|
+
{
|
|
2424
|
+
name: 'pinepaper_motion',
|
|
2425
|
+
description: `The generators' Animation knob, pointed at anything — the same motion engine every generator's own animation runs on, reachable for any group or list of items.
|
|
2426
|
+
|
|
2427
|
+
Two kinds, and the second is the one nothing else here can do:
|
|
2428
|
+
- GROUP motions (drift, sway, rotate, pulse, wave, bounce) move the target as one.
|
|
2429
|
+
- FIELD motions (ripple, breathe, undulate) sweep a crest THROUGH the children from an origin, with a chosen waveform — each element moves at its own moment in the cycle. That is a wave passing through a crowd, not a crowd moving together.
|
|
2430
|
+
|
|
2431
|
+
Call action 'list' first. It returns the engine's own catalogue — every motion, waveform and origin it will accept — so the names come from the engine rather than from an enum here that can drift away from it.
|
|
2432
|
+
|
|
2433
|
+
Origins apply to field motions: center, the four corners, the four edges, 'random' (every element on its own phase — a twinkle rather than a wave), and 'roam' (hopping between the corners and the centre). Pass a seed to make 'random' reproducible.
|
|
2434
|
+
|
|
2435
|
+
Waveform 'spike' is a narrow bump. It was called 'pulse' until the engine noticed that one word was naming both a waveform and an animation; saved scenes still carry the old spelling and it is still accepted, but 'spike' is the name.
|
|
2436
|
+
|
|
2437
|
+
This is not pinepaper_animate: that applies a loop preset to ONE item. This moves a group, or moves a wave through one.`,
|
|
2438
|
+
inputSchema: {
|
|
2439
|
+
type: 'object',
|
|
2440
|
+
properties: {
|
|
2441
|
+
action: { type: 'string', enum: ['list', 'apply'], description: "'list' the catalogue · 'apply' a motion." },
|
|
2442
|
+
itemId: { type: 'string', description: 'apply: a group or single item.' },
|
|
2443
|
+
itemIds: { type: 'array', items: { type: 'string' }, description: 'apply: several items, wrapped in a new group that hosts the motion. Members keep their own ids.' },
|
|
2444
|
+
motion: { type: 'string', description: "apply: the motion name. Call 'list' for the set the engine accepts." },
|
|
2445
|
+
speed: { type: 'number', description: 'apply: roughly cycles per second.' },
|
|
2446
|
+
intensity: { type: 'number', description: 'apply: amplitude (0.15 is the usual default elsewhere).' },
|
|
2447
|
+
waveform: { type: 'string', enum: ['sine', 'triangle', 'square', 'sawtooth', 'spike'], description: 'apply: the shape of one cycle.' },
|
|
2448
|
+
origin: { type: 'string', enum: ['center', 'topLeft', 'topRight', 'bottomLeft', 'bottomRight', 'left', 'right', 'top', 'bottom', 'random', 'roam'], description: 'apply, field motions only: where the crest sweeps from.' },
|
|
2449
|
+
seed: { type: 'number', description: "apply: makes a 'random' origin reproducible." },
|
|
2450
|
+
},
|
|
2451
|
+
required: ['action'],
|
|
2452
|
+
},
|
|
2453
|
+
},
|
|
2454
|
+
{
|
|
2455
|
+
name: 'pinepaper_path',
|
|
2456
|
+
description: `Destructive path operations — the ones that REPLACE or ADD items rather than restyling them.
|
|
2457
|
+
|
|
2458
|
+
- boolean: unite | subtract | intersect | exclude | divide. CONSUMES its operands and leaves one result, so the input ids stop existing. The first id is the base; the rest apply to it in order.
|
|
2459
|
+
- simplify: fewer segments, same shape. Higher tolerance is fewer points and a looser curve.
|
|
2460
|
+
- outline_stroke: a stroked line becomes a FILLED SHAPE of the same width — the thing you do before exporting to a format with no stroke model, or before a boolean against a line.
|
|
2461
|
+
- toggle_closed: open a closed path or close an open one.
|
|
2462
|
+
- pattern: repeat an item — concentric rings, a radial ring, a grid, or a depth-wise extrude stack.
|
|
2463
|
+
- get_geometry: read the segments back (anchor and handle coordinates).
|
|
2464
|
+
- set_locked / unlock_all: a locked item is also unselectable and undraggable, so it cannot be grabbed by accident.
|
|
2465
|
+
|
|
2466
|
+
These live apart from pinepaper_modify_item on purpose: modify restyles an item and keeps its id, every action here changes what items EXIST. A boolean's operands are gone afterwards, and their relations and keyframes go with them.
|
|
2467
|
+
|
|
2468
|
+
The engine names each refusal — "a boolean needs at least two paths", "that path has no stroke to outline", "simplify needs a path" — and those come back verbatim rather than being reworded here.`,
|
|
2469
|
+
inputSchema: {
|
|
2470
|
+
type: 'object',
|
|
2471
|
+
properties: {
|
|
2472
|
+
action: { type: 'string', enum: ['boolean', 'simplify', 'outline_stroke', 'toggle_closed', 'pattern', 'get_geometry', 'set_locked', 'unlock_all'], description: 'Which path operation.' },
|
|
2473
|
+
itemId: { type: 'string', description: 'The item to operate on — every action except boolean and unlock_all.' },
|
|
2474
|
+
itemIds: { type: 'array', items: { type: 'string' }, description: 'boolean: at least two path ids. The first is the base.' },
|
|
2475
|
+
op: { type: 'string', enum: ['unite', 'subtract', 'intersect', 'exclude', 'divide'], description: 'boolean: which operation (default unite).' },
|
|
2476
|
+
tolerance: { type: 'number', description: 'simplify: how far the new curve may stray, in canvas units (default 2.5). outline_stroke: flattening tolerance.' },
|
|
2477
|
+
kind: { type: 'string', enum: ['concentric', 'radial', 'grid', 'extrude'], description: 'pattern: which repeat (default radial).' },
|
|
2478
|
+
pattern: { type: 'object', description: 'pattern options: { count?, radius?, angle?, phase?, rows?, cols?, gapX?, gapY?, step?, depth?, rotateItems?, shade?, shadeStrength? }. angle and phase are DEGREES. Copies are capped — past a few hundred this is a generator, not a drawing aid.' },
|
|
2479
|
+
locked: { type: 'boolean', description: 'set_locked: true locks, false unlocks (default true).' },
|
|
2480
|
+
},
|
|
2481
|
+
required: ['action'],
|
|
2482
|
+
},
|
|
2483
|
+
},
|
|
2217
2484
|
{
|
|
2218
2485
|
name: 'pinepaper_world3d',
|
|
2219
2486
|
annotations: {
|
|
@@ -2239,7 +2506,7 @@ RECIPE — a character walking through a forest: create {spec:'forest'} → impo
|
|
|
2239
2506
|
inputSchema: {
|
|
2240
2507
|
type: 'object',
|
|
2241
2508
|
properties: {
|
|
2242
|
-
action: { type: 'string', enum: ['create', 'describe', 'configure', 'add_actor', 'remove_actor', 'list_actors', 'set_actor_pose', 'set_camera', 'add_object', 'remove_object', 'remove_world'], description: 'World operation' },
|
|
2509
|
+
action: { type: 'string', enum: ['create', 'describe', 'configure', 'add_actor', 'remove_actor', 'list_actors', 'set_actor_pose', 'set_camera', 'add_object', 'remove_object', 'remove_world', 'extrude_path', 'lathe_path', 'list_meshes', 'remove_mesh', 'add_light', 'set_light', 'remove_light', 'list_lights', 'add_material', 'set_material', 'remove_material', 'list_materials', 'import_obj', 'import_gltf', 'list_mesh_clips', 'set_mesh_clip', 'set_nav_target', 'get_nav_target', 'ground_height', 'raycast', 'dolly_camera', 'pan_camera', 'world_to_canvas', 'canvas_to_ground', 'add_body', 'remove_body', 'list_bodies', 'step_physics', 'impulse', 'set_velocity', 'fire_projectile', 'line_of_sight', 'set_mesh_instances'], description: 'World operation. extrude_path/lathe_path turn a canvas path into real geometry; lights are capped at 8; a material is shared by every object referencing it.' },
|
|
2243
2510
|
spec: {
|
|
2244
2511
|
anyOf: [{ type: 'string' }, { type: 'object' }],
|
|
2245
2512
|
description: "create: preset id ('forest'|'snowMountain'|'field'|'jungle') or a full spec object.",
|
|
@@ -2257,7 +2524,32 @@ RECIPE — a character walking through a forest: create {spec:'forest'} → impo
|
|
|
2257
2524
|
live: { type: 'boolean', description: 'add_actor: re-rasterize as the item animates.' },
|
|
2258
2525
|
pose: { type: 'object', description: 'set_actor_pose: { x?, z?, angle? }.' },
|
|
2259
2526
|
camera: { type: 'object', description: "set_camera: { mode: follow|fixed|orbit, target?, radius?, speed?, eye?, lookAt? }." },
|
|
2260
|
-
object: { type: 'object', description: 'add_object: { x, z, height?, color?, y? }.' },
|
|
2527
|
+
object: { type: 'object', description: 'add_object: { x, z, height?, color?, y? }. metalness/roughness are accepted and IGNORED here — a plain object is drawn by the prop shader, which declares no such uniform. They render on the mesh path only.' },
|
|
2528
|
+
pathId: { type: 'string', description: 'extrude_path / lathe_path: the canvas path to turn into geometry. The path itself is unchanged.' },
|
|
2529
|
+
mesh: { type: 'object', description: 'extrude_path / lathe_path options: { id?, depth?, unitsPerPixel?, caps?, segments?, arc?, flatness?, x?, y?, z?, rotY?, rotYDegrees?, scale?, doubleSided? }. arc is DEGREES; rotY is RADIANS (fed straight to cos/sin in the shader) — pass rotYDegrees to write degrees. These names are the ones the engine records as the mesh provenance, so a captured meshProvenance.opts spreads straight back in.' },
|
|
2530
|
+
meshId: { type: 'string', description: 'remove_mesh: the mesh id.' },
|
|
2531
|
+
light: { type: 'object', description: 'add_light / set_light: { id?, x?, y?, z?, color?, intensity?, range? }. At most 8 point lights; the ninth is refused by name because the shader array is fixed-size.' },
|
|
2532
|
+
lightId: { type: 'string', description: 'set_light / remove_light: the light id.' },
|
|
2533
|
+
material: { type: 'object', description: 'add_material / set_material: { id?, color?, emissive?, metalness?, roughness?, emissiveIntensity?, clearcoat?, clearcoatRoughness?, sheenColor?, sheenRoughness? }. A shared surface — one edit restyles every object using it. metalness/roughness render on the mesh path only.' },
|
|
2534
|
+
materialId: { type: 'string', description: 'set_material / remove_material: the material id.' },
|
|
2535
|
+
source: { type: 'string', description: 'import_obj: the OBJ file TEXT. import_gltf: a URL or a data: URI of the .glb bytes.' },
|
|
2536
|
+
importOptions: { type: 'object', description: 'import_obj / import_gltf: placement and scale options, passed through.' },
|
|
2537
|
+
clip: { type: 'string', description: 'set_mesh_clip: which imported animation clip a skinned mesh plays.' },
|
|
2538
|
+
crossfade: { type: 'number', description: 'set_mesh_clip: seconds to blend out of the previous clip (blended in LOCAL pose space).' },
|
|
2539
|
+
navTarget: { type: 'string', enum: ['2d', '3d'], description: "set_nav_target: which layer the pointer drives." },
|
|
2540
|
+
point: { type: 'object', description: 'ground_height / canvas_to_ground / world_to_canvas: { x, y, z? }.' },
|
|
2541
|
+
origin: { type: 'array', items: { type: 'number' }, description: 'raycast: ray origin [x, y, z].' },
|
|
2542
|
+
direction: { type: 'array', items: { type: 'number' }, description: 'raycast: ray direction [x, y, z], need not be normalised.' },
|
|
2543
|
+
multiplier: { type: 'number', description: 'dolly_camera: >1 away, <1 closer.' },
|
|
2544
|
+
dx: { type: 'number', description: 'pan_camera: horizontal pan in SCREEN pixels.' },
|
|
2545
|
+
dy: { type: 'number', description: 'pan_camera: vertical pan in SCREEN pixels.' },
|
|
2546
|
+
body: { type: 'object', description: 'add_body / fire_projectile: the body spec. NARROW by design — a sphere or capsule under gravity colliding with the world. No stacking solver, no joints; pinepaper_physics is the 2D world and has those.' },
|
|
2547
|
+
bodyId: { type: 'string', description: 'remove_body / impulse / set_velocity: the body id.' },
|
|
2548
|
+
vector: { type: 'array', items: { type: 'number' }, description: 'impulse / set_velocity: [x, y, z].' },
|
|
2549
|
+
dt: { type: 'number', description: 'step_physics: seconds to advance. Returns contacts made and bodies removed.' },
|
|
2550
|
+
from: { type: 'array', items: { type: 'number' }, description: 'line_of_sight: eye point [x, y, z].' },
|
|
2551
|
+
to: { type: 'array', items: { type: 'number' }, description: 'line_of_sight: target point [x, y, z].' },
|
|
2552
|
+
instances: { type: 'array', items: { type: 'array', items: { type: 'number' } }, description: 'set_mesh_instances: one entry per copy, six numbers — x, y, z, scale, rotY (RADIANS), variant.' },
|
|
2261
2553
|
objectId: { type: 'string', description: 'remove_object: object id.' },
|
|
2262
2554
|
},
|
|
2263
2555
|
required: ['action'],
|
|
@@ -2306,6 +2598,10 @@ NOT LIP SYNC. \`say\` opens and closes a mouth for the length of a line. Matchin
|
|
|
2306
2598
|
description: 'Where the figure stands.',
|
|
2307
2599
|
},
|
|
2308
2600
|
height: { type: 'number', description: 'Drawn height in pixels. Every amplitude in the graph is a fraction, so the performance scales with it.' },
|
|
2601
|
+
position: { type: 'object', description: 'Where the figure stands — a synonym for `at`, because the rest of this surface says position. `at` wins if both are sent.' },
|
|
2602
|
+
scale: { type: 'number', description: 'Size as a multiplier of the 300px default, for callers who think in scale rather than pixels. `height` wins if both are sent.' },
|
|
2603
|
+
palette: { type: 'object', description: "Override the depiction's own colours: part id → colour. Only the parts you name change." },
|
|
2604
|
+
ink: { type: 'string', description: 'Ink colour for the stroked copies that make the figure read as drawn rather than filled. Overrides the style\'s own.' },
|
|
2309
2605
|
id: { type: 'string', description: 'Prefix for the created items (default: the concept name).' },
|
|
2310
2606
|
style: { type: 'string', description: 'Style id for the depiction (default: the concept\'s own).' },
|
|
2311
2607
|
variant: { type: 'string', description: 'Depiction variant (default: "default").' },
|
|
@@ -2608,7 +2904,7 @@ GEOMETRIC CONSTRUCTION CONSTRAINTS (Layer 2) — the source item is RE-DERIVED e
|
|
|
2608
2904
|
|
|
2609
2905
|
PROCEDURAL / DETERMINISTIC BINDING (Expression IR — S10 G1) — bind a property to another property or to a math function of time. Pass params.signal:true to route through the pure, seed/frame-deterministic signal interpreter (replay-stable — same time → identical output); omit it for the per-frame compute fallback.
|
|
2610
2906
|
- driven_by: source's sourceProperty = target's targetProperty * multiplier + offset (optionally clamped). sourceProperty ∈ x|y|rotation|opacity|scale|strokeWidth|fillColor|strokeColor; targetProperty ∈ x|y|rotation|opacity|scale. For fillColor/strokeColor the (clamped 0..1) driven value interpolates colorFrom→colorTo — so a relation drives COLOR. NEEDS a target (the property source). params: sourceProperty, targetProperty, multiplier, offset, clamp {min,max}, colorFrom, colorTo, signal. e.g. tint a dot by a planet's x: sourceProperty 'fillColor', targetProperty 'x', colorFrom '#0055ff', colorTo '#ff3300', signal true.
|
|
2611
|
-
- time_expression: self-relation (targetId=null); the source's params.property is driven by a math expression of t (scene time) and v (params.baseValue). params: property (default 'y'), expression (e.g. 'sin(t*2)*50 + v'), baseValue, signal.
|
|
2907
|
+
- time_expression: self-relation (targetId=null); the source's params.property is driven by a math expression of t (scene time) and v (params.baseValue). params: property (default 'y'), expression (e.g. 'sin(t*2)*50 + v'), baseValue, signal. Both modes parse the SAME grammar — the caret is exponentiation (not XOR), and random() is rejected by name rather than falling back, because a scene that renders differently twice cannot be baked or exported. signal:true additionally evaluates it as a pure f(t) via the Expression IR. Beyond the usual trig/log/pow set: clamp, mod, fract, pingpong, inverseLerp, remap, noise, sec, csc, cot, the six ease in/out quad and cubic curves, and the constants PI, E and TAU.
|
|
2612
2908
|
|
|
2613
2909
|
EVENT-DRIVEN SCENE CHAINS (S11) — build a LONG scene as a graph of timed events, not a keyframe track. First make events with pinepaper_event (action:'create' → eventId). The relations below have an EVENT as their sourceId; firing the event runs the reaction. Chain beats over animation time with on_event_fire_after (timeline:'canvas'), have beats mutate the scene with on_event_add_relation, then kick it off with pinepaper_event action:'pulse'. Because canvas-timed fires are on the animation clock, the whole chain is scrub-, loop-, and replay-stable.
|
|
2614
2910
|
- on_event_fire_after: sourceId=event, targetId=the NEXT event. When source fires, pulse target after params.delay ms. params.timeline: 'canvas' (animation clock — use for scene chains) | 'wall' (real setTimeout). This is the chaining primitive.
|
|
@@ -2650,7 +2946,7 @@ Relations are COMPOSITIONAL - an item can have multiple relations that work toge
|
|
|
2650
2946
|
},
|
|
2651
2947
|
relationType: {
|
|
2652
2948
|
type: 'string',
|
|
2653
|
-
enum: ['orbits', 'follows', 'attached_to', 'maintains_distance', 'points_at', 'mirrors', 'parallax', 'bounds_to', 'anchored_in_world', 'spring_follow', 'repels', 'wiggle', 'animates', 'grows_from', 'staggered_with', 'indicates', 'circumscribes', 'wave_through', 'morphs_to', 'group_morphs_to', 'moves_along_path', 'construction_reveal', 'triggers_animation', 'syncs_with', 'tours', 'synced_to_audio', 'expresses', 'camera_follows', 'camera_animates', 'is_midpoint_of', 'lies_on_line', 'is_centroid_of', 'is_circumcenter_of', 'concentric_with', 'driven_by', 'time_expression', 'on_click_fire', 'on_pointer_enter_fire', 'on_pointer_exit_fire', 'on_key_fire', 'on_event_fire_after', 'on_event_fire_if', 'on_event_add_relation', 'on_event_remove_relation', 'on_event_set_color', 'on_event_set_property', 'on_event_set_property_from_template', 'on_event_set_visibility', 'on_event_set_active', 'on_event_set_data', 'on_event_increment', 'on_event_toggle', 'on_event_store_set', 'on_event_store_increment', 'on_enter_set_color', 'on_enter_set_property', 'on_enter_set_property_from_template', 'on_enter_set_visibility', 'on_enter_set_data', 'on_enter_increment', 'on_enter_toggle', 'on_exit_set_color', 'on_exit_set_property', 'on_exit_set_property_from_template', 'on_exit_set_visibility', 'on_exit_set_data', 'on_exit_increment', 'on_exit_toggle', 'exclusive_group', 'menubar_group', 'restores_from', 'on_top_of', 'below', 'beside', 'inside', 'centered_on', 'aligned_with', 'part_of', 'connects_to', 'attached_to_tail', 'head_points_to'],
|
|
2949
|
+
enum: ['orbits', 'follows', 'attached_to', 'maintains_distance', 'points_at', 'mirrors', 'parallax', 'bounds_to', 'anchored_in_world', 'spring_follow', 'repels', 'attracts', 'wiggle', 'animates', 'grows_from', 'staggered_with', 'indicates', 'circumscribes', 'wave_through', 'morphs_to', 'group_morphs_to', 'moves_along_path', 'construction_reveal', 'triggers_animation', 'syncs_with', 'tours', 'synced_to_audio', 'expresses', 'camera_follows', 'camera_animates', 'is_midpoint_of', 'lies_on_line', 'is_centroid_of', 'is_circumcenter_of', 'concentric_with', 'driven_by', 'time_expression', 'on_click_fire', 'on_pointer_enter_fire', 'on_pointer_exit_fire', 'on_key_fire', 'on_event_fire_after', 'on_event_fire_if', 'on_event_add_relation', 'on_event_remove_relation', 'on_event_set_color', 'on_event_set_property', 'on_event_set_property_from_template', 'on_event_set_visibility', 'on_event_set_active', 'on_event_set_data', 'on_event_increment', 'on_event_toggle', 'on_event_store_set', 'on_event_store_increment', 'on_enter_set_color', 'on_enter_set_property', 'on_enter_set_property_from_template', 'on_enter_set_visibility', 'on_enter_set_data', 'on_enter_increment', 'on_enter_toggle', 'on_exit_set_color', 'on_exit_set_property', 'on_exit_set_property_from_template', 'on_exit_set_visibility', 'on_exit_set_data', 'on_exit_increment', 'on_exit_toggle', 'exclusive_group', 'menubar_group', 'restores_from', 'on_top_of', 'below', 'beside', 'inside', 'centered_on', 'aligned_with', 'part_of', 'connects_to', 'attached_to_tail', 'head_points_to'],
|
|
2654
2950
|
description: 'Type of relationship',
|
|
2655
2951
|
},
|
|
2656
2952
|
params: {
|
|
@@ -2658,8 +2954,17 @@ Relations are COMPOSITIONAL - an item can have multiple relations that work toge
|
|
|
2658
2954
|
description: 'Relation-specific parameters',
|
|
2659
2955
|
additionalProperties: true,
|
|
2660
2956
|
},
|
|
2957
|
+
presetId: {
|
|
2958
|
+
type: 'string',
|
|
2959
|
+
description: "Adopt a community relation PRESET instead of naming a type and params yourself — a tuned motion with its symbols exposed as knobs. List them with pinepaper_query_capabilities { action: 'catalogue', catalogue: 'relation_presets' }. The preset decides the relationType, so relationType is not needed alongside it.",
|
|
2960
|
+
},
|
|
2961
|
+
presetValues: {
|
|
2962
|
+
type: 'object',
|
|
2963
|
+
description: 'presetId: symbol → number. An omitted symbol takes the midpoint of its declared range, so a preset applies sensibly with no values at all.',
|
|
2964
|
+
additionalProperties: true,
|
|
2965
|
+
},
|
|
2661
2966
|
},
|
|
2662
|
-
required: ['sourceId'
|
|
2967
|
+
required: ['sourceId'],
|
|
2663
2968
|
},
|
|
2664
2969
|
},
|
|
2665
2970
|
{
|
|
@@ -2684,7 +2989,7 @@ USE WHEN:
|
|
|
2684
2989
|
targetId: { type: 'string', description: 'Target item ID' },
|
|
2685
2990
|
relationType: {
|
|
2686
2991
|
type: 'string',
|
|
2687
|
-
enum: ['orbits', 'follows', 'attached_to', 'maintains_distance', 'points_at', 'mirrors', 'parallax', 'bounds_to', 'anchored_in_world', 'spring_follow', 'repels', 'wiggle', 'animates', 'grows_from', 'staggered_with', 'indicates', 'circumscribes', 'wave_through', 'morphs_to', 'group_morphs_to', 'moves_along_path', 'construction_reveal', 'triggers_animation', 'syncs_with', 'tours', 'synced_to_audio', 'expresses', 'camera_follows', 'camera_animates', 'is_midpoint_of', 'lies_on_line', 'is_centroid_of', 'is_circumcenter_of', 'concentric_with', 'driven_by', 'time_expression', 'on_click_fire', 'on_pointer_enter_fire', 'on_pointer_exit_fire', 'on_key_fire', 'on_event_fire_after', 'on_event_fire_if', 'on_event_add_relation', 'on_event_remove_relation', 'on_event_set_color', 'on_event_set_property', 'on_event_set_property_from_template', 'on_event_set_visibility', 'on_event_set_active', 'on_event_set_data', 'on_event_increment', 'on_event_toggle', 'on_event_store_set', 'on_event_store_increment', 'on_enter_set_color', 'on_enter_set_property', 'on_enter_set_property_from_template', 'on_enter_set_visibility', 'on_enter_set_data', 'on_enter_increment', 'on_enter_toggle', 'on_exit_set_color', 'on_exit_set_property', 'on_exit_set_property_from_template', 'on_exit_set_visibility', 'on_exit_set_data', 'on_exit_increment', 'on_exit_toggle', 'exclusive_group', 'menubar_group', 'restores_from', 'on_top_of', 'below', 'beside', 'inside', 'centered_on', 'aligned_with', 'part_of', 'connects_to', 'attached_to_tail', 'head_points_to'],
|
|
2992
|
+
enum: ['orbits', 'follows', 'attached_to', 'maintains_distance', 'points_at', 'mirrors', 'parallax', 'bounds_to', 'anchored_in_world', 'spring_follow', 'repels', 'attracts', 'wiggle', 'animates', 'grows_from', 'staggered_with', 'indicates', 'circumscribes', 'wave_through', 'morphs_to', 'group_morphs_to', 'moves_along_path', 'construction_reveal', 'triggers_animation', 'syncs_with', 'tours', 'synced_to_audio', 'expresses', 'camera_follows', 'camera_animates', 'is_midpoint_of', 'lies_on_line', 'is_centroid_of', 'is_circumcenter_of', 'concentric_with', 'driven_by', 'time_expression', 'on_click_fire', 'on_pointer_enter_fire', 'on_pointer_exit_fire', 'on_key_fire', 'on_event_fire_after', 'on_event_fire_if', 'on_event_add_relation', 'on_event_remove_relation', 'on_event_set_color', 'on_event_set_property', 'on_event_set_property_from_template', 'on_event_set_visibility', 'on_event_set_active', 'on_event_set_data', 'on_event_increment', 'on_event_toggle', 'on_event_store_set', 'on_event_store_increment', 'on_enter_set_color', 'on_enter_set_property', 'on_enter_set_property_from_template', 'on_enter_set_visibility', 'on_enter_set_data', 'on_enter_increment', 'on_enter_toggle', 'on_exit_set_color', 'on_exit_set_property', 'on_exit_set_property_from_template', 'on_exit_set_visibility', 'on_exit_set_data', 'on_exit_increment', 'on_exit_toggle', 'exclusive_group', 'menubar_group', 'restores_from', 'on_top_of', 'below', 'beside', 'inside', 'centered_on', 'aligned_with', 'part_of', 'connects_to', 'attached_to_tail', 'head_points_to'],
|
|
2688
2993
|
description: 'Specific relation type to remove (optional - removes all if not specified)',
|
|
2689
2994
|
},
|
|
2690
2995
|
},
|
|
@@ -2712,7 +3017,7 @@ USE WHEN:
|
|
|
2712
3017
|
itemId: { type: 'string', description: 'Item to query relations for' },
|
|
2713
3018
|
relationType: {
|
|
2714
3019
|
type: 'string',
|
|
2715
|
-
enum: ['orbits', 'follows', 'attached_to', 'maintains_distance', 'points_at', 'mirrors', 'parallax', 'bounds_to', 'anchored_in_world', 'spring_follow', 'repels', 'wiggle', 'animates', 'grows_from', 'staggered_with', 'indicates', 'circumscribes', 'wave_through', 'morphs_to', 'group_morphs_to', 'moves_along_path', 'construction_reveal', 'triggers_animation', 'syncs_with', 'tours', 'synced_to_audio', 'expresses', 'camera_follows', 'camera_animates', 'is_midpoint_of', 'lies_on_line', 'is_centroid_of', 'is_circumcenter_of', 'concentric_with', 'driven_by', 'time_expression', 'on_click_fire', 'on_pointer_enter_fire', 'on_pointer_exit_fire', 'on_key_fire', 'on_event_fire_after', 'on_event_fire_if', 'on_event_add_relation', 'on_event_remove_relation', 'on_event_set_color', 'on_event_set_property', 'on_event_set_property_from_template', 'on_event_set_visibility', 'on_event_set_active', 'on_event_set_data', 'on_event_increment', 'on_event_toggle', 'on_event_store_set', 'on_event_store_increment', 'on_enter_set_color', 'on_enter_set_property', 'on_enter_set_property_from_template', 'on_enter_set_visibility', 'on_enter_set_data', 'on_enter_increment', 'on_enter_toggle', 'on_exit_set_color', 'on_exit_set_property', 'on_exit_set_property_from_template', 'on_exit_set_visibility', 'on_exit_set_data', 'on_exit_increment', 'on_exit_toggle', 'exclusive_group', 'menubar_group', 'restores_from', 'on_top_of', 'below', 'beside', 'inside', 'centered_on', 'aligned_with', 'part_of', 'connects_to', 'attached_to_tail', 'head_points_to'],
|
|
3020
|
+
enum: ['orbits', 'follows', 'attached_to', 'maintains_distance', 'points_at', 'mirrors', 'parallax', 'bounds_to', 'anchored_in_world', 'spring_follow', 'repels', 'attracts', 'wiggle', 'animates', 'grows_from', 'staggered_with', 'indicates', 'circumscribes', 'wave_through', 'morphs_to', 'group_morphs_to', 'moves_along_path', 'construction_reveal', 'triggers_animation', 'syncs_with', 'tours', 'synced_to_audio', 'expresses', 'camera_follows', 'camera_animates', 'is_midpoint_of', 'lies_on_line', 'is_centroid_of', 'is_circumcenter_of', 'concentric_with', 'driven_by', 'time_expression', 'on_click_fire', 'on_pointer_enter_fire', 'on_pointer_exit_fire', 'on_key_fire', 'on_event_fire_after', 'on_event_fire_if', 'on_event_add_relation', 'on_event_remove_relation', 'on_event_set_color', 'on_event_set_property', 'on_event_set_property_from_template', 'on_event_set_visibility', 'on_event_set_active', 'on_event_set_data', 'on_event_increment', 'on_event_toggle', 'on_event_store_set', 'on_event_store_increment', 'on_enter_set_color', 'on_enter_set_property', 'on_enter_set_property_from_template', 'on_enter_set_visibility', 'on_enter_set_data', 'on_enter_increment', 'on_enter_toggle', 'on_exit_set_color', 'on_exit_set_property', 'on_exit_set_property_from_template', 'on_exit_set_visibility', 'on_exit_set_data', 'on_exit_increment', 'on_exit_toggle', 'exclusive_group', 'menubar_group', 'restores_from', 'on_top_of', 'below', 'beside', 'inside', 'centered_on', 'aligned_with', 'part_of', 'connects_to', 'attached_to_tail', 'head_points_to'],
|
|
2716
3021
|
description: 'Filter by relation type (optional)',
|
|
2717
3022
|
},
|
|
2718
3023
|
direction: {
|
|
@@ -2810,10 +3115,15 @@ USE WHEN:
|
|
|
2810
3115
|
- Custom item registration
|
|
2811
3116
|
- Accessing PinePaper APIs directly
|
|
2812
3117
|
- Prototyping new features
|
|
3118
|
+
- A scene whose repetition is the point: dozens of items built in a loop. This is the cheapest route by an order of magnitude — a 63-item animated scene is ~4k characters here against ~147k as keyframe tool calls — because the loop collapses the repetition instead of restating it per item. Synchronous build work is bounded by the governor's 4s deadline, which such a scene fits easily.
|
|
3119
|
+
|
|
3120
|
+
WHAT THE CHEAP ROUTE COSTS, so the choice is deliberate: items built and animated in raw JS carry NO behavioral record. No graph edge, nothing SMIL or widget export can lift, nothing the ontology can read — the scene renders and cannot describe itself. Relations are the canonical behavior surface here, so for motion that is a function of time prefer pinepaper_add_relation with 'time_expression' (still ~5.7x cheaper than keyframes), and for a whole group moving together staggered_with or wave_through. Reach for a loop when the geometry is procedural, not merely to avoid the typing.
|
|
2813
3121
|
|
|
2814
3122
|
AVAILABLE GLOBALS:
|
|
2815
3123
|
- app: PinePaper application instance
|
|
2816
3124
|
- app.create(type, params): Create items
|
|
3125
|
+
- app.addAnimation(itemId, keyframes, options): Attach keyframe TRACKS programmatically — the other half of a procedural scene, and what makes the loop route cheap: the keyframes are generated, not typed. Accepts an id or the item itself; options.timeUnits ('seconds'|'ms') overrides the ms auto-detect, which long-form timelines need
|
|
3126
|
+
- app.animate(item, params): Attach a LOOP animation (pulse, bounce, wobble, …) — the other kind of motion, and not what addAnimation does
|
|
2817
3127
|
- app.addRelation(sourceId, targetId, type, params): Add relations
|
|
2818
3128
|
- app.registerRelationRule(name, definition): Register custom relations
|
|
2819
3129
|
- app.itemRegistry: Access all registered items
|
|
@@ -2932,6 +3242,13 @@ USE WHEN:
|
|
|
2932
3242
|
- "first fade in, then rotate, then fade out"
|
|
2933
3243
|
- Any animation with specific timing or sequential stages
|
|
2934
3244
|
|
|
3245
|
+
BEFORE AUTHORING DENSE TRACKS — three routes are cheaper, and two of them keep the scene describable. Measured on the same 63-item, 32-keyframes-each scene:
|
|
3246
|
+
- Motion that is a FUNCTION OF TIME (bob, pulse, sweep, phase-offset wave) → pinepaper_add_relation with relationType 'time_expression'. One call per property instead of one keyframe per sample: 26k characters against 147k. It also survives into the design graph, save/reload and widget export, which keyframes generated from a formula do not describe.
|
|
3247
|
+
- PER-ITEM VARIATION across many items → staggered_with or wave_through express the whole group in ONE call. That collapses the 63-fold repetition a per-item time_expression still pays for.
|
|
3248
|
+
- GENUINELY PROCEDURAL scenes → pinepaper_execute_custom_code with app.create + app.addAnimation (which attaches keyframe tracks programmatically, so the keyframes are generated rather than typed), at 4k characters for the same scene — cheapest by an order of magnitude, because a loop collapses the repetition entirely. The trade is real and worth making deliberately: raw JS leaves NO behavioral record — no graph edge, nothing SMIL or widget export can lift, nothing the ontology can read. Scene building fits the governor's 4s synchronous deadline easily (it is the injected loop guards, not the 10s async-tail budget, that bites a build loop).
|
|
3249
|
+
|
|
3250
|
+
Keyframes are for motion that is AUTHORED, not computed. A track of hundreds of entries produced from a formula is the signal that one of the three above is the right route.
|
|
3251
|
+
|
|
2935
3252
|
ANIMATABLE PROPERTIES:
|
|
2936
3253
|
- position: [x, y] array (a { x, y } object is also accepted and normalized)
|
|
2937
3254
|
- x, y: Individual coordinates
|
|
@@ -3596,7 +3913,7 @@ SUPPORTED ANIMATIONS: bounce, breathe, fade, glow, jelly, path, pulse, rotate, s
|
|
|
3596
3913
|
target: { type: 'string', description: 'Name of target item' },
|
|
3597
3914
|
type: {
|
|
3598
3915
|
type: 'string',
|
|
3599
|
-
enum: ['orbits', 'follows', 'attached_to', 'maintains_distance', 'points_at', 'mirrors', 'parallax', 'bounds_to', 'anchored_in_world', 'spring_follow', 'repels', 'wiggle', 'animates', 'grows_from', 'staggered_with', 'indicates', 'circumscribes', 'wave_through', 'morphs_to', 'group_morphs_to', 'moves_along_path', 'construction_reveal', 'triggers_animation', 'syncs_with', 'tours', 'synced_to_audio', 'expresses', 'camera_follows', 'camera_animates', 'is_midpoint_of', 'lies_on_line', 'is_centroid_of', 'is_circumcenter_of', 'concentric_with', 'driven_by', 'time_expression', 'on_click_fire', 'on_pointer_enter_fire', 'on_pointer_exit_fire', 'on_key_fire', 'on_event_fire_after', 'on_event_fire_if', 'on_event_add_relation', 'on_event_remove_relation', 'on_event_set_color', 'on_event_set_property', 'on_event_set_property_from_template', 'on_event_set_visibility', 'on_event_set_active', 'on_event_set_data', 'on_event_increment', 'on_event_toggle', 'on_event_store_set', 'on_event_store_increment', 'on_enter_set_color', 'on_enter_set_property', 'on_enter_set_property_from_template', 'on_enter_set_visibility', 'on_enter_set_data', 'on_enter_increment', 'on_enter_toggle', 'on_exit_set_color', 'on_exit_set_property', 'on_exit_set_property_from_template', 'on_exit_set_visibility', 'on_exit_set_data', 'on_exit_increment', 'on_exit_toggle', 'exclusive_group', 'menubar_group', 'restores_from', 'on_top_of', 'below', 'beside', 'inside', 'centered_on', 'aligned_with', 'part_of', 'connects_to', 'attached_to_tail', 'head_points_to'],
|
|
3916
|
+
enum: ['orbits', 'follows', 'attached_to', 'maintains_distance', 'points_at', 'mirrors', 'parallax', 'bounds_to', 'anchored_in_world', 'spring_follow', 'repels', 'attracts', 'wiggle', 'animates', 'grows_from', 'staggered_with', 'indicates', 'circumscribes', 'wave_through', 'morphs_to', 'group_morphs_to', 'moves_along_path', 'construction_reveal', 'triggers_animation', 'syncs_with', 'tours', 'synced_to_audio', 'expresses', 'camera_follows', 'camera_animates', 'is_midpoint_of', 'lies_on_line', 'is_centroid_of', 'is_circumcenter_of', 'concentric_with', 'driven_by', 'time_expression', 'on_click_fire', 'on_pointer_enter_fire', 'on_pointer_exit_fire', 'on_key_fire', 'on_event_fire_after', 'on_event_fire_if', 'on_event_add_relation', 'on_event_remove_relation', 'on_event_set_color', 'on_event_set_property', 'on_event_set_property_from_template', 'on_event_set_visibility', 'on_event_set_active', 'on_event_set_data', 'on_event_increment', 'on_event_toggle', 'on_event_store_set', 'on_event_store_increment', 'on_enter_set_color', 'on_enter_set_property', 'on_enter_set_property_from_template', 'on_enter_set_visibility', 'on_enter_set_data', 'on_enter_increment', 'on_enter_toggle', 'on_exit_set_color', 'on_exit_set_property', 'on_exit_set_property_from_template', 'on_exit_set_visibility', 'on_exit_set_data', 'on_exit_increment', 'on_exit_toggle', 'exclusive_group', 'menubar_group', 'restores_from', 'on_top_of', 'below', 'beside', 'inside', 'centered_on', 'aligned_with', 'part_of', 'connects_to', 'attached_to_tail', 'head_points_to'],
|
|
3600
3917
|
},
|
|
3601
3918
|
params: {
|
|
3602
3919
|
type: 'object',
|
|
@@ -4242,7 +4559,7 @@ flags as a badly-composed scene, and they do not survive an artboard change.`,
|
|
|
4242
4559
|
register: { type: 'string', enum: ['naive', 'playful', 'poster', 'editorial', 'technical'], description: 'Which design language. Resolves gutter, margin, hue budget and type scale together; an explicit craft still overrides it.' },
|
|
4243
4560
|
level: { type: 'number', description: 'Craft level 1-4 within the register: sketch, competent, refined, art-directed.' },
|
|
4244
4561
|
medium: { type: 'string', enum: ['vector', 'thread'], description: "What makes the marks. 'thread' stitches every closed path AFTER arranging; photographs and text cannot be stitched and return in medium.skipped with the reason. Other media are refused with their own reason rather than faked." },
|
|
4245
|
-
stitch: { type: 'string', enum: [
|
|
4562
|
+
stitch: { type: 'string', enum: [...THREAD_STITCHES], description: 'Which stitch when medium is thread (default longAndShort) — the same six pinepaper_design_medium offers.' },
|
|
4246
4563
|
stitchBudget: { type: 'number', description: 'Total marks across the composition (default 6000); the stitch scales to fit rather than the fill being cut short.' },
|
|
4247
4564
|
action: { type: 'string', enum: ['list_patterns', 'list_treatments', 'apply', 'set_treatment'] },
|
|
4248
4565
|
pattern: { type: 'string', description: 'Pattern key from list_patterns' },
|
|
@@ -4827,8 +5144,13 @@ EXAMPLE — Choose effect for a victory card:
|
|
|
4827
5144
|
properties: {
|
|
4828
5145
|
action: {
|
|
4829
5146
|
type: 'string',
|
|
4830
|
-
enum: ['list', 'choose', 'coverage', 'find'],
|
|
4831
|
-
description:
|
|
5147
|
+
enum: ['list', 'choose', 'coverage', 'find', 'catalogue', 'studio'],
|
|
5148
|
+
description: "Query mode: list, choose, coverage, find, catalogue, or studio (default: list). 'catalogue' reads a registry the aggregate does not gather. 'studio' reports which engine METHODS this studio has, so you learn what will refuse BEFORE calling it — long-form export needs exportEngine.exportToStore, mesh authoring needs extrudeToMesh, and this is how you find out without trying each.",
|
|
5149
|
+
},
|
|
5150
|
+
catalogue: {
|
|
5151
|
+
type: 'string',
|
|
5152
|
+
enum: ['rig_presets', 'shader_effects', 'stroke_decorations', 'precomps', 'images', 'segment_edit_kinds', 'shatter_orders', 'world_meshes', 'relation_presets'],
|
|
5153
|
+
description: "action 'catalogue': which registry to read. These sit OUTSIDE the aggregate, which already covers styles, effects, deforms, entrances, animations, collages, palettes, masks, maskShapes and cutouts — 'list' reaches all of those.",
|
|
4832
5154
|
},
|
|
4833
5155
|
kind: {
|
|
4834
5156
|
anyOf: [{ type: 'string' }, { type: 'array', items: { type: 'string' } }],
|
|
@@ -6447,6 +6769,7 @@ SHADER AURAS (WebGL2, silhouette-clipped — same tool, routed to the aura syste
|
|
|
6447
6769
|
- vortex: The bright band is a RING, not a disc — condensation tracks the steepest pressure gradient, so the core is hollow, and differential rotation shears the field rather than spinning one picture round.
|
|
6448
6770
|
- rain_veil: Drifting sheets of falling rain across the silhouette.
|
|
6449
6771
|
- caustics: Refracted light patterns, as through moving water.
|
|
6772
|
+
- ink_bleed: Ink wicking outward into the surface, as on absorbent paper. Routable since the engine began publishing every aura name and warming the subsystem before routing; it was defined-but-unreachable before that, which is why it arrived last.
|
|
6450
6773
|
Aura params: { intensity, radius, palette, mode ('inside'|'outside'|'overlay'), tint, tintStrength, offsetX, offsetY, channels: { a: {speed, curve}, b: {speed, curve} } } — curves: linear, sawtooth, sine, triangle, pulse, ease, bounce, noise.
|
|
6451
6774
|
|
|
6452
6775
|
EXAMPLE — bubbles with magenta interior over a blue rim:
|
|
@@ -6459,7 +6782,7 @@ EXAMPLE — gold liquid-metal aura outside a logo:
|
|
|
6459
6782
|
itemId: { type: 'string', description: 'Registry ID of the item' },
|
|
6460
6783
|
effectType: {
|
|
6461
6784
|
type: 'string',
|
|
6462
|
-
enum: ['sparkle', 'blast', 'smoke', 'fire', 'rain', 'snow', 'confetti', 'ripple', 'glow', 'electric', 'bubbles', 'dust', 'fireflies', 'shockwave', 'trail', 'heatmap', 'liquid_metal', 'gem_smoke', 'electric_arc', 'vortex', 'rain_veil', 'caustics'],
|
|
6785
|
+
enum: ['sparkle', 'blast', 'smoke', 'fire', 'rain', 'snow', 'confetti', 'ripple', 'glow', 'electric', 'bubbles', 'dust', 'fireflies', 'shockwave', 'trail', 'heatmap', 'liquid_metal', 'gem_smoke', 'electric_arc', 'vortex', 'rain_veil', 'caustics', 'ink_bleed'],
|
|
6463
6786
|
description: 'Type of effect',
|
|
6464
6787
|
},
|
|
6465
6788
|
params: {
|
|
@@ -6940,7 +7263,7 @@ PRIVACY: No screenshots, no tool call arguments, no user content — only struct
|
|
|
6940
7263
|
idempotentHint: false,
|
|
6941
7264
|
openWorldHint: false,
|
|
6942
7265
|
},
|
|
6943
|
-
description: `Start a new agent job for creating animations, videos, graphics, or any visual content. Do
|
|
7266
|
+
description: `Start a new agent job for creating animations, videos, graphics, or any visual content. Do not hand-write HTML or React INSTEAD OF calling these tools — but if the user wants an HTML page or an embeddable widget, that is pinepaper_export_widget_html and pinepaper_export_widget, and they are the right answer rather than a fallback.
|
|
6944
7267
|
|
|
6945
7268
|
⚠️ Call ONCE per pipeline. NEVER restart — creates duplicates.
|
|
6946
7269
|
|
|
@@ -7243,7 +7566,7 @@ EXAMPLE — Animated sky scene with timed reveals:
|
|
|
7243
7566
|
targetId: { type: 'string', description: 'For relation: target item ID or $N' },
|
|
7244
7567
|
relationType: {
|
|
7245
7568
|
type: 'string',
|
|
7246
|
-
enum: ['orbits', 'follows', 'attached_to', 'maintains_distance', 'points_at', 'mirrors', 'parallax', 'bounds_to', 'anchored_in_world', 'spring_follow', 'repels', 'wiggle', 'animates', 'grows_from', 'staggered_with', 'indicates', 'circumscribes', 'wave_through', 'morphs_to', 'group_morphs_to', 'moves_along_path', 'construction_reveal', 'triggers_animation', 'syncs_with', 'tours', 'synced_to_audio', 'expresses', 'camera_follows', 'camera_animates', 'is_midpoint_of', 'lies_on_line', 'is_centroid_of', 'is_circumcenter_of', 'concentric_with', 'driven_by', 'time_expression', 'on_click_fire', 'on_pointer_enter_fire', 'on_pointer_exit_fire', 'on_key_fire', 'on_event_fire_after', 'on_event_fire_if', 'on_event_add_relation', 'on_event_remove_relation', 'on_event_set_color', 'on_event_set_property', 'on_event_set_property_from_template', 'on_event_set_visibility', 'on_event_set_active', 'on_event_set_data', 'on_event_increment', 'on_event_toggle', 'on_event_store_set', 'on_event_store_increment', 'on_enter_set_color', 'on_enter_set_property', 'on_enter_set_property_from_template', 'on_enter_set_visibility', 'on_enter_set_data', 'on_enter_increment', 'on_enter_toggle', 'on_exit_set_color', 'on_exit_set_property', 'on_exit_set_property_from_template', 'on_exit_set_visibility', 'on_exit_set_data', 'on_exit_increment', 'on_exit_toggle', 'exclusive_group', 'menubar_group', 'restores_from', 'on_top_of', 'below', 'beside', 'inside', 'centered_on', 'aligned_with', 'part_of', 'connects_to', 'attached_to_tail', 'head_points_to'],
|
|
7569
|
+
enum: ['orbits', 'follows', 'attached_to', 'maintains_distance', 'points_at', 'mirrors', 'parallax', 'bounds_to', 'anchored_in_world', 'spring_follow', 'repels', 'attracts', 'wiggle', 'animates', 'grows_from', 'staggered_with', 'indicates', 'circumscribes', 'wave_through', 'morphs_to', 'group_morphs_to', 'moves_along_path', 'construction_reveal', 'triggers_animation', 'syncs_with', 'tours', 'synced_to_audio', 'expresses', 'camera_follows', 'camera_animates', 'is_midpoint_of', 'lies_on_line', 'is_centroid_of', 'is_circumcenter_of', 'concentric_with', 'driven_by', 'time_expression', 'on_click_fire', 'on_pointer_enter_fire', 'on_pointer_exit_fire', 'on_key_fire', 'on_event_fire_after', 'on_event_fire_if', 'on_event_add_relation', 'on_event_remove_relation', 'on_event_set_color', 'on_event_set_property', 'on_event_set_property_from_template', 'on_event_set_visibility', 'on_event_set_active', 'on_event_set_data', 'on_event_increment', 'on_event_toggle', 'on_event_store_set', 'on_event_store_increment', 'on_enter_set_color', 'on_enter_set_property', 'on_enter_set_property_from_template', 'on_enter_set_visibility', 'on_enter_set_data', 'on_enter_increment', 'on_enter_toggle', 'on_exit_set_color', 'on_exit_set_property', 'on_exit_set_property_from_template', 'on_exit_set_visibility', 'on_exit_set_data', 'on_exit_increment', 'on_exit_toggle', 'exclusive_group', 'menubar_group', 'restores_from', 'on_top_of', 'below', 'beside', 'inside', 'centered_on', 'aligned_with', 'part_of', 'connects_to', 'attached_to_tail', 'head_points_to'],
|
|
7247
7570
|
description: 'For relation: type',
|
|
7248
7571
|
},
|
|
7249
7572
|
relationOptions: { type: 'object', description: 'For relation: options' },
|
|
@@ -7286,6 +7609,50 @@ EXAMPLE — Animated sky scene with timed reveals:
|
|
|
7286
7609
|
required: ['operations'],
|
|
7287
7610
|
},
|
|
7288
7611
|
},
|
|
7612
|
+
{
|
|
7613
|
+
name: 'pinepaper_export_store',
|
|
7614
|
+
annotations: {
|
|
7615
|
+
title: 'Export Store',
|
|
7616
|
+
readOnlyHint: false,
|
|
7617
|
+
destructiveHint: true,
|
|
7618
|
+
idempotentHint: false,
|
|
7619
|
+
openWorldHint: false,
|
|
7620
|
+
},
|
|
7621
|
+
description: `Recover an export the studio is still holding.
|
|
7622
|
+
|
|
7623
|
+
A long export is not returned inline — the studio keeps the encoded file and pinepaper_agent_export pages it out to a file for you. When that PAGING half fails, the render has already succeeded and the bytes are sitting in the store. This is how you go and get them, instead of re-rendering something that already exists.
|
|
7624
|
+
|
|
7625
|
+
ACTIONS:
|
|
7626
|
+
- list: {} — what is held, newest first: {id, format, size, createdAt}. The id IS the stored filename and the store is origin-persistent, so ids survive a page reload; an id lost with a dropped tool result is recoverable here.
|
|
7627
|
+
- save: {exportId} — page it out to a file and release it once the file is whole. Returns a filePath, the same shape agent_export returns. Safe to repeat: reading a held export mutates nothing, so a failed save can simply be run again.
|
|
7628
|
+
- release: {exportId} — drop it WITHOUT saving. The store is the only copy; this is not undoable.
|
|
7629
|
+
|
|
7630
|
+
WHEN TO REACH FOR IT:
|
|
7631
|
+
- An export failed with "Failed to write data to data pipe". That is the browser's transport refusing to carry one oversized value, not the encoder failing — the bytes may already be in the store. Call 'list' BEFORE re-rendering.
|
|
7632
|
+
- An export error named an exportId and a byte count reached. That error is a true promise: call 'save' with the id.
|
|
7633
|
+
|
|
7634
|
+
RETENTION, AND THE ONE WAY TO LOSE WORK:
|
|
7635
|
+
Held exports last until released, or until a LATER export needs the space — and eviction drops the OLDEST first. Rendering five chunks and paging them out at the end can evict chunk 1 to make room for chunk 5. Save or release each export before starting the next one. An id dropped this way usually says "evicted" rather than "not found", including after a page reload — but that record is best-effort browser storage, so a miss can still be genuinely ambiguous. Treat the absence of "evicted" as "unknown", never as proof the export never existed.`,
|
|
7636
|
+
inputSchema: {
|
|
7637
|
+
type: 'object',
|
|
7638
|
+
properties: {
|
|
7639
|
+
action: {
|
|
7640
|
+
type: 'string',
|
|
7641
|
+
enum: ['list', 'save', 'release'],
|
|
7642
|
+
description: "'list' (what is held), 'save' (page it to a file, then release), 'release' (drop it unsaved).",
|
|
7643
|
+
},
|
|
7644
|
+
exportId: {
|
|
7645
|
+
type: 'string',
|
|
7646
|
+
description: "Required for 'save' and 'release'. From a failed export's error, or from 'list'.",
|
|
7647
|
+
},
|
|
7648
|
+
platform: {
|
|
7649
|
+
type: 'string',
|
|
7650
|
+
description: "save: a label for the saved filename only. Defaults to 'recovered'.",
|
|
7651
|
+
},
|
|
7652
|
+
},
|
|
7653
|
+
required: ['action'],
|
|
7654
|
+
},
|
|
7655
|
+
},
|
|
7289
7656
|
{
|
|
7290
7657
|
name: 'pinepaper_agent_export',
|
|
7291
7658
|
annotations: {
|
|
@@ -7330,8 +7697,17 @@ EXAMPLES:
|
|
|
7330
7697
|
},
|
|
7331
7698
|
format: {
|
|
7332
7699
|
type: 'string',
|
|
7333
|
-
enum: ['svg', 'png', 'gif', 'mp4', 'webm', 'pdf'],
|
|
7334
|
-
description:
|
|
7700
|
+
enum: ['svg', 'png', 'gif', 'mp4', 'webm', 'pdf', 'wav'],
|
|
7701
|
+
description: "Override format (auto-detected if not specified). 'wav' exports the SOUNDTRACK ON ITS OWN, with no frames rendered — no platform preset resolves to it, so it must be asked for by name, and platform dimensions, framing and quality do not apply.",
|
|
7702
|
+
},
|
|
7703
|
+
sampleRate: {
|
|
7704
|
+
type: 'number',
|
|
7705
|
+
description: 'wav only: samples per second (default 48000). Rejected for any other format.',
|
|
7706
|
+
},
|
|
7707
|
+
bitDepth: {
|
|
7708
|
+
type: 'number',
|
|
7709
|
+
enum: [16, 32],
|
|
7710
|
+
description: 'wav only: 16 (default) or 32-bit float. Rejected for any other format.',
|
|
7335
7711
|
},
|
|
7336
7712
|
quality: {
|
|
7337
7713
|
type: 'string',
|
|
@@ -7345,7 +7721,7 @@ EXAMPLES:
|
|
|
7345
7721
|
},
|
|
7346
7722
|
estimateOnly: {
|
|
7347
7723
|
type: 'boolean',
|
|
7348
|
-
description: 'Preflight only — return the estimated file size for these exact settings and render nothing. Modeled for mp4/webm/gif; png/pdf/svg report confidence "none" (no dimension-based model exists for them).',
|
|
7724
|
+
description: 'Preflight only — return the estimated file size for these exact settings and render nothing. Modeled for mp4/webm/gif; png/pdf/svg report confidence "none" (no dimension-based model exists for them); wav reports confidence "exact", because uncompressed PCM size is arithmetic.',
|
|
7349
7725
|
},
|
|
7350
7726
|
duration: {
|
|
7351
7727
|
type: 'number',
|
|
@@ -8095,6 +8471,9 @@ ACTIONS:
|
|
|
8095
8471
|
required: ['action'],
|
|
8096
8472
|
},
|
|
8097
8473
|
},
|
|
8474
|
+
// ---------------------------------------------------------------------------
|
|
8475
|
+
// STITCHCRAFT PROCEDURAL EMBROIDERY & THREAD
|
|
8476
|
+
// ---------------------------------------------------------------------------
|
|
8098
8477
|
];
|
|
8099
8478
|
/**
|
|
8100
8479
|
* Get a tool definition by name
|