@pinepaper.studio/mcp-server 1.6.19 → 1.6.20
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 +1 -1
- package/README.es.md +1 -1
- package/README.fr.md +1 -1
- package/README.hi.md +1 -1
- package/README.ja.md +1 -1
- package/README.ko.md +1 -1
- package/README.md +86 -4
- package/README.pt-BR.md +1 -1
- package/README.zh-CN.md +1 -1
- package/dist/build-info.json +3 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +7 -4
- package/dist/index.js.map +1 -1
- package/dist/ontology/upstream-vocabulary.d.ts +2 -2
- package/dist/ontology/upstream-vocabulary.js +2 -2
- package/dist/ontology/vocabulary.d.ts.map +1 -1
- package/dist/ontology/vocabulary.js +8 -0
- package/dist/ontology/vocabulary.js.map +1 -1
- package/dist/tools/choreograph.d.ts +64 -0
- package/dist/tools/choreograph.d.ts.map +1 -0
- package/dist/tools/choreograph.js +336 -0
- package/dist/tools/choreograph.js.map +1 -0
- package/dist/tools/compact-descriptions.js +1 -1
- package/dist/tools/definitions.d.ts +10 -1
- package/dist/tools/definitions.d.ts.map +1 -1
- package/dist/tools/definitions.js +284 -25
- package/dist/tools/definitions.js.map +1 -1
- package/dist/tools/effect-check.d.ts +26 -0
- package/dist/tools/effect-check.d.ts.map +1 -0
- package/dist/tools/effect-check.js +129 -0
- package/dist/tools/effect-check.js.map +1 -0
- package/dist/tools/effect-class.d.ts +31 -0
- package/dist/tools/effect-class.d.ts.map +1 -0
- package/dist/tools/effect-class.js +170 -0
- package/dist/tools/effect-class.js.map +1 -0
- package/dist/tools/engine-lists.d.ts +6 -6
- package/dist/tools/engine-lists.d.ts.map +1 -1
- package/dist/tools/engine-lists.js +11 -9
- package/dist/tools/engine-lists.js.map +1 -1
- package/dist/tools/engine-methods.d.ts.map +1 -1
- package/dist/tools/engine-methods.js +8 -0
- package/dist/tools/engine-methods.js.map +1 -1
- package/dist/tools/engine-surface.d.ts +1 -1
- package/dist/tools/engine-surface.d.ts.map +1 -1
- package/dist/tools/engine-surface.js +188 -10
- package/dist/tools/engine-surface.js.map +1 -1
- package/dist/tools/handlers/export.d.ts.map +1 -1
- package/dist/tools/handlers/export.js +8 -1
- package/dist/tools/handlers/export.js.map +1 -1
- package/dist/tools/handlers.d.ts +23 -0
- package/dist/tools/handlers.d.ts.map +1 -1
- package/dist/tools/handlers.js +176 -5
- package/dist/tools/handlers.js.map +1 -1
- package/dist/tools/index.d.ts +2 -2
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/index.js +2 -2
- package/dist/tools/index.js.map +1 -1
- package/dist/tools/minimal-descriptions.d.ts.map +1 -1
- package/dist/tools/minimal-descriptions.js +9 -3
- package/dist/tools/minimal-descriptions.js.map +1 -1
- package/dist/tools/shape-params.d.ts +2 -2
- package/dist/tools/shape-params.d.ts.map +1 -1
- package/dist/tools/shape-params.js +24 -2
- package/dist/tools/shape-params.js.map +1 -1
- package/dist/tools/stick-vocabulary.d.ts +1 -1
- package/dist/tools/stick-vocabulary.js +1 -1
- package/dist/tools/toolkits.d.ts.map +1 -1
- package/dist/tools/toolkits.js +6 -0
- package/dist/tools/toolkits.js.map +1 -1
- package/dist/types/code-generator.d.ts +35 -1
- package/dist/types/code-generator.d.ts.map +1 -1
- package/dist/types/code-generator.js +538 -24
- package/dist/types/code-generator.js.map +1 -1
- package/dist/types/schemas.d.ts +1617 -273
- package/dist/types/schemas.d.ts.map +1 -1
- package/dist/types/schemas.js +164 -2
- package/dist/types/schemas.js.map +1 -1
- package/manifest.json +25 -1
- package/package.json +4 -3
|
@@ -27,9 +27,44 @@ const SIMPLE_ANIMATION_TYPES_LIST = SimpleAnimationTypeSchema.options.join(', ')
|
|
|
27
27
|
// (round 8 DD, 1.68) — derived now, so it cannot say what the schema refuses.
|
|
28
28
|
const KEYFRAME_EASINGS_LIST = EasingSchema.options.join(', ');
|
|
29
29
|
const EASING_LINES = KEYFRAME_EASINGS.map((e) => `- ${e}: ${EASING_DESCRIPTIONS[e]}`).join('\n');
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
30
|
+
const DOORS = [
|
|
31
|
+
{ when: 'A scene or landscape drawn in an art style (cut paper, ink, watercolour, dither, flow, ASCII)', doors: [{ tool: 'pinepaper_styled_scene', text: 'pinepaper_styled_scene' }] },
|
|
32
|
+
{ when: 'Make THIS — an item, a character, the whole scene — look like a style (8-bit, blueprint, ink sketch, flat modern, print halftone, paper cutout…)', doors: [{ tool: 'pinepaper_look', text: 'pinepaper_look (describe first: the engine grades each look native / faithful / impression)' }] },
|
|
33
|
+
{ when: 'A story, several beats, a narrative from prose — a video or film in N parts, or a click-through widget', doors: [{ tool: 'pinepaper_story', text: "pinepaper_story (from_text; nav: 'scenes' for a VIDEO — a scene chain that cuts — 'panels' for a widget)" }, { tool: 'pinepaper_scene_playback', text: 'scene chains (pinepaper_scene_playback: cutSound, play)' }] },
|
|
34
|
+
{ when: 'An ORIGINAL character from a description (a hero with a cape, a round robot, a cat in glasses), or a cast of variants', doors: [{ tool: 'pinepaper_original_character', text: 'pinepaper_original_character (describe first, then create)' }] },
|
|
35
|
+
{ when: 'A character that acts (expressions, poses, walks)', doors: [{ tool: 'pinepaper_character', text: 'pinepaper_character' }, { tool: 'pinepaper_stick', text: 'pinepaper_stick' }, { tool: 'pinepaper_rigging', text: 'pinepaper_rigging' }, { tool: 'pinepaper_deform', text: 'squash and stretch via pinepaper_deform' }] },
|
|
36
|
+
{ when: 'A number that counts up (a KPI roll-up, a year counter, a timer)', doors: [{ tool: 'pinepaper_create_item', text: 'create_item text with counter: exact on every frame, steady width; year counters: counter {from: -30000, to: 2026, era: true}' }] },
|
|
37
|
+
{ when: 'Any item that moves with intent (pops in, hops, bounces, rolls, flies, peeks, lands)', doors: [{ tool: 'pinepaper_choreograph', text: 'pinepaper_choreograph: beats, not hand-timed keyframes' }] },
|
|
38
|
+
{ when: 'One element that becomes the next thing, and the next, with no cuts (a pill → a field → a dot → a card)', doors: [{ tool: 'pinepaper_morph_sequence', text: 'pinepaper_morph_sequence' }] },
|
|
39
|
+
{ when: 'A title or caption with craft', doors: [{ tool: 'pinepaper_text_style', text: 'pinepaper_text_style (display styles; cursive with animate writes itself on)' }, { tool: 'pinepaper_text_effect', text: 'pinepaper_text_effect' }] },
|
|
40
|
+
{ when: 'A poster or layout in an aesthetic, or a collage', doors: [{ tool: 'pinepaper_design_system', text: 'pinepaper_design_system (compose)' }, { tool: 'pinepaper_compose', text: 'a collage: pinepaper_compose' }] },
|
|
41
|
+
{ when: 'A painted, stitched, hatched, inked or cut-paper look on shapes or photos', doors: [{ tool: 'pinepaper_design_medium', text: 'pinepaper_design_medium' }, { tool: 'pinepaper_image_filter', text: 'photos also pinepaper_image_filter (watercolor, painterly)' }] },
|
|
42
|
+
{ when: 'A brand', doors: [{ tool: 'pinepaper_brand_kit', text: 'pinepaper_brand_kit set (first): every item made afterwards inherits it' }] },
|
|
43
|
+
{ when: 'Sound and music', doors: [{ tool: 'pinepaper_sound', text: 'pinepaper_sound' }, { tool: 'pinepaper_audio_beats', text: 'pinepaper_audio_beats' }, { tool: 'pinepaper_beat_cuts', text: 'pinepaper_beat_cuts' }] },
|
|
44
|
+
{ when: 'Particles that must survive save, export and the cloud (confetti bursts, a trail), or custom per-frame drawing', doors: [{ tool: 'pinepaper_emitter', text: 'pinepaper_emitter' }, { tool: 'pinepaper_render_hook', text: 'custom drawing: pinepaper_render_hook' }] },
|
|
45
|
+
{ when: 'A camera move through the piece, or 3D', doors: [{ tool: 'pinepaper_camera_director', text: 'pinepaper_camera_director' }, { tool: 'pinepaper_world3d', text: '3D: pinepaper_world3d' }, { tool: 'pinepaper_relight', text: 'pinepaper_relight' }] },
|
|
46
|
+
];
|
|
47
|
+
/**
|
|
48
|
+
* The door block for a host's tool list (D72; cloud request from a3). A host
|
|
49
|
+
* that offers only some tools passes their names: a row keeps only the doors
|
|
50
|
+
* that host has, and a row with none is dropped — so the model is never told
|
|
51
|
+
* to "use pinepaper_X" for a tool it cannot see. With no list, every door.
|
|
52
|
+
*/
|
|
53
|
+
export function buildDoorBlock(available) {
|
|
54
|
+
const has = available ? new Set(available) : null;
|
|
55
|
+
const rows = DOORS.map((d) => {
|
|
56
|
+
const doors = d.doors.filter((x) => !has || !x.tool || has.has(x.tool));
|
|
57
|
+
return doors.length ? `- ${d.when} → ${doors.map((x) => x.text).join('; ')}` : null;
|
|
58
|
+
}).filter(Boolean);
|
|
59
|
+
return [
|
|
60
|
+
'CHOOSE THE HIGHEST-LEVEL TOOL FIRST. Primitive shapes over a generator backdrop with a pulse is the stock result users reject; reach for it only when nothing below fits the brief.',
|
|
61
|
+
...rows,
|
|
62
|
+
'pinepaper_agent_batch_execute then does the glue in ONE call: extra items, keyframes, relations, masks, effects, playback.',
|
|
63
|
+
'If no tool reaches what the brief asks (for example, redrawing a subject in another art style), tell the user what is missing instead of handing over a lesser result as done.',
|
|
64
|
+
].join('\n');
|
|
65
|
+
}
|
|
66
|
+
/** The full door block (every tool), for the guide and a local server. */
|
|
67
|
+
export const CHOOSE_THE_DOOR = buildDoorBlock();
|
|
33
68
|
export const AI_AGENT_GUIDE = `⚠️ You are connected to PinePaper Studio via MCP tools. ALWAYS use these tools to create visual content.
|
|
34
69
|
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.
|
|
35
70
|
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.
|
|
@@ -43,11 +78,14 @@ The generated code is shown in tool responses and can be copied into PinePaper's
|
|
|
43
78
|
|
|
44
79
|
⚠️ 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.
|
|
45
80
|
|
|
81
|
+
${CHOOSE_THE_DOOR}
|
|
82
|
+
|
|
46
83
|
WORKFLOW — Create → Validate → Iterate:
|
|
47
84
|
|
|
48
85
|
1. pinepaper_agent_start_job (clearCanvas: true, canvasPreset)
|
|
49
|
-
2.
|
|
50
|
-
|
|
86
|
+
2. The craft tool(s) above that fit the brief, each called once.
|
|
87
|
+
Then pinepaper_agent_batch_execute — ONE call for the glue:
|
|
88
|
+
set_canvas_size → set_background → create items → keyframe_animate / animate → relation → apply_mask → apply_effect → play_timeline
|
|
51
89
|
3. pinepaper_agent_end_job — returns screenshot
|
|
52
90
|
4. Show screenshot to user for validation
|
|
53
91
|
5. If user wants changes → modify specific items or start a new job
|
|
@@ -59,13 +97,13 @@ If you restart the pipeline or re-call batch_execute, you DOUBLE every item on t
|
|
|
59
97
|
To fix mistakes: use modify/delete operations, or start a NEW job with clearCanvas: true.
|
|
60
98
|
|
|
61
99
|
RULES:
|
|
62
|
-
- NEVER restart the pipeline — one start_job, one batch_execute, one end_job
|
|
63
|
-
-
|
|
100
|
+
- NEVER restart the pipeline — one start_job, one batch_execute, one end_job; the craft tools go between them
|
|
101
|
+
- Primitive operations go in the ONE batch_execute — canvas, background, items, animation, masks, effects, playback
|
|
64
102
|
- EXCEPTION: Diagrams (flowcharts, UML) use pinepaper_create_diagram_shape + pinepaper_connect, NOT batch_execute
|
|
65
|
-
-
|
|
103
|
+
- A generator is a BACKDROP: under a composed scene it adds texture; on its own it is the stock look. Prefer a styled scene, a drawn world or a real photo for the ground of a piece
|
|
66
104
|
- Use "$0", "$1" to reference items by creation order within the batch
|
|
67
105
|
|
|
68
|
-
─── BATCH OPERATIONS (
|
|
106
|
+
─── BATCH OPERATIONS (${AgentBatchOperationTypeSchema.options.length} types, in order) ───
|
|
69
107
|
|
|
70
108
|
CANVAS: set_canvas_size (width/height or preset) → set_background (color) → execute_generator (procedural art)
|
|
71
109
|
ITEMS: create (itemType, position, properties) → modify (itemId, properties) → delete (itemId) → group (itemIds → one entity)
|
|
@@ -73,9 +111,9 @@ ANIMATE: animate (loop presets) → keyframe_animate (timed reveals) → relatio
|
|
|
73
111
|
EFFECTS: apply_mask (reveal animations) → apply_effect (sparkle/blast/bubbles/fireflies/trail...)
|
|
74
112
|
PLAY: play_timeline (start playback)
|
|
75
113
|
|
|
76
|
-
─── GENERATORS (
|
|
114
|
+
─── GENERATORS (procedural backdrops — under a scene, not as one) ───
|
|
77
115
|
|
|
78
|
-
Generators fill the canvas with procedural art
|
|
116
|
+
Generators fill the canvas with procedural art: richer than a flat colour as a backdrop, but not a composition by themselves.
|
|
79
117
|
Choose based on mood:
|
|
80
118
|
Dreamy/soft: drawBokeh, drawGradientMesh, drawOrganicFlow
|
|
81
119
|
Techy/modern: drawCircuit, drawGrid, drawWindField
|
|
@@ -556,6 +594,9 @@ For glossy 3D spheres, use pinepaper_create_glossy_sphere instead. For diagonal
|
|
|
556
594
|
inputSchema: {
|
|
557
595
|
type: 'object',
|
|
558
596
|
properties: {
|
|
597
|
+
screenSpace: { type: 'boolean', description: 'HUD: true keeps the item fixed in the FRAME under camera moves; its x/y, keyframes and relations are then frame coordinates. Exports (mp4, webm, gif, png, pdf) honour it; the live preview still tilts it; SVG and Lottie ignore it (agent_export warns). A studio without it refuses.' },
|
|
598
|
+
counter: { description: "TEXT only: a number that counts on the scene clock, exact on every exported frame. {from, to, start? (s), duration? (s, 1), easing? (engine name or [x1,y1,x2,y2]), decimals?, prefix?, suffix?, locale?, grouping?, padStart?, steps?, tabular? (true: steady width)}; null removes it. A year counter: {from: -30000, to: 2026, era: true} reads '30,000 BCE' … '2026 CE' (eraNegative / eraPositive relabel; no year 0); a KPI: {from: 1.67, to: 5.58, suffix: '%'}. A studio without counters refuses.", oneOf: [{ type: 'object', additionalProperties: true }, { type: 'null' }] },
|
|
599
|
+
stepTiming: { description: "Animate 'on twos': N or {every: N, baseFps?} (every N frames of a 30 fps base unless baseFps), {fps}, or null to turn off. A stepped group steps its children; follows, spring_follow, auras, rigging and GPU generators are not stepped. A studio without it refuses.", oneOf: [{ type: 'integer', minimum: 1 }, { type: 'object', properties: { every: { type: 'integer', minimum: 1 }, baseFps: { type: 'number' }, fps: { type: 'number' } } }, { type: 'null' }] },
|
|
559
600
|
itemType: {
|
|
560
601
|
type: 'string',
|
|
561
602
|
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'],
|
|
@@ -714,6 +755,9 @@ Use the collage group's id for palette/collageStyle; use a child letter's id for
|
|
|
714
755
|
inputSchema: {
|
|
715
756
|
type: 'object',
|
|
716
757
|
properties: {
|
|
758
|
+
screenSpace: { type: 'boolean', description: 'HUD: true keeps the item fixed in the FRAME under camera moves; its x/y, keyframes and relations are then frame coordinates. Exports (mp4, webm, gif, png, pdf) honour it; the live preview still tilts it; SVG and Lottie ignore it (agent_export warns). A studio without it refuses.' },
|
|
759
|
+
counter: { description: "TEXT only: a number that counts on the scene clock, exact on every exported frame. {from, to, start? (s), duration? (s, 1), easing? (engine name or [x1,y1,x2,y2]), decimals?, prefix?, suffix?, locale?, grouping?, padStart?, steps?, tabular? (true: steady width)}; null removes it. A year counter: {from: -30000, to: 2026, era: true} reads '30,000 BCE' … '2026 CE' (eraNegative / eraPositive relabel; no year 0); a KPI: {from: 1.67, to: 5.58, suffix: '%'}. A studio without counters refuses.", oneOf: [{ type: 'object', additionalProperties: true }, { type: 'null' }] },
|
|
760
|
+
stepTiming: { description: "Animate 'on twos': N or {every: N, baseFps?} (every N frames of a 30 fps base unless baseFps), {fps}, or null to turn off. A stepped group steps its children; follows, spring_follow, auras, rigging and GPU generators are not stepped. A studio without it refuses.", oneOf: [{ type: 'integer', minimum: 1 }, { type: 'object', properties: { every: { type: 'integer', minimum: 1 }, baseFps: { type: 'number' }, fps: { type: 'number' } } }, { type: 'null' }] },
|
|
717
761
|
itemId: {
|
|
718
762
|
type: 'string',
|
|
719
763
|
description: 'Registry ID of the item (e.g., "item_1")',
|
|
@@ -1073,7 +1117,7 @@ EXAMPLE (sequenceDiagram):
|
|
|
1073
1117
|
"mermaidText": "sequenceDiagram\\n Alice->>Bob: Hello\\n Bob-->>Alice: Hi back\\n Note right of Bob: Thinking..."
|
|
1074
1118
|
}
|
|
1075
1119
|
|
|
1076
|
-
Returns { success, nodeCount, edgeCount, nodes, edges, errors }.
|
|
1120
|
+
Returns { success, nodeCount, edgeCount, nodeItemIds, nodeIdMap?, edgeIds?, nodes, edges, errors }. nodeItemIds are the CANVAS ids of the shapes (item_N): pass THOSE to pinepaper_auto_layout, pinepaper_animate, pinepaper_add_relation. The mermaid ids (A, B…) in edges[].from/to name nodes in the source text and resolve to nothing on the canvas; nodeIdMap (where the studio returns it) maps one to the other, and edgeIds are the connectors' canvas ids.
|
|
1077
1121
|
|
|
1078
1122
|
NOTE: Import-only — there is no MCP equivalent of FxTool's exportMermaid. Mermaid lacks animation primitives, so a round-trip would silently drop animations.`,
|
|
1079
1123
|
inputSchema: {
|
|
@@ -1635,6 +1679,7 @@ RETURNS: create → { success, action, eventId }; pulse → { success, action, e
|
|
|
1635
1679
|
inputSchema: {
|
|
1636
1680
|
type: 'object',
|
|
1637
1681
|
properties: {
|
|
1682
|
+
at: { description: 'create: fire this event at these scene times (seconds) — a timed trigger that runs on the timeline and in video exports. The widget player does not run timed triggers.', oneOf: [{ type: 'number' }, { type: 'array', items: { type: 'number' } }] },
|
|
1638
1683
|
action: { type: 'string', enum: ['create', 'pulse'], description: "'create' a pp:event · 'pulse' it to fire" },
|
|
1639
1684
|
name: { type: 'string', description: "Event name — required for action 'create'" },
|
|
1640
1685
|
payloadType: { type: 'string', description: "Payload type label (default 'Pulse') — action 'create'" },
|
|
@@ -2355,7 +2400,7 @@ READ THIS BEFORE PROMISING A MEDIUM. Naming a medium does not create its marks.
|
|
|
2355
2400
|
Call resolve before telling a user you will render in a medium. "yes, but as an impression" is the true answer for half of them, and a flat approximation misrepresents a medium rather than approximating it.
|
|
2356
2401
|
|
|
2357
2402
|
ACTIONS:
|
|
2358
|
-
- apply: { itemId, medium, options? } — render an item in ANY medium the engine can make: ${Object.keys(DESIGN_MEDIA_APPLY).join(', ')}. One engine entry point; a medium this studio cannot apply is refused with the reason: pass it on. ink / charcoal (where the studio applies them) restyle a path, text, or group of them IN PLACE — same itemId, keyframes and relations kept — with a boiling hand-drawn line; raster and video exports boil, SVG/Lottie get the colour and width only. Their options: color, amplitude (px), wavelength (px), fps (boil rate, 12), seed, boil (default true), width (px, paths), keepColor. watercolor options: color, brush, water 0..1, opacity, edge 0..1 (the dark rim), angle, bleed, seed. oil (stylised): color, brush, length, density, toneRange, relief, angle, seed. cutPaper (vector: survives SVG/PDF/video): color, facet, jitter, shadow, shadowColor, shadowOpacity, shadowOffset [dx, dy], seed. The result replaces the source in the stacking order and hides it; applying again replaces; one undo step.
|
|
2403
|
+
- apply: { itemId, medium, options? } — on a PHOTO (an image item), watercolor and oil run as the watercolor / painterly image filters and report fidelity 'stylised' (an image filter, not paint simulated over geometry); other media are refused for photos, with the reason. On shapes — render an item in ANY medium the engine can make: ${Object.keys(DESIGN_MEDIA_APPLY).join(', ')}. One engine entry point; a medium this studio cannot apply is refused with the reason: pass it on. ink / charcoal (where the studio applies them) restyle a path, text, or group of them IN PLACE — same itemId, keyframes and relations kept — with a boiling hand-drawn line; raster and video exports boil, SVG/Lottie get the colour and width only. Their options: color, amplitude (px), wavelength (px), fps (boil rate, 12), seed, boil (default true), width (px, paths), keepColor. watercolor options: color, brush, water 0..1, opacity, edge 0..1 (the dark rim), angle, bleed, seed. oil (stylised): color, brush, length, density, toneRange, relief, angle, seed. cutPaper (vector: survives SVG/PDF/video): color, facet, jitter, shadow, shadowColor, shadowOpacity, shadowOffset [dx, dy], seed. The result replaces the source in the stacking order and hides it; applying again replaces; one undo step.
|
|
2359
2404
|
- list_media: every medium with fidelity, definition and limitation. Read it rather than assuming a fixed set — the catalogue grows (hatch and watercolor are recent additions).
|
|
2360
2405
|
- resolve: { medium } → { ok, fidelity, reason, markMaker }. ok:false with a reason is a real answer — pass it on rather than trying anyway.
|
|
2361
2406
|
- list_stitches: the thread stitches with their params.
|
|
@@ -2771,7 +2816,9 @@ The geometry is vendored from mcp-cloud, which makes this a three-repo artifact:
|
|
|
2771
2816
|
idempotentHint: false,
|
|
2772
2817
|
openWorldHint: false,
|
|
2773
2818
|
},
|
|
2774
|
-
description: `
|
|
2819
|
+
description: `FORM — nav: 'scenes' is the VIDEO story: one scene per part on a scene chain that cuts in time (export as MP4); each part's length follows its role (hook 2.5 s, stat 3 s, section 3.5 s, quote 3 s, exit 3 s; 0.4 s transitions), and the reply carries the cut times. nav: 'panels' (the default) is the WIDGET story: tabs a viewer clicks through (export_widget_html). A video brief needs 'scenes'.
|
|
2820
|
+
|
|
2821
|
+
A piece of prose becomes a scene.
|
|
2775
2822
|
|
|
2776
2823
|
- 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.
|
|
2777
2824
|
- from_text: distill and assemble in one call, when the reading does not need checking.
|
|
@@ -2780,6 +2827,7 @@ The geometry is vendored from mcp-cloud, which makes this a three-repo artifact:
|
|
|
2780
2827
|
inputSchema: {
|
|
2781
2828
|
type: 'object',
|
|
2782
2829
|
properties: {
|
|
2830
|
+
nav: { type: 'string', enum: ['panels', 'scenes'], description: "'scenes' = the video form (a scene chain that cuts); 'panels' = the widget form (default)" },
|
|
2783
2831
|
action: { type: 'string', enum: ['distill', 'from_text', 'apply_spec', 'plan_book'], description: 'Which story operation.' },
|
|
2784
2832
|
text: { type: 'string', description: 'distill / from_text: the prose.' },
|
|
2785
2833
|
spec: { type: 'object', description: 'apply_spec: the story spec, usually a distilled one you edited.' },
|
|
@@ -3440,6 +3488,7 @@ An event channel (pinepaper_event) is the hub: something FIRES it, and reactions
|
|
|
3440
3488
|
· on_event_fire_after (params: delay, timeline) — chain one beat to the next.
|
|
3441
3489
|
· on_event_fire_if — the only reaction that TESTS graph state rather than mutating it; params.predicate is an ExpressionIR program.
|
|
3442
3490
|
· on_event_add_relation / on_event_remove_relation — the scene rewires itself.
|
|
3491
|
+
· on_event_play_sound (source = the EVENT, target null; params: sound, gain?, note?) — play a sound when the event fires: a catalogue name (effect, drum or instrument; aliases accepted) or a define_sfx spec; gain is a multiplier capped at full scale; note is for instruments (default C5). An unknown sound is refused with the catalogue. Wire a click sound as on_click_fire (button → event) + on_event_play_sound (event → null). For a sound at a TIME, pinepaper_event create { at: seconds | [seconds] } fires the event on the timeline (and in video exports); a scene chain's cutSound puts one on every cut. LIMITS: the exported widget player does not run timed triggers, and a browser may block sound until the viewer's first click or key.
|
|
3443
3492
|
· on_event_store_set / on_event_store_increment / restores_from — persistent state. The target is a store node whose id is the storage SCOPE, so two stores in a scene and two widgets on a page do not collide. restores_from is the read half and fires ONCE at load.
|
|
3444
3493
|
- Proximity (pointer over an item): on_enter_* / on_exit_* mirror the on_event_* reactions above (set_color, set_property, set_property_from_template, set_visibility, set_data, increment, toggle) — hover states without a single line of script.
|
|
3445
3494
|
- Exclusive state: exclusive_group makes at most one member active (on_event_set_active is how you activate one — tabs, steppers, quiz cards). menubar_group is the same grouping WITHOUT the mutex.
|
|
@@ -3509,7 +3558,7 @@ Relations are COMPOSITIONAL - an item can have multiple relations that work toge
|
|
|
3509
3558
|
},
|
|
3510
3559
|
relationType: {
|
|
3511
3560
|
type: 'string',
|
|
3512
|
-
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'],
|
|
3561
|
+
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_event_play_sound', 'looks_at', 'reacts_to', 'drag_to_turn', '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'],
|
|
3513
3562
|
description: 'Type of relationship. A name registered with pinepaper_register_custom_relation in this session is accepted too.',
|
|
3514
3563
|
},
|
|
3515
3564
|
params: {
|
|
@@ -3552,7 +3601,7 @@ USE WHEN:
|
|
|
3552
3601
|
targetId: { type: 'string', description: 'Target item ID' },
|
|
3553
3602
|
relationType: {
|
|
3554
3603
|
type: 'string',
|
|
3555
|
-
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'],
|
|
3604
|
+
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_event_play_sound', 'looks_at', 'reacts_to', 'drag_to_turn', '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'],
|
|
3556
3605
|
description: 'Specific relation type to remove (optional - removes all if not specified)',
|
|
3557
3606
|
},
|
|
3558
3607
|
},
|
|
@@ -3580,7 +3629,7 @@ USE WHEN:
|
|
|
3580
3629
|
itemId: { type: 'string', description: 'Item to query relations for' },
|
|
3581
3630
|
relationType: {
|
|
3582
3631
|
type: 'string',
|
|
3583
|
-
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'],
|
|
3632
|
+
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_event_play_sound', 'looks_at', 'reacts_to', 'drag_to_turn', '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'],
|
|
3584
3633
|
description: 'Filter by relation type (optional)',
|
|
3585
3634
|
},
|
|
3586
3635
|
direction: {
|
|
@@ -3844,6 +3893,10 @@ EASING — IT SHAPES THE SEGMENT ARRIVING AT THE KEYFRAME IT IS ON.
|
|
|
3844
3893
|
The move from keyframe A to keyframe B is eased by B's easing, not A's. Easing on the FIRST keyframe does nothing (no segment arrives at it) — a Ken Burns with easing only on its first key plays linear. Put the easing on the key you are moving TO.
|
|
3845
3894
|
${EASING_LINES}
|
|
3846
3895
|
- or a custom cubic-bezier [x1, y1, x2, y2] — x in 0..1, y may exceed 0..1 for overshoot. keyframe_animate and camera_animate only.
|
|
3896
|
+
COUNTERS: a text item with a counter (create_item / modify_item counter) also animates the numeric property counterValue, drawn through the counter's format — keyframe it to shape a count by hand (hold on a number, then race). Its keys override the counter's own from / to.
|
|
3897
|
+
|
|
3898
|
+
HOLD KEYS (where the studio has them): interpolation: 'hold' on a key holds ITS value until the next key, then cuts — no in-between. Easing 'hold' / 'step' on the ARRIVING key does the same. A studio without hold keys refuses rather than interpolate; there, two keys a frame apart make the cut. For a whole layer 'on twos', set stepTiming on the item (create_item / modify_item).
|
|
3899
|
+
|
|
3847
3900
|
Every easing renders exactly in video, GIF and APNG. Lottie and CSS get the closest single Bézier: springPlayful loses its wobble, and the in-out quart/quint/expo/circ curves are within 2–4 %. SMIL is exact for springs and those four.
|
|
3848
3901
|
|
|
3849
3902
|
CLIP WINDOW (optional — Premiere/Canva-style clip behavior):
|
|
@@ -4504,7 +4557,7 @@ SUPPORTED ANIMATIONS: bounce, breathe, fade, glow, jelly, path, pulse, rotate, s
|
|
|
4504
4557
|
target: { type: 'string', description: 'Name of target item' },
|
|
4505
4558
|
type: {
|
|
4506
4559
|
type: 'string',
|
|
4507
|
-
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'],
|
|
4560
|
+
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_event_play_sound', 'looks_at', 'reacts_to', 'drag_to_turn', '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'],
|
|
4508
4561
|
},
|
|
4509
4562
|
params: {
|
|
4510
4563
|
type: 'object',
|
|
@@ -4637,6 +4690,7 @@ EXAMPLE — Slideshow:
|
|
|
4637
4690
|
inputSchema: {
|
|
4638
4691
|
type: 'object',
|
|
4639
4692
|
properties: {
|
|
4693
|
+
cutSound: { description: "create_chain: a sound at every cut — a catalogue name, or {sound, gain?, offset? (s)}. The scene_cut event also fires at each cut.", oneOf: [{ type: 'string' }, { type: 'object', additionalProperties: true }] },
|
|
4640
4694
|
action: {
|
|
4641
4695
|
type: 'string',
|
|
4642
4696
|
enum: ['create_chain', 'play', 'pause', 'resume', 'stop', 'toggle_loop', 'jump'],
|
|
@@ -5185,6 +5239,8 @@ ACTIONS:
|
|
|
5185
5239
|
- plan: Report what WOULD change (count, per-role breakdown, WCAG contrast audit) WITHOUT touching
|
|
5186
5240
|
the canvas. Call this first on an unfamiliar scene; a whole-scene recolour is hard to eyeball afterwards.
|
|
5187
5241
|
- apply: Commit it. A history snapshot is taken FIRST, so one undo puts everything back.
|
|
5242
|
+
- set: { kit } — apply it AND make it the ACTIVE brand for the rest of the piece: every shape created afterwards (create_item, batch create, agent_batch_execute) takes colors.primary, and every text colors.text with the heading font from 32 px up (body below), wherever the call names none. Pass noBrand: true in an item's properties to opt it out. Use set at the start of a multi-beat piece so beat 5 matches beat 1. It lives with the studio session: set it again after a reload.
|
|
5243
|
+
- get: the active brand (or null). clear: stop inheriting (what is on the canvas keeps its colours).
|
|
5188
5244
|
- from_url: { url, screenshots? } — read the product's REAL brand from its own site before animating anything: screenshots down the page, the logo (header image or SVG, else the site icon), and a proposed kit from the colours and fonts the site's CSS computes (buttons and links weigh most). Saved to files; the result lists them. Read in an isolated browser context: the studio is not touched. Review the kit against the screenshots, then plan / apply it. Use the brand you are given, never an invented one.
|
|
5189
5245
|
|
|
5190
5246
|
KIT SHAPE — only name and colors.primary are required:
|
|
@@ -5200,7 +5256,7 @@ Both actions return a WCAG contrast audit, so you can see failing pairs before s
|
|
|
5200
5256
|
inputSchema: {
|
|
5201
5257
|
type: 'object',
|
|
5202
5258
|
properties: {
|
|
5203
|
-
action: { type: 'string', enum: ['plan', 'apply', 'from_url'], description: 'plan (dry run), apply, or from_url (read a site into a proposed kit)' },
|
|
5259
|
+
action: { type: 'string', enum: ['plan', 'apply', 'from_url', 'set', 'get', 'clear'], description: 'plan (dry run), apply (once), set (apply + every new item inherits it), get, clear, or from_url (read a site into a proposed kit)' },
|
|
5204
5260
|
url: { type: 'string', description: "from_url: the product's site, http(s)." },
|
|
5205
5261
|
screenshots: { type: 'integer', minimum: 1, maximum: 6, description: 'from_url: screenshots down the page (default 3).' },
|
|
5206
5262
|
kit: {
|
|
@@ -5497,7 +5553,7 @@ ACTIONS:
|
|
|
5497
5553
|
idempotentHint: false,
|
|
5498
5554
|
openWorldHint: false,
|
|
5499
5555
|
},
|
|
5500
|
-
description: `Apply
|
|
5556
|
+
description: `Apply image filters to raster items: a GPU set, plus painted watercolor / painterly looks for photos.
|
|
5501
5557
|
|
|
5502
5558
|
ACTIONS:
|
|
5503
5559
|
- apply: Apply a single filter. Params: itemId, filterName, params
|
|
@@ -5510,6 +5566,8 @@ Available filters (GPU raster set):
|
|
|
5510
5566
|
- Stylize: vignette (intensity, radius), edgeDetect, halftoneDots (size, angle), halftoneCMYK (size), dither (levels), grain (amount, seed), scanlines (intensity, period), chromaticAberration (amount), blur (radius)
|
|
5511
5567
|
- Light (additive): bloom (amount, threshold, radius), glow, halation (warm-fringed bloom; color), lightShafts (amount, threshold, decay, density, x, y, color — volumetric rays from a point)
|
|
5512
5568
|
- Keying: lumaKey (threshold, softness, invert)
|
|
5569
|
+
- Pixel art: pixelate (size or cells across, levels, dither, palette [colours] — e.g. a PICO-8 set), where the studio has it
|
|
5570
|
+
- Painted (CPU, STILL images only, where the studio has them): watercolor (strength, seed, radius, edges, bleed, granulation, paper, washes — layered washes, pigment rims, paper grain), painterly (strength, seed, radius, stroke, texture, edges, vivid — brush strokes along the form). About 1 s per 1080p image; the same seed paints the same picture; values are clamped and unknown params are warned about. A video is refused (they cannot run per frame): apply to a still or a captured frame. A studio without them refuses with its list of filters.
|
|
5513
5571
|
- SECOND-INPUT (params.map = another item's id, resolved to its pixels): displace (amount, dispersion, map, mapChannel — the map's brightness pushes pixels), refract (displace with per-channel dispersion — glass), trackMatte (channel, invert, strength — prefer pinepaper_media apply_track_matte for the live version), datamosh (amount, block, map? — self-moshes without a map)
|
|
5514
5572
|
|
|
5515
5573
|
RECIPE — grunge poster: chain [grain, scanlines, vignette]. Glass header: refract with map = a gradient item.
|
|
@@ -6506,7 +6564,7 @@ EXAMPLES:
|
|
|
6506
6564
|
- Grid of icons: {layoutType: "grid", options: {columns: 4, cellWidth: 120}}
|
|
6507
6565
|
|
|
6508
6566
|
PARTIAL LAYOUT:
|
|
6509
|
-
Pass itemIds array to only layout specific items, leaving others in place.`,
|
|
6567
|
+
Pass itemIds array to only layout specific items, leaving others in place. They are CANVAS ids (item_N) — after pinepaper_import_mermaid, use its nodeItemIds, not the mermaid ids (A, B…), which lay out nothing.`,
|
|
6510
6568
|
inputSchema: {
|
|
6511
6569
|
type: 'object',
|
|
6512
6570
|
properties: {
|
|
@@ -6518,7 +6576,7 @@ Pass itemIds array to only layout specific items, leaving others in place.`,
|
|
|
6518
6576
|
itemIds: {
|
|
6519
6577
|
type: 'array',
|
|
6520
6578
|
items: { type: 'string' },
|
|
6521
|
-
description: '
|
|
6579
|
+
description: 'Canvas item ids (item_N) to layout (default: all diagram items). After import_mermaid, its nodeItemIds.',
|
|
6522
6580
|
},
|
|
6523
6581
|
options: {
|
|
6524
6582
|
type: 'object',
|
|
@@ -7396,6 +7454,8 @@ USE WHEN:
|
|
|
7396
7454
|
},
|
|
7397
7455
|
description: `Apply a visual effect to an item.
|
|
7398
7456
|
|
|
7457
|
+
EFFECT OR EMITTER: apply_effect is a live look on an item. For particles a saved scene, a template, the cloud render and every export must reproduce frame for frame — confetti at 2 s, a trail behind a moving item — use pinepaper_emitter: its particles are a pure function of its spec and the scene time.
|
|
7458
|
+
|
|
7399
7459
|
USE WHEN:
|
|
7400
7460
|
- Adding sparkle/glitter effects
|
|
7401
7461
|
- Creating burst/explosion, fire, smoke effects
|
|
@@ -7708,6 +7768,205 @@ EXAMPLE: { style: 'ink', duration: 6 }`,
|
|
|
7708
7768
|
},
|
|
7709
7769
|
},
|
|
7710
7770
|
},
|
|
7771
|
+
{
|
|
7772
|
+
name: 'pinepaper_look',
|
|
7773
|
+
annotations: { title: 'Look', readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: false },
|
|
7774
|
+
description: `Restyle what is already drawn — one item, a group and everything in it, or the WHOLE SCENE — as a named look: palette remapped in place (colour keyframes too), strokes, type, image treatment, texture, background and a framing device. Ids, keyframes and relations are kept; it survives a project round trip; remove restores it pixel for pixel. This is "the same subject, in style X".
|
|
7775
|
+
|
|
7776
|
+
ACTIONS:
|
|
7777
|
+
- list: every look with its FIDELITY — the engine's own grade: native (the medium itself), faithful (close, its approximations named), impression (an evocation, not the real style).
|
|
7778
|
+
- describe: { look } — the recipe, its fidelity, what it approximates, and the engine call per part. Read it before promising a look.
|
|
7779
|
+
- apply: { look, target? ('scene' default | an itemId), scope? ('item' | 'subtree' | 'scene') } → what it restyled, and the fidelity. An impression comes with a warning — present it as an approximation, not the finished style; a faithful look lists what it approximates.
|
|
7780
|
+
- remove: { target } — restore what was there. get: { target } — the look on it now.
|
|
7781
|
+
- grid: { looks?, cols?, cellWidth?, t? } — a contact sheet of the scene in several looks, to choose from: the PNG is the reply's \`data\` (a data URL, as agent_export returns it), with cells [{ id, name, fidelity }].
|
|
7782
|
+
|
|
7783
|
+
look is an id from list, or a look spec. An unknown look is refused with the known ones.
|
|
7784
|
+
Looks act on what is THERE: they restyle a drawing, they do not redraw a subject from scratch in another medium.`,
|
|
7785
|
+
inputSchema: {
|
|
7786
|
+
type: 'object',
|
|
7787
|
+
properties: {
|
|
7788
|
+
action: { type: 'string', enum: ['list', 'describe', 'apply', 'remove', 'get', 'grid'] },
|
|
7789
|
+
look: { description: 'a look id, or a look spec', oneOf: [{ type: 'string' }, { type: 'object', additionalProperties: true }] },
|
|
7790
|
+
target: { type: 'string', description: "an itemId, or 'scene' (default)" },
|
|
7791
|
+
scope: { type: 'string', enum: ['item', 'subtree', 'scene'] },
|
|
7792
|
+
looks: { type: 'array', items: { type: 'string' } },
|
|
7793
|
+
cols: { type: 'integer' }, cellWidth: { type: 'number' }, t: { type: 'number' },
|
|
7794
|
+
},
|
|
7795
|
+
required: ['action'],
|
|
7796
|
+
},
|
|
7797
|
+
},
|
|
7798
|
+
{
|
|
7799
|
+
name: 'pinepaper_original_character',
|
|
7800
|
+
annotations: { title: 'Original Character', readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: false },
|
|
7801
|
+
description: `Make an ORIGINAL character from a base rig and a declarative variant — no drawing code, and nothing anyone else owns. Every variant keeps its base's parts and rig, so expressions, walks, poses and pinepaper_choreograph (which drives its root) all work on it.
|
|
7802
|
+
|
|
7803
|
+
ACTIONS:
|
|
7804
|
+
- bases: the bases (person, robot, cat, bird, blob) with their roles.
|
|
7805
|
+
- describe: { base? } — every legal palette key, feature value, accessory (and its slot), proportion range and look. READ IT FIRST: a value it does not list is refused by name and nothing is drawn.
|
|
7806
|
+
- random: { base, seed, fixed? } — a distinct, valid variant; the same seed gives the same one. fixed is shared by every member (a look, proportions) while each draws its own signature — a cast of 12 is twelve seeds with one fixed.
|
|
7807
|
+
- create: { base, variant?: { palette, features, look, seed, name }, at: { x, y }, height? (320) | scale?, rig? (true) } → itemId (the root), rigId, parts { role: id }. y is the FEET.
|
|
7808
|
+
|
|
7809
|
+
FEATURES: hair, eyes, eyeColor, nose, mouth, ears, brows, accessories (12 slots, one per slot), proportions { headScale, bodyScale, limbLength }.
|
|
7810
|
+
LOOKS on a rig: flat, ink, charcoal, paper-cutout, pixel. watercolor / oil / hatch are refused with the reason.
|
|
7811
|
+
|
|
7812
|
+
INTERACTION (pinepaper_add_relation, source = the character's itemId):
|
|
7813
|
+
- looks_at → an item id, or target 'cursor': the face follows it.
|
|
7814
|
+
- reacts_to → an event or another character; params reaction (hop | jolt | shake | nod | an expression), after, duration, amount.
|
|
7815
|
+
- drag_to_turn (no target): dragging turns the head; params max, sensitivity, turn (keyframeable), spring.
|
|
7816
|
+
- a sound on the reaction: on_event_play_sound on the same event.
|
|
7817
|
+
|
|
7818
|
+
EXAMPLE: { action: 'create', base: 'person', at: { x: 480, y: 900 }, variant: { palette: { skin: '#e8b48a', hair: '#2b1d16', outfit: '#3a7bd5', accent: '#f2c14e' }, features: { hair: 'bun', eyes: 'almond', mouth: 'smile', accessories: ['cape'] }, look: 'ink', name: 'Mira' } }`,
|
|
7819
|
+
inputSchema: {
|
|
7820
|
+
type: 'object',
|
|
7821
|
+
properties: {
|
|
7822
|
+
action: { type: 'string', enum: ['bases', 'describe', 'random', 'create'] },
|
|
7823
|
+
base: { type: 'string' }, variant: { type: 'object', additionalProperties: true },
|
|
7824
|
+
seed: { type: 'integer' }, fixed: { type: 'object', additionalProperties: true },
|
|
7825
|
+
at: { type: 'object', properties: { x: { type: 'number' }, y: { type: 'number' } } },
|
|
7826
|
+
height: { type: 'number' }, scale: { type: 'number' }, rig: { type: 'boolean' },
|
|
7827
|
+
},
|
|
7828
|
+
required: ['action'],
|
|
7829
|
+
},
|
|
7830
|
+
},
|
|
7831
|
+
{
|
|
7832
|
+
name: 'pinepaper_morph_sequence',
|
|
7833
|
+
annotations: { title: 'Morph Sequence', readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: false },
|
|
7834
|
+
description: `ONE element through many states, with no cuts: each state grows out of the last (a pill becomes an input field becomes a dot becomes a card). The one-take UI-launch idiom, from one call.
|
|
7835
|
+
|
|
7836
|
+
{ itemId, states: [{ at, duration? (0.8), to: itemId | shape: { itemType, position, properties? } }], easing?, camera?, sound? }
|
|
7837
|
+
- Each state is the shape the element morphs INTO, starting at \`at\` seconds. Name an existing item (to) or describe one (shape); either way the reference is hidden and the element keeps its own id throughout. States run one after another; an overlap is refused.
|
|
7838
|
+
- easing: linear | easeIn | easeOut | easeInOut (default easeInOut) — the four the morph supports.
|
|
7839
|
+
- camera: true (or { fill, easing }) keys the camera on the SAME timing: it holds while a state rests and moves with each morph, framing the new state to \`fill\` of the frame (default 0.45).
|
|
7840
|
+
- sound: true puts a whoosh at each morph start (or name any catalogue sound).
|
|
7841
|
+
|
|
7842
|
+
Shapes morph by kind: path → path point by point, circle → circle by radius, text → text by font, across kinds by a particle transition. Colours and size morph too.
|
|
7843
|
+
|
|
7844
|
+
RETURNS: states [{ at, duration, targetId }], end (seconds), camera { keyframes }, sounds.
|
|
7845
|
+
|
|
7846
|
+
EXAMPLE — pill → field → dot:
|
|
7847
|
+
{ itemId: "item_1", camera: true, sound: true, states: [
|
|
7848
|
+
{ at: 1, shape: { itemType: "rectangle", position: { x: 960, y: 540 }, properties: { width: 640, height: 88, cornerRadius: 44, color: "#ffffff" } } },
|
|
7849
|
+
{ at: 3, shape: { itemType: "circle", position: { x: 960, y: 540 }, properties: { radius: 18, color: "#111111" } } } ] }`,
|
|
7850
|
+
inputSchema: {
|
|
7851
|
+
type: 'object',
|
|
7852
|
+
properties: {
|
|
7853
|
+
itemId: { type: 'string' },
|
|
7854
|
+
states: { type: 'array', items: { type: 'object', properties: { at: { type: 'number' }, duration: { type: 'number' }, to: { type: 'string' }, shape: { type: 'object', additionalProperties: true } }, required: ['at'] } },
|
|
7855
|
+
easing: { type: 'string', enum: ['linear', 'easeIn', 'easeOut', 'easeInOut'] },
|
|
7856
|
+
camera: { description: 'true, or {fill, easing}', oneOf: [{ type: 'boolean' }, { type: 'object', additionalProperties: true }] },
|
|
7857
|
+
sound: { description: 'true, or a catalogue sound name', oneOf: [{ type: 'boolean' }, { type: 'string' }] },
|
|
7858
|
+
},
|
|
7859
|
+
required: ['itemId', 'states'],
|
|
7860
|
+
},
|
|
7861
|
+
},
|
|
7862
|
+
{
|
|
7863
|
+
name: 'pinepaper_emitter',
|
|
7864
|
+
annotations: { title: 'Particle Emitter', readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: false },
|
|
7865
|
+
description: `Particles as an ITEM whose every frame is a pure function of its spec and the scene time — so the preview, capture_frames, every export, a saved project, a template and the cloud render all draw the same particles, scrubbing backwards included. The serialisable, cloud-safe choice; pinepaper_apply_effect is a live look on an item.
|
|
7866
|
+
|
|
7867
|
+
ACTIONS:
|
|
7868
|
+
- create: { spec } → itemId
|
|
7869
|
+
- set: { itemId, spec } — merge a partial spec onto the emitter's.
|
|
7870
|
+
|
|
7871
|
+
SPEC:
|
|
7872
|
+
- mode: 'burst' (default) — bursts: [{ t, x, y, count, …per-burst overrides }]: a pop of particles at scene time t.
|
|
7873
|
+
- mode: 'trail' (or give target) — target (an item id), rate (per second), emitWindows [[t0, t1], …], window, offset: particles shed from a moving item.
|
|
7874
|
+
- look and physics (per emitter or per burst): shape ('circle' | 'rect' | 'dash' | 'star' | 'confetti', or an array), palette [colours], size / sizes / sizeEnd, speed + angle ranges or velocities, gravity (px/s², +down), drag, friction, lifetime, fadeIn / fadeOut, spin, opacity, jitter, seed.
|
|
7875
|
+
An unknown shape, mode or bad range is refused with the engine's reason — never defaulted.
|
|
7876
|
+
|
|
7877
|
+
EXAMPLE — confetti at 2 s:
|
|
7878
|
+
{ action: 'create', spec: { bursts: [{ t: 2, x: 960, y: 400, count: 80 }], shape: 'confetti', palette: ['#f43f5e', '#facc15', '#22d3ee'], speed: [300, 700], angle: [-150, -30], gravity: 900, lifetime: 2.5, seed: 7 } }`,
|
|
7879
|
+
inputSchema: {
|
|
7880
|
+
type: 'object',
|
|
7881
|
+
properties: {
|
|
7882
|
+
action: { type: 'string', enum: ['create', 'set'] },
|
|
7883
|
+
itemId: { type: 'string', description: 'set: the emitter' },
|
|
7884
|
+
spec: { type: 'object', additionalProperties: true, description: 'create: the whole spec; set: the keys to change' },
|
|
7885
|
+
},
|
|
7886
|
+
required: ['action', 'spec'],
|
|
7887
|
+
},
|
|
7888
|
+
},
|
|
7889
|
+
{
|
|
7890
|
+
name: 'pinepaper_render_hook',
|
|
7891
|
+
annotations: { title: 'Render Hook', readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: false },
|
|
7892
|
+
description: `Custom per-frame drawing that a saved scene CARRIES: SOURCE TEXT, compiled and run under the governor's loop guards with seeded Math, saved in the project document, the template and undo, and re-installed on load. (A raw function added with code is not saved — pinepaper_export_scene { full: true } names any such as unserialized.)
|
|
7893
|
+
|
|
7894
|
+
ACTIONS:
|
|
7895
|
+
- register: { id, source, layer? ('above' | 'below'), deterministic? (true), seed? } — source evaluates to (ctx, t, info) => {}: ctx in canvas coordinates, t the scene time in seconds, info { width, height, frame, seed }. 'above' draws over every item, 'below' under them. deterministic reseeds Math.random from (seed, frame) each call, so a frame always draws the same.
|
|
7896
|
+
- unregister: { id } list: the saved hooks.
|
|
7897
|
+
|
|
7898
|
+
Reach for it when no tool draws the look (a scanline overlay, a custom texture pass). For particles, pinepaper_emitter is data rather than code.
|
|
7899
|
+
|
|
7900
|
+
EXAMPLE: { action: 'register', id: 'scanlines', layer: 'above', source: "(ctx, t, info) => { ctx.globalAlpha = 0.08; for (let y = (t * 40) % 4; y < info.height; y += 4) ctx.fillRect(0, y, info.width, 1); }" }`,
|
|
7901
|
+
inputSchema: {
|
|
7902
|
+
type: 'object',
|
|
7903
|
+
properties: {
|
|
7904
|
+
action: { type: 'string', enum: ['register', 'unregister', 'list'] },
|
|
7905
|
+
id: { type: 'string' }, source: { type: 'string' },
|
|
7906
|
+
layer: { type: 'string', enum: ['above', 'below'] },
|
|
7907
|
+
deterministic: { type: 'boolean' }, seed: { type: 'integer' },
|
|
7908
|
+
},
|
|
7909
|
+
required: ['action'],
|
|
7910
|
+
},
|
|
7911
|
+
},
|
|
7912
|
+
{
|
|
7913
|
+
name: 'pinepaper_choreograph',
|
|
7914
|
+
annotations: {
|
|
7915
|
+
title: 'Choreograph an Actor',
|
|
7916
|
+
readOnlyHint: false,
|
|
7917
|
+
destructiveHint: false,
|
|
7918
|
+
idempotentHint: false,
|
|
7919
|
+
openWorldHint: false,
|
|
7920
|
+
},
|
|
7921
|
+
description: `Make any item ACT: a list of beats compiled to one keyframe track with anticipation, squash and stretch, contact and settle — the timing a hand animator would key, from one call.
|
|
7922
|
+
|
|
7923
|
+
BEATS run one after another: [{ at, verb, ...params }]. Positions are the actor's CENTRE in canvas px; a squash keeps its BOTTOM on the ground.
|
|
7924
|
+
- pop: scales up from nothing with an overshoot (an entrance in place).
|
|
7925
|
+
- drop { to? }: falls and lands with a squash. Already in the air (after a fly), it falls from where it is; on the ground or below the landing point, it comes in from above the frame.
|
|
7926
|
+
- hop { to?, height? }: crouch, launch stretched, arc, land squashed, settle. Without to it hops in place.
|
|
7927
|
+
- bounce { times? (3), height?, decay? (0.6), to? }: bounces that lose height; with to it travels while bouncing.
|
|
7928
|
+
- roll { to }: rolls without slipping — it turns by the distance over its radius (right = clockwise).
|
|
7929
|
+
- fly { to, arc? }: an arc through the air, nose up on the rise and down on the fall.
|
|
7930
|
+
- peek { edge (left|right|top|bottom), amount? (0.5), hold? (1) }: slides partly in from a frame edge, waits, ducks back out.
|
|
7931
|
+
- shake { intensity? }: a startled shiver. squash { amount? }: an in-place squash and recover (a reaction, a landing hit).
|
|
7932
|
+
- enter { from (edge), to? }: slides in from an edge with an overshoot. exit { edge }: a small anticipation, then away off that edge.
|
|
7933
|
+
Each verb has a default duration; pass duration to change it.
|
|
7934
|
+
|
|
7935
|
+
WHAT IT RETURNS: keyframes written, the duration, and where the actor ends (and whether that is on screen). Beats that overlap, an unknown verb, or roll / fly without a destination are refused by name.
|
|
7936
|
+
|
|
7937
|
+
ACTORS: a shape, a group, an imported SVG character, a photo cut-out — anything with one transform. Its own scale and rotation are kept (a beat squashes relative to them). A figure placed by pinepaper_character is several parts with their own tracks and no single transform, so choreograph its parts' group only if you grouped a STATIC figure; otherwise direct it with character beats.
|
|
7938
|
+
|
|
7939
|
+
SOUND: sound: true puts a sound on every moment the motion makes — the pop, each launch, every landing (a bounce's landings get quieter as the bounces shrink), a shake — placed on the timeline and baked into the video. sound: { contact: 'kick', whoosh: false, gain: 0.6 } picks or silences them by catalogue name (SFX beep, pop, wind, whoosh, zap; drums kick, snare, tom, hat, clap; or your own from define_sfx). The reply lists the sounds placed. A sound due before 0.06 s is placed at 0.06 s (movedFrom says so): an MP4 encoder swallows the first ~50 ms of audio.
|
|
7940
|
+
|
|
7941
|
+
MIX WITH: pinepaper_character / text expressions on top; pinepaper_apply_effect (confetti, shockwave) at a landing; pinepaper_sound at the same times. Call choreograph BEFORE keyframing the actor's other properties (colour, fill): the beat keys carry position, scale, rotation and opacity only, and the result warns if the actor already animates something else.
|
|
7942
|
+
|
|
7943
|
+
EXAMPLE — a ball comes to life and crosses the frame:
|
|
7944
|
+
{ itemId: "item_1", beats: [ { at: 0, verb: "pop" }, { at: 0.6, verb: "bounce", times: 3, to: [700, 820] }, { at: 2.4, verb: "roll", to: [1200, 820] }, { at: 3.5, verb: "fly", to: [1600, 300] } ] }`,
|
|
7945
|
+
inputSchema: {
|
|
7946
|
+
type: 'object',
|
|
7947
|
+
properties: {
|
|
7948
|
+
itemId: { type: 'string', description: 'The actor (any item with one transform).' },
|
|
7949
|
+
sound: { description: "true, or {pop?, whoosh?, contact?, shake? (catalogue name or false), gain? 0..1}: a sound on every pop, launch, landing and shake.", oneOf: [{ type: 'boolean' }, { type: 'object', additionalProperties: true }] },
|
|
7950
|
+
beats: {
|
|
7951
|
+
type: 'array',
|
|
7952
|
+
description: 'Beats in time order: [{at, verb, to?, duration?, height?, times?, decay?, arc?, edge?, from?, amount?, hold?, intensity?}].',
|
|
7953
|
+
items: {
|
|
7954
|
+
type: 'object',
|
|
7955
|
+
properties: {
|
|
7956
|
+
at: { type: 'number' },
|
|
7957
|
+
verb: { type: 'string', enum: ['pop', 'drop', 'hop', 'bounce', 'roll', 'fly', 'peek', 'shake', 'squash', 'enter', 'exit'] },
|
|
7958
|
+
to: { description: '[x, y] or {x, y}: the actor centre at the end of the beat' },
|
|
7959
|
+
duration: { type: 'number' }, height: { type: 'number' }, times: { type: 'integer' }, decay: { type: 'number' },
|
|
7960
|
+
arc: { type: 'number' }, edge: { type: 'string', enum: ['left', 'right', 'top', 'bottom'] }, from: { type: 'string', enum: ['left', 'right', 'top', 'bottom'] },
|
|
7961
|
+
amount: { type: 'number' }, hold: { type: 'number' }, intensity: { type: 'number' },
|
|
7962
|
+
},
|
|
7963
|
+
required: ['at', 'verb'],
|
|
7964
|
+
},
|
|
7965
|
+
},
|
|
7966
|
+
},
|
|
7967
|
+
required: ['itemId', 'beats'],
|
|
7968
|
+
},
|
|
7969
|
+
},
|
|
7711
7970
|
{
|
|
7712
7971
|
name: 'pinepaper_relight',
|
|
7713
7972
|
annotations: {
|
|
@@ -8104,7 +8363,7 @@ PRIVACY: No screenshots, no tool call arguments, no user content — only struct
|
|
|
8104
8363
|
|
|
8105
8364
|
⚠️ Call ONCE per pipeline. NEVER restart — creates duplicates.
|
|
8106
8365
|
|
|
8107
|
-
WORKFLOW: start_job →
|
|
8366
|
+
WORKFLOW: start_job → the craft tool(s) that fit the brief (styled_scene, story, character, text_style, compose, design_medium…) → batch_execute for the primitive glue, in ONE call → end_job (screenshot) → show user → iterate if needed. Primitive shapes over a generator backdrop is the stock look; use it only when no higher-level tool fits.
|
|
8108
8367
|
|
|
8109
8368
|
RETURNS: canvasSize {width, height} — use this to position items within bounds. Without a canvasPreset, an unbounded canvas is fixed at that size, so stills and video both export it (the result says so in note). Also returns ontology: a pp: triples + item summary snapshot of the (typically empty) canvas. Reuse this baseline across the same agent turn instead of calling pinepaper_get_canvas_ontology unless you've mutated the canvas. When clearCanvas is false, the ontology captures whatever's already on the canvas.
|
|
8110
8369
|
|
|
@@ -8257,7 +8516,7 @@ EXAMPLES:
|
|
|
8257
8516
|
idempotentHint: false,
|
|
8258
8517
|
openWorldHint: false,
|
|
8259
8518
|
},
|
|
8260
|
-
description: `Execute
|
|
8519
|
+
description: `Execute the primitive operations of a scene in a single call — canvas setup, backgrounds, items, animations, masks, effects, and playback. It is the GLUE: a styled scene, a character, a story or a crafted title has its own tool (styled_scene, character, story, text_style), called first.
|
|
8261
8520
|
|
|
8262
8521
|
NOTE: For diagrams (flowcharts, UML), use pinepaper_create_diagram_shape + pinepaper_connect instead.
|
|
8263
8522
|
|
|
@@ -8268,7 +8527,7 @@ NOTE: For diagrams (flowcharts, UML), use pinepaper_create_diagram_shape + pinep
|
|
|
8268
8527
|
ONTOLOGY PREFLIGHT: Before code generation, this tool validates itemType, relationType, effectType, and generatorName against the canonical PinePaper vocabulary. A typo (e.g. "circel") returns a structured VALIDATION_ERROR with the operation index, the offending field, the canonical valid list, and a suggested fix — fix and retry rather than guessing. Pass skipValidation: true to bypass when intentionally using experimental vocabulary.
|
|
8269
8528
|
|
|
8270
8529
|
WORKFLOW:
|
|
8271
|
-
1. pinepaper_agent_start_job → 2.
|
|
8530
|
+
1. pinepaper_agent_start_job → 2. the craft tools that fit the brief (styled_scene, story, character, text_style, compose…) → 3. pinepaper_agent_batch_execute (the primitive glue, in one call) → 4. pinepaper_agent_end_job (screenshot for validation)
|
|
8272
8531
|
After validation: user reviews screenshot → feedback → modify/recreate as needed.
|
|
8273
8532
|
|
|
8274
8533
|
OPERATION TYPES (${AgentBatchOperationTypeSchema.options.length}) — use in this order:
|