@pinepaper.studio/mcp-server 1.6.18 → 1.6.19
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 +97 -10
- package/README.pt-BR.md +1 -1
- package/README.zh-CN.md +1 -1
- package/dist/agent/export-manager.js +2 -2
- package/dist/agent/session-manager.d.ts +8 -0
- package/dist/agent/session-manager.d.ts.map +1 -1
- package/dist/agent/session-manager.js +17 -2
- package/dist/agent/session-manager.js.map +1 -1
- package/dist/assets/asset-manager.d.ts +28 -1
- package/dist/assets/asset-manager.d.ts.map +1 -1
- package/dist/assets/asset-manager.js +65 -25
- package/dist/assets/asset-manager.js.map +1 -1
- package/dist/assets/index.d.ts +1 -3
- package/dist/assets/index.d.ts.map +1 -1
- package/dist/assets/index.js +1 -3
- package/dist/assets/index.js.map +1 -1
- package/dist/assets/repositories/iconify.js +1 -1
- package/dist/assets/repositories/iconify.js.map +1 -1
- package/dist/assets/repositories/openclipart.js +1 -1
- package/dist/assets/repositories/openclipart.js.map +1 -1
- package/dist/assets/repositories/svgrepo.js +2 -2
- package/dist/assets/repositories/svgrepo.js.map +1 -1
- package/dist/assets/types.d.ts +2 -2
- package/dist/assets/types.d.ts.map +1 -1
- package/dist/browser/puppeteer-controller.d.ts +25 -0
- package/dist/browser/puppeteer-controller.d.ts.map +1 -1
- package/dist/browser/puppeteer-controller.js +107 -1
- package/dist/browser/puppeteer-controller.js.map +1 -1
- package/dist/build-info.json +2 -2
- package/dist/cli.js +4 -2
- package/dist/cli.js.map +1 -1
- package/dist/design/design-systems.d.ts +2 -0
- package/dist/design/design-systems.d.ts.map +1 -1
- package/dist/design/design-systems.js +2 -0
- package/dist/design/design-systems.js.map +1 -1
- package/dist/execution/canvas-state.d.ts.map +1 -1
- package/dist/execution/canvas-state.js +19 -43
- package/dist/execution/canvas-state.js.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +20 -7
- package/dist/index.js.map +1 -1
- package/dist/ontology/design-graph.js +2 -2
- package/dist/ontology/design-graph.js.map +1 -1
- package/dist/ontology/upstream-vocabulary.d.ts +2 -2
- package/dist/ontology/upstream-vocabulary.js +2 -2
- package/dist/ontology/validator.js +1 -1
- package/dist/ontology/validator.js.map +1 -1
- package/dist/tools/compact-descriptions.d.ts.map +1 -1
- package/dist/tools/compact-descriptions.js +15 -14
- 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 +422 -126
- package/dist/tools/definitions.js.map +1 -1
- package/dist/tools/engine-lists.d.ts +17 -2
- package/dist/tools/engine-lists.d.ts.map +1 -1
- package/dist/tools/engine-lists.js +102 -2
- 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 +14 -1
- 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 +49 -8
- package/dist/tools/engine-surface.js.map +1 -1
- package/dist/tools/handlers/camera.js +8 -8
- package/dist/tools/handlers/camera.js.map +1 -1
- package/dist/tools/handlers/export.d.ts.map +1 -1
- package/dist/tools/handlers/export.js +77 -5
- package/dist/tools/handlers/export.js.map +1 -1
- package/dist/tools/handlers/font.js +10 -10
- package/dist/tools/handlers/font.js.map +1 -1
- package/dist/tools/handlers/generate.d.ts +12 -12
- package/dist/tools/handlers/maps.d.ts.map +1 -1
- package/dist/tools/handlers/maps.js +23 -3
- package/dist/tools/handlers/maps.js.map +1 -1
- package/dist/tools/handlers.d.ts +21 -0
- package/dist/tools/handlers.d.ts.map +1 -1
- package/dist/tools/handlers.js +240 -37
- package/dist/tools/handlers.js.map +1 -1
- package/dist/tools/minimal-descriptions.d.ts.map +1 -1
- package/dist/tools/minimal-descriptions.js +32 -25
- 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 +5 -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 +5 -0
- package/dist/tools/toolkits.js.map +1 -1
- package/dist/types/code-generator.d.ts +57 -3
- package/dist/types/code-generator.d.ts.map +1 -1
- package/dist/types/code-generator.js +1007 -253
- package/dist/types/code-generator.js.map +1 -1
- package/dist/types/schemas.d.ts +1842 -890
- package/dist/types/schemas.d.ts.map +1 -1
- package/dist/types/schemas.js +229 -51
- package/dist/types/schemas.js.map +1 -1
- package/manifest.json +22 -2
- package/package.json +1 -1
package/dist/types/schemas.js
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
* 3. TypeScript type inference
|
|
9
9
|
*/
|
|
10
10
|
import { z } from 'zod';
|
|
11
|
-
import { ENGINE_EASING_NAMES, DESIGN_MEDIA, DESIGN_MEDIA_APPLY } from '../tools/engine-lists.js';
|
|
11
|
+
import { ENGINE_EASING_NAMES, DESIGN_MEDIA, DESIGN_MEDIA_APPLY, FILTER_TYPES, LINEAGE_KINDS, STYLED_SCENE_STYLES } from '../tools/engine-lists.js';
|
|
12
12
|
// =============================================================================
|
|
13
13
|
// COMMON SCHEMAS
|
|
14
14
|
// =============================================================================
|
|
@@ -1105,22 +1105,10 @@ export const BlastParamsSchema = z.object({
|
|
|
1105
1105
|
// 'saturate' is what the published JSON schema offered for releases, while
|
|
1106
1106
|
// the engine registers 'saturation' and this enum rejected 'saturate' — a
|
|
1107
1107
|
// caller who followed the docs got a validation error. Accepted and mapped.
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
'brightness',
|
|
1113
|
-
'contrast',
|
|
1114
|
-
'saturation',
|
|
1115
|
-
'invert',
|
|
1116
|
-
'noise',
|
|
1117
|
-
'vignette',
|
|
1118
|
-
'vintage',
|
|
1119
|
-
'colorOverlay',
|
|
1120
|
-
'sharpen',
|
|
1121
|
-
'emboss',
|
|
1122
|
-
'posterize',
|
|
1123
|
-
])).describe('Type of visual filter to apply');
|
|
1108
|
+
// GENERATED list (FilterSystem.js registerFilter, scripts/sync-engine-lists.mjs).
|
|
1109
|
+
// The hand copy here hid six of twenty: dither, halftoneCMYK, halftoneDots,
|
|
1110
|
+
// edgeDetect, hsl and colorTint. 'saturate' stays accepted as 'saturation'.
|
|
1111
|
+
export const FilterTypeSchema = z.preprocess((v) => (v === 'saturate' ? 'saturation' : v), z.enum(FILTER_TYPES)).describe('Type of visual filter to apply');
|
|
1124
1112
|
// =============================================================================
|
|
1125
1113
|
// TOOL INPUT SCHEMAS
|
|
1126
1114
|
// =============================================================================
|
|
@@ -1441,9 +1429,12 @@ export const SetCanvasSizeInputSchema = z.object({
|
|
|
1441
1429
|
// not manage it.
|
|
1442
1430
|
// The refusal NAMES the route: a 728x90 banner refused with a bare "too
|
|
1443
1431
|
// small" left a caller to export the preset instead (round 8 BB, 1.48).
|
|
1444
|
-
width: z.number().min(100, "a canvas side under 100 px is not supported. For small assets (a 728x90 or 320x50 banner, a 28 px emote) design at 2-4x — e.g. 1456x180 — and export with agent_export region {x:0, y:0, width, height, outputWidth:728, outputHeight:90}. For VIDEO at a small size, design at 2x and export with agent_export scale: 0.5.").max(16384).describe('Canvas width (100-16384; above 8192 Safari / iOS may fail)'),
|
|
1445
|
-
height: z.number().min(100, "a canvas side under 100 px is not supported. For small assets (a 728x90 or 320x50 banner, a 28 px emote) design at 2-4x — e.g. 1456x180 — and export with agent_export region {x:0, y:0, width, height, outputWidth:728, outputHeight:90}. For VIDEO at a small size, design at 2x and export with agent_export scale: 0.5.").max(16384).describe('Canvas height (100-16384; above 8192 Safari / iOS may fail)'),
|
|
1446
|
-
preset: z.string().optional().describe('
|
|
1432
|
+
width: z.number().min(100, "a canvas side under 100 px is not supported. For small assets (a 728x90 or 320x50 banner, a 28 px emote) design at 2-4x — e.g. 1456x180 — and export with agent_export region {x:0, y:0, width, height, outputWidth:728, outputHeight:90}. For VIDEO at a small size, design at 2x and export with agent_export scale: 0.5.").max(16384).optional().describe('Canvas width (100-16384; above 8192 Safari / iOS may fail)'),
|
|
1433
|
+
height: z.number().min(100, "a canvas side under 100 px is not supported. For small assets (a 728x90 or 320x50 banner, a 28 px emote) design at 2-4x — e.g. 1456x180 — and export with agent_export region {x:0, y:0, width, height, outputWidth:728, outputHeight:90}. For VIDEO at a small size, design at 2x and export with agent_export scale: 0.5.").max(16384).optional().describe('Canvas height (100-16384; above 8192 Safari / iOS may fail)'),
|
|
1434
|
+
preset: z.string().optional().describe('A named size instead of width/height; an unknown name is refused with the known ones listed.'),
|
|
1435
|
+
}).refine((v) => !!v.preset || (v.width !== undefined && v.height !== undefined), {
|
|
1436
|
+
// {preset} alone was refused for a missing width (1.6.19 gate).
|
|
1437
|
+
message: 'pass width and height, or a preset', path: ['width'],
|
|
1447
1438
|
});
|
|
1448
1439
|
// Export
|
|
1449
1440
|
export const ExportSVGInputSchema = z.object({
|
|
@@ -1521,12 +1512,12 @@ export const SetToolkitInputSchema = z.object({
|
|
|
1521
1512
|
// =============================================================================
|
|
1522
1513
|
export const SearchAssetsInputSchema = z.object({
|
|
1523
1514
|
query: z.string().describe('Search term (e.g., "rocket", "heart", "user icon")'),
|
|
1524
|
-
repository: z.enum(['all', '
|
|
1515
|
+
repository: z.enum(['all', 'iconify', 'fontawesome']).optional().describe('Which repository to search (default: all)'),
|
|
1525
1516
|
limit: z.number().min(1).max(50).optional().describe('Max results to return (default: 10)'),
|
|
1526
1517
|
includeSvgContent: z.boolean().optional().describe('Include actual SVG content for each result (default: false). When true, fetches and returns the SVG string for each asset, enabling AI to display or describe the icons.'),
|
|
1527
1518
|
});
|
|
1528
1519
|
export const ImportAssetInputSchema = z.object({
|
|
1529
|
-
assetId: z.string().optional().describe('Asset ID from search results (e.g., "
|
|
1520
|
+
assetId: z.string().optional().describe('Asset ID from search results (e.g., "iconify_mdi_rocket")'),
|
|
1530
1521
|
url: z.string().optional().describe('Direct URL to SVG (alternative to assetId)'),
|
|
1531
1522
|
position: z.object({
|
|
1532
1523
|
x: z.number(),
|
|
@@ -1738,8 +1729,23 @@ export const CreateDiagramShapeInputSchema = z.object({
|
|
|
1738
1729
|
/**
|
|
1739
1730
|
* Connect items input
|
|
1740
1731
|
*/
|
|
1741
|
-
|
|
1742
|
-
|
|
1732
|
+
// strokeColor / strokeWidth are what a model guesses (Paper's names); they
|
|
1733
|
+
// were stripped and the connector drew in the default colour (gate run 3).
|
|
1734
|
+
export const ConnectInputSchema = z.preprocess((v) => {
|
|
1735
|
+
if (!v || typeof v !== 'object' || Array.isArray(v))
|
|
1736
|
+
return v;
|
|
1737
|
+
const o = { ...v };
|
|
1738
|
+
if (o.lineColor === undefined && o.strokeColor !== undefined) {
|
|
1739
|
+
o.lineColor = o.strokeColor;
|
|
1740
|
+
delete o.strokeColor;
|
|
1741
|
+
}
|
|
1742
|
+
if (o.lineWidth === undefined && o.strokeWidth !== undefined) {
|
|
1743
|
+
o.lineWidth = o.strokeWidth;
|
|
1744
|
+
delete o.strokeWidth;
|
|
1745
|
+
}
|
|
1746
|
+
return o;
|
|
1747
|
+
}, z.object({
|
|
1748
|
+
id: z.string().optional().describe('Requested connector id. The studio may not honour it (the result says idHonoured): always use the connectorId the result returns for update/remove.'),
|
|
1743
1749
|
sourceItemId: z.string().describe('Registry ID of source item'),
|
|
1744
1750
|
targetItemId: z.string().describe('Registry ID of target item'),
|
|
1745
1751
|
routing: ConnectorRoutingSchema.optional().default('orthogonal'),
|
|
@@ -1752,12 +1758,12 @@ export const ConnectInputSchema = z.object({
|
|
|
1752
1758
|
curvature: z.number().min(0.1).max(1.0).optional().default(0.5).describe('Curve intensity for curved routing'),
|
|
1753
1759
|
boltEnabled: z.boolean().optional().default(true).describe('Enable animated bolt effect'),
|
|
1754
1760
|
boltColor: z.string().optional().default('#fbbf24').describe('Bolt animation color'),
|
|
1755
|
-
});
|
|
1761
|
+
}));
|
|
1756
1762
|
/**
|
|
1757
1763
|
* Connect specific ports input
|
|
1758
1764
|
*/
|
|
1759
1765
|
export const ConnectPortsInputSchema = z.object({
|
|
1760
|
-
id: z.string().optional().describe('
|
|
1766
|
+
id: z.string().optional().describe('Requested connector id. The studio may not honour it (the result says idHonoured): always use the connectorId the result returns for update/remove.'),
|
|
1761
1767
|
sourceItemId: z.string().describe('Registry ID of source item'),
|
|
1762
1768
|
sourcePort: PortPositionSchema.describe('Port position on source'),
|
|
1763
1769
|
targetItemId: z.string().describe('Registry ID of target item'),
|
|
@@ -1824,16 +1830,34 @@ export const GetDiagramShapesInputSchema = z.object({
|
|
|
1824
1830
|
/**
|
|
1825
1831
|
* Update connector input
|
|
1826
1832
|
*/
|
|
1833
|
+
// Paper.js's own names are what a model guesses for a connector's style, and
|
|
1834
|
+
// an unknown key was STRIPPED, so {strokeColor} changed nothing and reported
|
|
1835
|
+
// success (gate run 3). The Paper names are mapped; anything else is refused
|
|
1836
|
+
// with the keys that work.
|
|
1837
|
+
const CONNECTOR_STYLE_ALIASES = { strokeColor: 'lineColor', color: 'lineColor', strokeWidth: 'lineWidth', width: 'lineWidth' };
|
|
1838
|
+
const CONNECTOR_STYLE_KEYS = ['lineColor', 'lineWidth', 'headStyle', 'tailStyle', 'routing', 'lineStyle'];
|
|
1827
1839
|
export const UpdateConnectorInputSchema = z.object({
|
|
1828
1840
|
connectorId: z.string().describe('Connector ID to update'),
|
|
1829
|
-
style: z.
|
|
1841
|
+
style: z.preprocess((v) => {
|
|
1842
|
+
if (!v || typeof v !== 'object' || Array.isArray(v))
|
|
1843
|
+
return v;
|
|
1844
|
+
const out = {};
|
|
1845
|
+
for (const [k, val] of Object.entries(v)) {
|
|
1846
|
+
if (k === 'dashArray') {
|
|
1847
|
+
out.lineStyle = Array.isArray(val) && val.length ? 'dashed' : 'solid';
|
|
1848
|
+
continue;
|
|
1849
|
+
}
|
|
1850
|
+
out[CONNECTOR_STYLE_ALIASES[k] ?? k] = val;
|
|
1851
|
+
}
|
|
1852
|
+
return out;
|
|
1853
|
+
}, z.object({
|
|
1830
1854
|
lineColor: z.string().optional(),
|
|
1831
1855
|
lineWidth: z.number().optional(),
|
|
1832
1856
|
headStyle: ArrowHeadStyleSchema.optional(),
|
|
1833
1857
|
tailStyle: ArrowHeadStyleSchema.optional(),
|
|
1834
1858
|
routing: ConnectorRoutingSchema.optional(),
|
|
1835
1859
|
lineStyle: ConnectorLineStyleSchema.optional(),
|
|
1836
|
-
}).optional(),
|
|
1860
|
+
}).strict(`a connector's style takes ${CONNECTOR_STYLE_KEYS.join(', ')} (strokeColor, strokeWidth and dashArray are accepted for lineColor, lineWidth and lineStyle)`)).optional(),
|
|
1837
1861
|
label: z.string().optional().describe('Update connector label'),
|
|
1838
1862
|
labelPosition: z.number().min(0).max(1).optional().describe('Label position along path (0-1)'),
|
|
1839
1863
|
});
|
|
@@ -2039,10 +2063,8 @@ export const AgentBatchOperationSchema = z.object({
|
|
|
2039
2063
|
type: AgentBatchOperationTypeSchema,
|
|
2040
2064
|
// Create operation fields
|
|
2041
2065
|
itemType: z.string().optional().describe('Item type for create operations'),
|
|
2042
|
-
|
|
2043
|
-
|
|
2044
|
-
y: z.number(),
|
|
2045
|
-
}).optional().describe('Position for create operations'),
|
|
2066
|
+
// PositionSchema, as create_item takes: [x, y] was refused here (1.6.19 gate).
|
|
2067
|
+
position: PositionSchema.optional().describe('Position for create operations: {x, y} or [x, y]'),
|
|
2046
2068
|
properties: z.record(z.unknown()).optional().describe('Properties for create/modify operations'),
|
|
2047
2069
|
// Modify/Animate/Delete/Keyframe/Mask/Effect target
|
|
2048
2070
|
itemId: z.string().optional().describe('Target item ID or $N reference'),
|
|
@@ -2171,6 +2193,19 @@ export const GIF_MAX_DURATION_S = 15;
|
|
|
2171
2193
|
* out-of-memory — it turns into a message naming the ceiling and what to do.
|
|
2172
2194
|
*/
|
|
2173
2195
|
export const VIDEO_MAX_DURATION_S = 600;
|
|
2196
|
+
/**
|
|
2197
|
+
* pinepaper_styled_scene (FxTool K2): one declarative composition drawn in a
|
|
2198
|
+
* built-in style, as ONE canvas item that redraws itself every exported frame.
|
|
2199
|
+
* The styles are GENERATED (STYLED_SCENE_STYLES); the engine also resolves its
|
|
2200
|
+
* own aliases ('watercolour', 'papercut'), so style is a string here and an
|
|
2201
|
+
* unknown one is refused by the engine with the known list.
|
|
2202
|
+
*/
|
|
2203
|
+
export const StyledSceneInputSchema = z.object({
|
|
2204
|
+
style: z.string().optional().describe(`The look: ${STYLED_SCENE_STYLES.join(' | ')} (default watercolor). The engine also takes its aliases (watercolour, papercut, 1bit…).`),
|
|
2205
|
+
duration: z.number().positive().max(VIDEO_MAX_DURATION_S).optional().describe('Seconds the scene runs (default the composition\'s, 8). Export for this long.'),
|
|
2206
|
+
id: z.string().optional().describe('Scene id (default "styled-scene"). Calling again with the same id REPLACES that scene, e.g. to change style.'),
|
|
2207
|
+
spec: z.record(z.string(), z.unknown()).optional().describe("The composition, every key optional (omitted keys take the 'valley' preset): preset, size [W, H], duration, transition {name, start, length}, camera {zoom: [from, to], pan}, palette, sun, clouds, ridges, foreground, river, settlements, structure, pylons, vegetation, effects {steam, ripples, scars}, hud {label}."),
|
|
2208
|
+
});
|
|
2174
2209
|
/**
|
|
2175
2210
|
* Smart export input schema
|
|
2176
2211
|
*/
|
|
@@ -2591,6 +2626,7 @@ export const HighlightRegionsInputSchema = z.object({
|
|
|
2591
2626
|
strokeColor: z.string().optional().describe('Highlight stroke color'),
|
|
2592
2627
|
stroke: z.string().optional().describe("The engine's own name for the stroke."),
|
|
2593
2628
|
strokeWidth: z.number().optional().describe('Highlight stroke width'),
|
|
2629
|
+
opacity: z.number().min(0).max(1).optional().describe('0..1: a TINT over the land. The colour is pre-blended over the region\'s land fill and drawn opaque, so the export shows exactly the fill reported. Hex colours only.'),
|
|
2594
2630
|
animate: z.boolean().optional().describe('Animate the highlight'),
|
|
2595
2631
|
}).optional().describe('Highlight options'),
|
|
2596
2632
|
}).describe('Highlight regions input');
|
|
@@ -2656,12 +2692,24 @@ export const GetRegionAtPointInputSchema = z.object({
|
|
|
2656
2692
|
y: z.number().describe('Canvas Y coordinate'),
|
|
2657
2693
|
}).describe('Get region at point input');
|
|
2658
2694
|
// Map Animation Schemas
|
|
2659
|
-
|
|
2695
|
+
// The engine reads fillColor OR color, plus easing (MapSystem.animateRegions);
|
|
2696
|
+
// requiring fillColor refused keyframes written with color (gate D17, 1.6.19).
|
|
2697
|
+
// A keyframe may nest its values under `properties`, the shape every other
|
|
2698
|
+
// keyframe tool takes; it is flattened rather than refused (gate run 2).
|
|
2699
|
+
export const MapRegionKeyframeSchema = z.preprocess((k) => {
|
|
2700
|
+
if (!k || typeof k !== 'object' || Array.isArray(k))
|
|
2701
|
+
return k;
|
|
2702
|
+
const { properties, ...rest } = k;
|
|
2703
|
+
return properties && typeof properties === 'object' && !Array.isArray(properties) ? { ...properties, ...rest } : k;
|
|
2704
|
+
}, z.object({
|
|
2660
2705
|
time: z.number().describe('Time in seconds'),
|
|
2661
|
-
fillColor: z.string().describe('Fill color at this keyframe'),
|
|
2706
|
+
fillColor: z.string().optional().describe('Fill color at this keyframe (or color)'),
|
|
2707
|
+
color: z.string().optional().describe('Same as fillColor'),
|
|
2662
2708
|
strokeColor: z.string().optional().describe('Stroke color (optional)'),
|
|
2663
2709
|
opacity: z.number().optional().describe('Opacity 0-1 (optional)'),
|
|
2664
|
-
|
|
2710
|
+
easing: z.string().optional().describe('Easing into this keyframe'),
|
|
2711
|
+
}).refine((k) => !!(k.fillColor || k.color), { message: 'each keyframe needs fillColor (or color)', path: ['fillColor'] }))
|
|
2712
|
+
.describe('Map region keyframe');
|
|
2665
2713
|
export const WaveDirectionSchema = z.enum(['horizontal', 'vertical', 'radial']).describe('Wave animation direction');
|
|
2666
2714
|
export const AnimateMapRegionsInputSchema = z.object({
|
|
2667
2715
|
duration: z.number().optional().default(5).describe('Total animation duration in seconds'),
|
|
@@ -2671,9 +2719,10 @@ export const AnimateMapRegionsInputSchema = z.object({
|
|
|
2671
2719
|
export const AnimateMapWaveInputSchema = z.object({
|
|
2672
2720
|
duration: z.number().optional().default(10).describe('Total wave duration in seconds'),
|
|
2673
2721
|
loop: z.boolean().optional().default(true).describe('Loop the animation'),
|
|
2674
|
-
colors: z.array(z.string()).optional().describe('
|
|
2722
|
+
colors: z.array(z.string()).optional().describe('Colors the wave cycles through (at least 2)'),
|
|
2675
2723
|
waveDirection: WaveDirectionSchema.optional().default('horizontal').describe('Direction of wave effect'),
|
|
2676
|
-
|
|
2724
|
+
waveSpeed: z.number().positive().optional().describe('Speed of the wave (default 1)'),
|
|
2725
|
+
}).describe('Animate map wave input: the wave runs across ALL regions of the map');
|
|
2677
2726
|
export const StopMapAnimationsInputSchema = z.object({
|
|
2678
2727
|
regions: z.array(z.string()).optional().describe('Specific region IDs to stop (omit for all)'),
|
|
2679
2728
|
resetColors: z.boolean().optional().default(true).describe('Reset regions to default colors'),
|
|
@@ -3135,7 +3184,9 @@ export const CommentInputSchema = z.object({
|
|
|
3135
3184
|
export const ProvenanceInputSchema = z.object({
|
|
3136
3185
|
action: z.enum(['get', 'lineage', 'dependents', 'record']),
|
|
3137
3186
|
itemId: z.string(),
|
|
3138
|
-
|
|
3187
|
+
// GENERATED (LINEAGE_KINDS): the default was 'derived', which the engine
|
|
3188
|
+
// refuses, and the docs named three kinds that do not exist (1.6.19 gate).
|
|
3189
|
+
kind: z.enum(LINEAGE_KINDS).optional().describe('record: how the item came from sourceRef (default derivedFrom).'),
|
|
3139
3190
|
sourceRef: z.string().optional(),
|
|
3140
3191
|
meta: z.record(z.string(), z.unknown()).optional(),
|
|
3141
3192
|
});
|
|
@@ -3539,6 +3590,41 @@ export const ValidateSceneInputSchema = z.object({
|
|
|
3539
3590
|
* deterministic capture; the times come from `times`, or from one of the
|
|
3540
3591
|
* modes below.
|
|
3541
3592
|
*/
|
|
3593
|
+
/**
|
|
3594
|
+
* pinepaper_export_scene / pinepaper_import_scene (D28): a restorable save.
|
|
3595
|
+
* The default export is a summary for inspection; `full` writes the engine's
|
|
3596
|
+
* project document (captureProjectDocument) to a file.
|
|
3597
|
+
*/
|
|
3598
|
+
/**
|
|
3599
|
+
* pinepaper_place_on_surface (D22, FxTool #56): a UI onto a screen in a photo,
|
|
3600
|
+
* corner-pinned, matted and lit, baked into the photo's pixels.
|
|
3601
|
+
*/
|
|
3602
|
+
const PointPair = z.tuple([z.number(), z.number()]);
|
|
3603
|
+
export const PlaceOnSurfaceInputSchema = z.object({
|
|
3604
|
+
photoId: z.string().describe('The photo: an image item (or a group holding one).'),
|
|
3605
|
+
sourceId: z.string().describe('The UI to place: any canvas item or group, or an image item.'),
|
|
3606
|
+
quad: z.tuple([PointPair, PointPair, PointPair, PointPair]).optional().describe('The screen\'s four corners TL, TR, BR, BL. Omit to detect it (the largest bright, neutral region).'),
|
|
3607
|
+
quadSpace: z.enum(['image', 'canvas']).optional().describe("quad's coordinates: 'image' (default) photo pixels, or 'canvas'."),
|
|
3608
|
+
occlusion: z.enum(['luma', 'none']).optional().describe("'luma' (default) keeps a thumb or hand in front of the screen; 'none' covers it."),
|
|
3609
|
+
key: z.number().optional().describe('Brightness above which the photo counts as screen (default: found from the photo).'),
|
|
3610
|
+
erode: z.number().min(0).optional().describe('Pull the matte in from the bezel, px (default 2).'),
|
|
3611
|
+
matteBlur: z.number().min(0).optional().describe('Soften the matte edge (default 0.8).'),
|
|
3612
|
+
soften: z.number().min(0).optional().describe('Soften the UI to the photo\'s focus (default 0.5).'),
|
|
3613
|
+
glare: z.number().min(0).max(1).optional().describe('Glass glare kept over the UI (default 0.10).'),
|
|
3614
|
+
spill: z.number().min(0).max(1).optional().describe('Screen light spilling onto the surroundings (default 0.35).'),
|
|
3615
|
+
spillRadius: z.number().min(0).optional().describe('Spill reach, px (default 40).'),
|
|
3616
|
+
tint: z.tuple([z.number(), z.number(), z.number()]).optional().describe('Multiply the UI by [r, g, b], 0..1, to match the photo\'s white balance.'),
|
|
3617
|
+
slot: z.string().optional().describe("Name for this screen (default 'screen'). Placing again in the same slot REPLACES it; several screens in one photo use different slots."),
|
|
3618
|
+
hideSource: z.boolean().optional().describe('Hide the UI item after placing it (default true).'),
|
|
3619
|
+
});
|
|
3620
|
+
export const ExportSceneInputSchema = z.object({
|
|
3621
|
+
full: z.boolean().optional().describe('Save a RESTORABLE project document to a file (keyframes, relations, rigging, scene chains), not the summary. Restore it with pinepaper_import_scene.'),
|
|
3622
|
+
name: z.string().optional().describe('full: a name recorded in the document.'),
|
|
3623
|
+
});
|
|
3624
|
+
export const ImportSceneInputSchema = z.object({
|
|
3625
|
+
path: z.string().min(1).describe('The project document a full pinepaper_export_scene saved (absolute path, or relative to the server working directory).'),
|
|
3626
|
+
strict: z.boolean().optional().describe('Refuse a document with validation problems (default true). false loads anyway and returns the problems as warnings.'),
|
|
3627
|
+
});
|
|
3542
3628
|
export const CaptureSheetSchema = z.object({
|
|
3543
3629
|
every: z.number().positive().optional().describe('One frame every N seconds from 0 to duration (needs duration).'),
|
|
3544
3630
|
duration: z.number().positive().optional().describe('Scene length in seconds, for every and loopSeam.'),
|
|
@@ -3571,7 +3657,7 @@ export const InstantiateOntologyInputSchema = z.object({
|
|
|
3571
3657
|
canvas: z.object({
|
|
3572
3658
|
width: z.number().positive(),
|
|
3573
3659
|
height: z.number().positive(),
|
|
3574
|
-
}).optional().describe('Canvas size
|
|
3660
|
+
}).optional().describe('Canvas size to lay out for (default: the live canvas).'),
|
|
3575
3661
|
defaultGeometry: z.record(z.string(), z.object({
|
|
3576
3662
|
width: z.number(),
|
|
3577
3663
|
height: z.number(),
|
|
@@ -3684,7 +3770,26 @@ export const TextStyleInputSchema = z.object({
|
|
|
3684
3770
|
scale: z.number().optional().describe('Size multiplier (default 1).'),
|
|
3685
3771
|
strokeColor: z.string().optional().describe("Ink colour (default '#ffffff')."),
|
|
3686
3772
|
strokeWidth: z.number().optional().describe('Pen width (default 2).'),
|
|
3687
|
-
|
|
3773
|
+
nib: z.union([
|
|
3774
|
+
z.boolean(),
|
|
3775
|
+
z.enum(['monoline', 'broad']),
|
|
3776
|
+
z.object({
|
|
3777
|
+
angle: z.number().optional().describe('Nib angle in degrees.'),
|
|
3778
|
+
width: z.number().positive().optional().describe('Widest stroke, in px.'),
|
|
3779
|
+
contrast: z.number().min(0).max(1).optional().describe('0..1; the hairline is width × (1 − contrast).'),
|
|
3780
|
+
taper: z.number().min(0).max(0.5).optional().describe('0..0.5; thin entry and exit.'),
|
|
3781
|
+
}).strict(),
|
|
3782
|
+
]).optional().describe("The pen. 'monoline' (or false): one even line. 'broad' (or true): a broad nib, thick across it and hairline along it; an object tunes the broad nib. Omitted: the studio's default pen."),
|
|
3783
|
+
// Draw-on (gate D41): the engine keyframes trimEnd 0→1 itself; these were
|
|
3784
|
+
// stripped, so a handwritten title arrived fully drawn.
|
|
3785
|
+
animate: z.boolean().optional().describe('true writes the words on, stroke by stroke, over `duration` seconds — no keyframe_animate needed (default false: drawn at once).'),
|
|
3786
|
+
duration: z.number().positive().optional().describe('animate: seconds to write the whole line (default 2).'),
|
|
3787
|
+
easing: z.enum(ENGINE_EASING_NAMES).optional().describe("animate: the write-on easing (default 'easeOut')."),
|
|
3788
|
+
timeOffset: z.number().min(0).optional().describe('animate: seconds into the timeline before writing starts (default 0).'),
|
|
3789
|
+
singleStroke: z.boolean().optional().describe('Primary strokes only — drop the secondary strokes (default false).'),
|
|
3790
|
+
showGhost: z.boolean().optional().describe('Show a faint outline of the whole line under the write-on (default false).'),
|
|
3791
|
+
tension: z.number().optional().describe("Curve tension of the pen path (the studio's default when omitted)."),
|
|
3792
|
+
}).strict().optional().describe('cursive: where and how it is written. The result is a STROKED PATH, so pinepaper_animate\'s draw-on and pinepaper_path\'s outline_stroke both apply to it — which is the reason to prefer it over a script font.'),
|
|
3688
3793
|
collageOptions: z.record(z.string(), z.unknown()).optional().describe('to_collage: style, palette and the rest, same vocabulary as pinepaper_create_letter_collage.'),
|
|
3689
3794
|
itemId: z.string().optional().describe('Text item id — apply_style / set_font_axes.'),
|
|
3690
3795
|
styleKey: z.string().optional().describe("apply_style: style name from list_styles (e.g. 'stacked', 'arcade' — the pixel/arcade styles suggest their own face)."),
|
|
@@ -3708,7 +3813,13 @@ export const TextStyleInputSchema = z.object({
|
|
|
3708
3813
|
}).passthrough().optional().describe('set_font_axes: weight/width/slant, or OpenType tags (wght/wdth/slnt). Unknown axes are passed to the engine and come back in `rejected` rather than being dropped here. All three named axes are animatable (addKeyframe with fontWeight interpolates).'),
|
|
3709
3814
|
})
|
|
3710
3815
|
.refine((v) => v.action !== 'apply_style' || (!!v.itemId && !!v.styleKey), { message: 'apply_style requires itemId and styleKey', path: ['styleKey'] })
|
|
3711
|
-
.refine((v) => v.action !== 'set_font_axes' || (!!v.itemId && !!v.axes && Object.keys(v.axes).length > 0), { message: 'set_font_axes requires itemId and at least one axis', path: ['axes'] })
|
|
3816
|
+
.refine((v) => v.action !== 'set_font_axes' || (!!v.itemId && !!v.axes && Object.keys(v.axes).length > 0), { message: 'set_font_axes requires itemId and at least one axis', path: ['axes'] })
|
|
3817
|
+
// cursive WRITES new words; with no text it reached the engine and failed as
|
|
3818
|
+
// "Cannot read properties of undefined (reading 'length')" (gate, P2).
|
|
3819
|
+
.refine((v) => v.action !== 'cursive' || (typeof v.text === 'string' && v.text.trim() !== ''), {
|
|
3820
|
+
message: "cursive writes new text from `text`; it does not restyle an existing item. Pass text (the words to write); for a style on an existing text item use apply_style with its itemId.",
|
|
3821
|
+
path: ['text']
|
|
3822
|
+
});
|
|
3712
3823
|
/**
|
|
3713
3824
|
* pinepaper_text_effect — the 37 character-level text effects
|
|
3714
3825
|
* (terminaltexteffects' vocabulary, reimplemented in FxTool from source).
|
|
@@ -3737,9 +3848,9 @@ export const TextStyleInputSchema = z.object({
|
|
|
3737
3848
|
* `list_media` before promising a medium in prose.
|
|
3738
3849
|
*/
|
|
3739
3850
|
export const DesignMediumInputSchema = z.object({
|
|
3740
|
-
action: z.enum(['list_media', 'resolve', 'list_stitches', 'apply_thread', 'apply_hatch', 'list_flow_fields', 'list_hatch_options', 'apply'])
|
|
3851
|
+
action: z.enum(['list_media', 'resolve', 'list_stitches', 'apply_thread', 'apply_hatch', 'list_flow_fields', 'list_hatch_options', 'apply', 'sdf_stroke'])
|
|
3741
3852
|
.describe("'apply' (render an item in ANY medium the engine can make: medium + options — watercolor, oil, cutPaper, thread, hatch) · 'list_media' (every medium with fidelity + limitation) · 'resolve' (can this medium be made here, and how honestly) · 'list_stitches' · 'apply_thread' (render an item in thread) · 'apply_hatch' (rule an item with hatching — value through line density) · 'list_flow_fields' · 'list_hatch_options'"),
|
|
3742
|
-
medium: z.string().optional().describe(`resolve / apply: medium key — ${DESIGN_MEDIA.join(', ')}. apply works for ${Object.keys(DESIGN_MEDIA_APPLY).join(', ')}; the
|
|
3853
|
+
medium: z.string().optional().describe(`resolve / apply: medium key — ${DESIGN_MEDIA.join(', ')}. apply works for ${Object.keys(DESIGN_MEDIA_APPLY).join(', ')}; a medium the studio cannot apply is refused by the engine with the reason. ink and charcoal, where the studio applies them, restyle the item IN PLACE (same id).`),
|
|
3743
3854
|
options: z.record(z.string(), z.unknown()).optional().describe('apply: the medium\'s own options. watercolor: color, brush, water 0..1, opacity, edge 0..1 (the dark rim), angle, bleed, seed, keepSource. oil: color, brush, length, density, toneRange, relief, angle, seed, keepSource. cutPaper: color, facet, jitter, shadow, shadowColor, shadowOpacity, shadowOffset [dx, dy], seed, keepSource. thread / hatch: as apply_thread / apply_hatch.'),
|
|
3744
3855
|
itemId: z.string().optional().describe('apply / apply_thread / apply_hatch: a closed path, compound path (holes kept), or a group of them (applied per path). The result takes the source\'s place in the stacking order and the source is hidden; applying again replaces it. One undo step.'),
|
|
3745
3856
|
stitch: z.enum(THREAD_STITCHES).optional()
|
|
@@ -3756,9 +3867,9 @@ export const DesignMediumInputSchema = z.object({
|
|
|
3756
3867
|
stitchLen: z.number().positive().optional().describe('apply_thread: nominal stitch length px (default 18).'),
|
|
3757
3868
|
rowGap: z.number().positive().optional().describe('apply_thread: row spacing px. Defaults from the thread width so the rows abut; setting it wider is what makes a fill read as hatching.'),
|
|
3758
3869
|
variance: z.number().min(0).max(1).optional().describe('apply_thread: length jitter 0..1 (default 0.35) — the variance IS the long-and-short shading.'),
|
|
3759
|
-
width: z.number().positive().optional().describe('apply_thread: thread width px (default 2).'),
|
|
3870
|
+
width: z.number().positive().optional().describe('apply_thread: thread width px (default 2). sdf_stroke: stroke width px (default 8).'),
|
|
3760
3871
|
sheen: z.boolean().optional().describe('apply_thread: draw the highlight along each stitch (default true) — thread is not matte.'),
|
|
3761
|
-
color: z.string().optional().describe("apply_thread: thread colour, defaulting to the item's own fill."),
|
|
3872
|
+
color: z.string().optional().describe("apply_thread: thread colour, defaulting to the item's own fill. sdf_stroke: stroke colour."),
|
|
3762
3873
|
seed: z.number().int().optional().describe('apply_thread: PRNG seed (default 1). Same seed stitches the same way.'),
|
|
3763
3874
|
count: z.number().int().positive().optional().describe('apply_thread: stitch count for seed/satin.'),
|
|
3764
3875
|
// THE OPTIONS THE ENGINE READS AND NOTHING NAMED. ThreadPainting.paint reads
|
|
@@ -3791,12 +3902,78 @@ export const DesignMediumInputSchema = z.object({
|
|
|
3791
3902
|
flowField: z.enum(['hand', 'curved', 'zigzag', 'waves', 'seabed', 'spiral', 'columns']).optional()
|
|
3792
3903
|
.describe('apply_hatch: bend each line along a flow field. The straight scanline is the ruling; the field is what makes it read as drawn rather than printed. See list_flow_fields.'),
|
|
3793
3904
|
t: z.number().optional().describe('apply_hatch: flow-field time offset — advances the field without changing the seed.'),
|
|
3905
|
+
// --- SDF brush stroke (FxTool D5) ---
|
|
3906
|
+
points: z.array(z.union([
|
|
3907
|
+
z.object({ x: z.number(), y: z.number(), pressure: z.number().min(0).max(1).optional() }),
|
|
3908
|
+
z.tuple([z.number(), z.number()]),
|
|
3909
|
+
z.tuple([z.number(), z.number(), z.number()]),
|
|
3910
|
+
])).min(1).optional().describe('sdf_stroke: the stroke path in canvas px, each {x, y, pressure?} or [x, y, pressure?]. Pressure 0..1 scales the width at that point.'),
|
|
3911
|
+
softness: z.number().min(0).max(1).optional().describe('sdf_stroke: edge softness 0..1 (default 0.2).'),
|
|
3912
|
+
opacity: z.number().min(0).max(1).optional().describe('sdf_stroke: 0..1 (default 1).'),
|
|
3913
|
+
resolution: z.number().positive().optional().describe('sdf_stroke: bitmap pixels per canvas px (default 2).'),
|
|
3914
|
+
name: z.string().optional().describe('sdf_stroke: item name.'),
|
|
3794
3915
|
})
|
|
3795
3916
|
.refine((v) => v.action !== 'apply_thread' || !!v.itemId, { message: 'apply_thread requires itemId', path: ['itemId'] })
|
|
3796
3917
|
.refine((v) => v.action !== 'resolve' || !!v.medium, { message: 'resolve requires medium', path: ['medium'] })
|
|
3918
|
+
.refine((v) => v.action !== 'sdf_stroke' || (Array.isArray(v.points) && v.points.length > 0), { message: 'sdf_stroke requires points', path: ['points'] })
|
|
3797
3919
|
.refine((v) => v.action !== 'apply_hatch' || !!v.itemId, { message: 'apply_hatch requires itemId', path: ['itemId'] })
|
|
3798
3920
|
.refine((v) => v.action !== 'apply' || (!!v.itemId && !!v.medium), { message: 'apply requires itemId and medium', path: ['medium'] })
|
|
3799
3921
|
.refine((v) => v.action !== 'apply' || !v.medium || DESIGN_MEDIA.includes(v.medium), { message: `unknown medium; the engine knows ${DESIGN_MEDIA.join(', ')}`, path: ['medium'] });
|
|
3922
|
+
/**
|
|
3923
|
+
* pinepaper_relight — a lighting pass over the 3D world layer (FxTool D5).
|
|
3924
|
+
* CPU-backed; normals from the world's luminance (no depth). Applied in the
|
|
3925
|
+
* preview and in PNG / PDF / MP4 / WebM; not GIF / APNG; not saved with the
|
|
3926
|
+
* project. Lights are validated by the engine, which names every error.
|
|
3927
|
+
*/
|
|
3928
|
+
const RelightColorSchema = z.union([z.string(), z.tuple([z.number(), z.number(), z.number()])]);
|
|
3929
|
+
export const RelightInputSchema = z.object({
|
|
3930
|
+
action: z.enum(['set', 'get', 'clear', 'list_lights'])
|
|
3931
|
+
.describe("'set' (install or replace the rig) · 'get' (the current rig) · 'clear' (remove it) · 'list_lights' (the light types)"),
|
|
3932
|
+
lights: z.array(z.discriminatedUnion('type', [
|
|
3933
|
+
z.object({
|
|
3934
|
+
type: z.literal('point'),
|
|
3935
|
+
x: z.number(), y: z.number(),
|
|
3936
|
+
z: z.number().optional().describe('Height above the picture, px (default 120).'),
|
|
3937
|
+
radius: z.number().positive().optional().describe('Falloff radius, px (default 400).'),
|
|
3938
|
+
color: RelightColorSchema.optional(),
|
|
3939
|
+
intensity: z.number().min(0).optional().describe('Default 1.'),
|
|
3940
|
+
specular: z.number().min(0).optional().describe('Shininess exponent (default 32).'),
|
|
3941
|
+
}),
|
|
3942
|
+
z.object({
|
|
3943
|
+
type: z.literal('directional'),
|
|
3944
|
+
dir: z.tuple([z.number(), z.number(), z.number()]).describe('[dx, dy, dz]; [0, 0, -1] faces the viewer.'),
|
|
3945
|
+
color: RelightColorSchema.optional(),
|
|
3946
|
+
intensity: z.number().min(0).optional(),
|
|
3947
|
+
}),
|
|
3948
|
+
])).max(8).optional().describe('set: up to 8 lights. Coordinates are export-frame px. Colours are #rrggbb or [r, g, b].'),
|
|
3949
|
+
ambient: z.number().min(0).optional().describe('set: ambient light (default 0.2).'),
|
|
3950
|
+
strength: z.number().positive().optional().describe('set: normal-map strength (default 2).'),
|
|
3951
|
+
enabled: z.boolean().optional().describe('set: false keeps the rig but turns it off.'),
|
|
3952
|
+
preview: z.union([z.boolean(), z.object({ maxSide: z.number().min(64).max(4096) })]).optional()
|
|
3953
|
+
.describe('set: show it in the live preview (capped-resolution overlay); {maxSide} sets the cap.'),
|
|
3954
|
+
}).refine((v) => v.action !== 'set' || (Array.isArray(v.lights) && v.lights.length > 0) || v.enabled === false, { message: 'set requires at least one light (or enabled: false)', path: ['lights'] });
|
|
3955
|
+
/**
|
|
3956
|
+
* pinepaper_shader_graph — validated JSON pixel graphs (FxTool D5), CPU-backed.
|
|
3957
|
+
* Linear chains only; the engine names every error (unknown type, duplicate,
|
|
3958
|
+
* dangling edge, cycle, branching).
|
|
3959
|
+
*/
|
|
3960
|
+
const ShaderGraphJsonSchema = z.object({
|
|
3961
|
+
id: z.string().optional(),
|
|
3962
|
+
nodes: z.array(z.object({ id: z.string(), type: z.string(), params: z.record(z.string(), z.unknown()).optional() })).min(1),
|
|
3963
|
+
edges: z.array(z.object({ from: z.string(), to: z.string() })).optional(),
|
|
3964
|
+
});
|
|
3965
|
+
export const ShaderGraphInputSchema = z.object({
|
|
3966
|
+
action: z.enum(['node_types', 'validate', 'create', 'get', 'list', 'remove', 'apply'])
|
|
3967
|
+
.describe("'node_types' (the node vocabulary + params) · 'validate' (check a graph, store nothing) · 'create' (validate + store) · 'get' / 'remove' (by graphId) · 'list' · 'apply' (run a graph over an item or the scene)"),
|
|
3968
|
+
graph: ShaderGraphJsonSchema.optional().describe('validate / create / apply: {id?, nodes: [{id, type, params?}], edges: [{from, to}]} — a linear chain.'),
|
|
3969
|
+
graphId: z.string().optional().describe('get / remove / apply: a stored graph id.'),
|
|
3970
|
+
target: z.string().optional().describe("apply: an itemId, or 'scene'."),
|
|
3971
|
+
keepSource: z.boolean().optional().describe('apply to an item: keep the source visible (default: hidden).'),
|
|
3972
|
+
asItem: z.boolean().optional().describe("apply to 'scene': add the result as an image item instead of returning it."),
|
|
3973
|
+
})
|
|
3974
|
+
.refine((v) => !['validate', 'create'].includes(v.action) || !!v.graph, { message: 'validate / create require graph', path: ['graph'] })
|
|
3975
|
+
.refine((v) => !['get', 'remove'].includes(v.action) || !!v.graphId, { message: 'get / remove require graphId', path: ['graphId'] })
|
|
3976
|
+
.refine((v) => v.action !== 'apply' || (!!v.target && (!!v.graph || !!v.graphId)), { message: "apply requires target (an itemId or 'scene') and graph or graphId", path: ['target'] });
|
|
3800
3977
|
export const TextEffectInputSchema = z.object({
|
|
3801
3978
|
action: z.enum(['apply', 'list'])
|
|
3802
3979
|
.describe("'apply' (explode a text item into animated characters) · 'list' (the 37 effects with key/label/definition, for a picker)"),
|
|
@@ -3985,7 +4162,7 @@ export const World3DInputSchema = z.object({
|
|
|
3985
4162
|
}).optional().describe("add_material / set_material: a NAMED, SHARED surface referenced by many objects, so one edit restyles all of them. metalness and roughness reach the shader on the MESH path only. There are no aoMapIntensity / normalScale / envMapIntensity knobs: each scales a map that does not exist, and a knob that scales nothing is worse than a missing one."),
|
|
3986
4163
|
materialId: z.string().optional().describe('set_material / remove_material: the material id.'),
|
|
3987
4164
|
// --- Import ---------------------------------------------------------------
|
|
3988
|
-
source: z.string().optional().describe('import_obj: the OBJ file TEXT. import_gltf:
|
|
4165
|
+
source: z.string().optional().describe('import_obj: the OBJ file TEXT. import_gltf: the .gltf JSON TEXT with its buffers embedded. A URL, data: URI or file path is NOT fetched (the string is parsed as JSON), so a .glb cannot be imported here.'),
|
|
3989
4166
|
importOptions: z.record(z.string(), z.unknown()).optional().describe('import_obj / import_gltf: placement and scale options, passed through to the engine.'),
|
|
3990
4167
|
clip: z.string().optional().describe('set_mesh_clip: which imported animation clip a skinned mesh plays.'),
|
|
3991
4168
|
crossfade: z.number().optional().describe('set_mesh_clip: seconds to blend out of the clip that was playing. The blend happens in LOCAL pose space — a palette cannot be blended after the fact.'),
|
|
@@ -4098,7 +4275,7 @@ export const DesignSystemInputSchema = z.object({
|
|
|
4098
4275
|
export const StickInputSchema = z.object({
|
|
4099
4276
|
action: z.enum(['figure', 'set']).describe("'figure' a posed, walking or travelling stick figure · 'set' the floor, wall and objects it stands on and among."),
|
|
4100
4277
|
id: z.string().optional().describe('Prefix for the created items.'),
|
|
4101
|
-
kind: z.string().optional().describe("figure: which figure. set: which piece
|
|
4278
|
+
kind: z.string().optional().describe("figure: which figure. set: which piece — room (floor + wall; options groundY, wall, floor), tabletop (object + surfaceY), chair (facing), table, counter, door, shelf (items), window. An unknown kind or tabletop object is refused with the engine's current list."),
|
|
4102
4279
|
at: z.object({ x: z.number().optional(), y: z.number().optional() }).optional().describe('Where it goes.'),
|
|
4103
4280
|
scale: z.number().optional().describe('Size multiplier.'),
|
|
4104
4281
|
facing: z.enum(['left', 'right']).optional().describe("set: which way a CHAIR faces. The figure has no facing — it is ignored on action 'figure', which refuses it by name rather than dropping it."),
|
|
@@ -4164,7 +4341,7 @@ export const InterchangeInputSchema = z.object({
|
|
|
4164
4341
|
.describe("'export_lottie' (JSON) · 'export_dotlottie' (the zipped .lottie) · 'import_lottie' (a Lottie or .lottie back onto the canvas) · 'export_glb' (the perspective 3D objects — needs some to exist) · 'export_bvh' (a skeleton's motion — needs a rig) · 'export_png_sequence' (one file per frame)."),
|
|
4165
4342
|
options: z.record(z.string(), z.unknown()).optional().describe('Format options, passed through to the exporter: frame range, dimensions, fps, naming.'),
|
|
4166
4343
|
data: z.union([z.string(), z.record(z.string(), z.unknown())]).optional()
|
|
4167
|
-
.describe('import_lottie: the Lottie JSON — an object
|
|
4344
|
+
.describe('import_lottie: the Lottie JSON — an object or a JSON string. A URL or a file path is NOT fetched: read the file and pass its contents.'),
|
|
4168
4345
|
skeletonId: z.string().optional().describe('export_bvh: which skeleton to write. A BVH is one skeleton\'s motion, so this is not optional in practice.'),
|
|
4169
4346
|
})
|
|
4170
4347
|
.refine((v) => v.action !== 'import_lottie' || v.data !== undefined, { message: 'import_lottie requires data', path: ['data'] })
|
|
@@ -4260,7 +4437,7 @@ export const SoundInputSchema = z.object({
|
|
|
4260
4437
|
* pinepaper_motion — the generators' Animation knob, pointed at anything.
|
|
4261
4438
|
*
|
|
4262
4439
|
* The same engine every generator's own animation runs on, reachable for any
|
|
4263
|
-
* group or list of items. Two kinds: a GROUP motion (
|
|
4440
|
+
* group or list of items. Two kinds: a GROUP motion (driftX/Y, swayX/Y, rotate,
|
|
4264
4441
|
* pulse, wave, bounce) moves the target as one; a FIELD motion (ripple,
|
|
4265
4442
|
* breathe, undulate) sweeps a crest through the children from an origin, with
|
|
4266
4443
|
* a chosen waveform. The field kind is the one nothing else here can do.
|
|
@@ -4273,7 +4450,7 @@ export const MotionInputSchema = z.object({
|
|
|
4273
4450
|
action: z.enum(['list', 'apply']).describe("'list' every motion, waveform and origin the engine offers · 'apply' one to a target."),
|
|
4274
4451
|
itemId: z.string().optional().describe('apply: a group or single item to move.'),
|
|
4275
4452
|
itemIds: z.array(z.string()).optional().describe('apply: several items, wrapped in a new group that becomes the motion host. The members keep their own identity and ids.'),
|
|
4276
|
-
motion: z.string().optional().describe("apply: the motion name — a GROUP motion (
|
|
4453
|
+
motion: z.string().optional().describe("apply: the motion name — a GROUP motion (driftX, driftY, swayX, swayY, rotate, pulse, wave, bounce) moves the target as one; a FIELD motion (ripple, breathe, undulate) sweeps a crest through its children. Call 'list' for the engine's own set rather than guessing."),
|
|
4277
4454
|
speed: z.number().optional().describe('apply: cycles per second, roughly. Higher is faster.'),
|
|
4278
4455
|
intensity: z.number().optional().describe('apply: amplitude. 0.15 is the usual default elsewhere in this surface.'),
|
|
4279
4456
|
waveform: z.enum(['sine', 'triangle', 'square', 'sawtooth', 'spike']).optional()
|
|
@@ -4472,7 +4649,8 @@ export const RiggingInputSchema = z.object({
|
|
|
4472
4649
|
duration: z.number().positive().optional().describe('Seconds to traverse the path (default 1) — set_target_path.'),
|
|
4473
4650
|
loop: z.boolean().optional().describe('Cycle the path — set_target_path.'),
|
|
4474
4651
|
})
|
|
4475
|
-
|
|
4652
|
+
// Listing ALL skeletons or pose libraries needs no skeleton (gate D6, 1.6.19).
|
|
4653
|
+
.refine((v) => ['create_skeleton', 'import_bvh', 'import_spine', 'list_skeletons', 'list_pose_libraries'].includes(v.action) || !!v.skeletonId, { message: 'this action requires skeletonId', path: ['skeletonId'] })
|
|
4476
4654
|
.refine((v) => v.action !== 'add_bone' || v.skeletonId != null, { message: 'add_bone requires skeletonId', path: ['skeletonId'] })
|
|
4477
4655
|
.refine((v) => v.action !== 'attach_item' || (!!v.boneId && !!v.itemId), { message: 'attach_item requires boneId and itemId', path: ['boneId'] })
|
|
4478
4656
|
.refine((v) => v.action !== 'create_ik_chain' || (!!v.boneIds && v.boneIds.length >= 2), { message: 'create_ik_chain requires boneIds (≥2)', path: ['boneIds'] })
|