@pinepaper.studio/mcp-server 1.6.10 → 1.6.12
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.md +94 -1
- package/dist/design/design-systems.d.ts +12 -3
- package/dist/design/design-systems.d.ts.map +1 -1
- package/dist/design/design-systems.js +12 -11
- package/dist/design/design-systems.js.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -1
- package/dist/index.js.map +1 -1
- package/dist/tools/compact-descriptions.js +1 -1
- 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 +189 -55
- package/dist/tools/definitions.js.map +1 -1
- package/dist/tools/engine-methods.d.ts.map +1 -1
- package/dist/tools/engine-methods.js +7 -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 +25 -6
- package/dist/tools/engine-surface.js.map +1 -1
- package/dist/tools/handlers.js +9 -0
- package/dist/tools/handlers.js.map +1 -1
- package/dist/tools/minimal-descriptions.js +1 -1
- package/dist/tools/minimal-descriptions.js.map +1 -1
- package/dist/tools/shape-params.d.ts +36 -0
- package/dist/tools/shape-params.d.ts.map +1 -0
- package/dist/tools/shape-params.js +159 -0
- package/dist/tools/shape-params.js.map +1 -0
- package/dist/tools/stick-vocabulary.d.ts +26 -0
- package/dist/tools/stick-vocabulary.d.ts.map +1 -0
- package/dist/tools/stick-vocabulary.js +102 -0
- package/dist/tools/stick-vocabulary.js.map +1 -0
- package/dist/types/code-generator.d.ts +15 -0
- package/dist/types/code-generator.d.ts.map +1 -1
- package/dist/types/code-generator.js +556 -76
- package/dist/types/code-generator.js.map +1 -1
- package/dist/types/schemas.d.ts +97 -26
- package/dist/types/schemas.d.ts.map +1 -1
- package/dist/types/schemas.js +18 -11
- package/dist/types/schemas.js.map +1 -1
- package/dist/vendor/design/design-style.d.ts +3 -1
- package/dist/vendor/design/design-style.d.ts.map +1 -1
- package/dist/vendor/design/design-style.js +37 -2
- package/dist/vendor/design/design-style.js.map +1 -1
- package/dist/vendor/design/design-systems-dtcg.d.ts +9 -0
- package/dist/vendor/design/design-systems-dtcg.d.ts.map +1 -1
- package/dist/vendor/design/design-systems-dtcg.js +53 -1
- package/dist/vendor/design/design-systems-dtcg.js.map +1 -1
- package/dist/vendor/design/device-mockup-generator.d.ts +83 -0
- package/dist/vendor/design/device-mockup-generator.d.ts.map +1 -0
- package/dist/vendor/design/device-mockup-generator.js +634 -0
- package/dist/vendor/design/device-mockup-generator.js.map +1 -0
- package/dist/vendor/design/recursive-subdivision-generator.d.ts +79 -0
- package/dist/vendor/design/recursive-subdivision-generator.d.ts.map +1 -0
- package/dist/vendor/design/recursive-subdivision-generator.js +319 -0
- package/dist/vendor/design/recursive-subdivision-generator.js.map +1 -0
- package/dist/vendor/design/textile-weave-generator.d.ts +140 -0
- package/dist/vendor/design/textile-weave-generator.d.ts.map +1 -0
- package/dist/vendor/design/textile-weave-generator.js +568 -0
- package/dist/vendor/design/textile-weave-generator.js.map +1 -0
- package/manifest.json +1 -1
- package/package.json +8 -2
|
@@ -9,6 +9,8 @@
|
|
|
9
9
|
*/
|
|
10
10
|
import { COMPACT_DESCRIPTIONS } from './compact-descriptions.js';
|
|
11
11
|
import { MINIMAL_DESCRIPTIONS } from './minimal-descriptions.js';
|
|
12
|
+
import { STICK_GAITS, STICK_POSES, STICK_SEQUENCES, STICK_EXPRESSIONS, STICK_PROPS } from './stick-vocabulary.js';
|
|
13
|
+
import { GeneratorNameSchema, ItemTypeSchema } from '../types/schemas.js';
|
|
12
14
|
import { EffectTypeSchema, SimpleAnimationTypeSchema, GEOMETRY_OPERATIONS, THREAD_STITCHES, } from '../types/schemas.js';
|
|
13
15
|
/**
|
|
14
16
|
* Vocabulary lists derived from Zod schemas so tool descriptions stay in
|
|
@@ -75,6 +77,22 @@ Choose based on mood:
|
|
|
75
77
|
Abstract: drawGeometricAbstract, drawFluidFlow, drawNoiseTexture
|
|
76
78
|
Decorative: drawPattern, drawStackedCircles
|
|
77
79
|
|
|
80
|
+
Generators paint the canvas WITHOUT fully registering what they paint — by
|
|
81
|
+
design, so a large procedural field does not cost memory per path. How much is
|
|
82
|
+
registered varies by generator: drawSunsetScene registers 6 of its 27 objects,
|
|
83
|
+
drawSunburst 1 of 18, drawPattern none of 15. So get_items, modify and the
|
|
84
|
+
ontology see a partial view or nothing at all after one runs. Ask
|
|
85
|
+
app.config.currentBackgroundGenerator and generatorParams for what actually
|
|
86
|
+
ran. To go beyond the parameters, write your own generator function — see
|
|
87
|
+
pinepaper_execute_generator.
|
|
88
|
+
|
|
89
|
+
Writing your own also hands you the registration decision, which is what makes
|
|
90
|
+
a thing EDITABLE. app.registerItem(item, type, props) gives an item a registry
|
|
91
|
+
id: the user can select it and change its colour, and tools can modify,
|
|
92
|
+
animate, keyframe and relate it. Without that it is pixels — it exports the
|
|
93
|
+
same and can never be touched again. Register what a person might want to
|
|
94
|
+
change; leave the dense decorative bulk unregistered.
|
|
95
|
+
|
|
78
96
|
─── ITEMS ───
|
|
79
97
|
|
|
80
98
|
Shapes: circle, rectangle, star, ellipse, triangle, polygon, line, arc, path, pentagon, hexagon, diamond, arrow, heart
|
|
@@ -364,13 +382,64 @@ For requests like "draw a witch", "draw a cat face", "draw a person", or any det
|
|
|
364
382
|
- DO NOT attempt pixel-level character drawing with paths
|
|
365
383
|
|
|
366
384
|
ITEM TYPES:
|
|
385
|
+
|
|
386
|
+
EVERY type below also takes an anchor, which says WHICH CORNER your x/y meant.
|
|
387
|
+
Position is the bounding-box CENTRE by default. Anything that computed a layout
|
|
388
|
+
box — a design system, or any CSS-shaped mental model — authored the TOP-LEFT
|
|
389
|
+
instead, and passing those coordinates straight in displaces every item by half
|
|
390
|
+
its own size. anchor: 'top-left' (also top-right, bottom-left, bottom-right,
|
|
391
|
+
center; origin is an alias for the parameter) fixes that without you computing
|
|
392
|
+
bounds you cannot know until the item exists. It is applied after size and
|
|
393
|
+
rotation, so it uses the item's real box.
|
|
394
|
+
|
|
395
|
+
EVERY type below also takes a label, which wraps the item in a labelled group —
|
|
396
|
+
you do not need a second create call and a hand-computed position to caption a
|
|
397
|
+
shape. A string is the short form; the object form places and styles it:
|
|
398
|
+
label: { content: 'Start', position: 'top', offset: [0, 10], fontSize: 14,
|
|
399
|
+
fontFamily: 'Inter, sans-serif', color: '#ffffff', backgroundColor: null }.
|
|
400
|
+
position takes center (default), top, bottom, left, right or a corner. Use
|
|
401
|
+
label.position for placement: it works here today, and where the sibling
|
|
402
|
+
labelPosition spelling is also accepted, label.position wins.
|
|
403
|
+
Labelling a text item gives you TWO text items in the group — the body and the
|
|
404
|
+
label. That is what you want for a caption; it is a surprise if you expected
|
|
405
|
+
the label to replace the content.
|
|
406
|
+
|
|
367
407
|
- text: Text content with font styling (properties: content, fontSize, color, fontFamily)
|
|
368
408
|
- circle: Circular shape (properties: radius, color, strokeColor, strokeWidth)
|
|
369
409
|
- star: Star shape (properties: radius1, radius2, points, color)
|
|
410
|
+
radius1 is the OUTER radius and is what sizes the star; radius or
|
|
411
|
+
width/height size it equally well. radius2 is read ONLY as a ratio to
|
|
412
|
+
radius1 (inner/outer, default 0.4), so radius2 passed WITHOUT radius1 is
|
|
413
|
+
ignored completely and you get the default waist. innerRadiusRatio sets that
|
|
414
|
+
same waist directly and needs no radii at all. points defaults to 5.
|
|
415
|
+
A star is always radially symmetric — given width and height it uses the
|
|
416
|
+
smaller — and the size you give is the radius BOX, the circle the tips
|
|
417
|
+
touch. The visible bounds are never larger than that box and usually
|
|
418
|
+
smaller — they fill it only when points is a multiple of 4.
|
|
370
419
|
- rectangle: Rectangle (properties: width, height, color, cornerRadius)
|
|
371
|
-
- triangle: Triangular shape (properties: color)
|
|
420
|
+
- triangle: Triangular shape (properties: width, height, color, angles, kind)
|
|
421
|
+
Defaults to a 100x86 isosceles. For any OTHER triangle, do not hand-build it
|
|
422
|
+
from a path — name it: kind: 'right' | 'equilateral' | 'isosceles' |
|
|
423
|
+
'obtuse' | 'acute' | 'scalene', or give exact interior angles in degrees,
|
|
424
|
+
angles: [30, 60] (the third is inferred) or [30, 60, 90]. Angles that nearly
|
|
425
|
+
sum to 180 are normalized, so rounding is safe. With angles or kind the
|
|
426
|
+
triangle scales UNIFORMLY into the width x height box — the angles are fixed
|
|
427
|
+
and win, so one axis comes out smaller than requested. That is the only way
|
|
428
|
+
to keep a 'right' triangle actually right.
|
|
429
|
+
An angle set the engine cannot use — fewer than two entries, or any angle
|
|
430
|
+
outside 0.5-179.5 degrees — falls back to the default isosceles SILENTLY,
|
|
431
|
+
with no error. If you asked for a right triangle and got an isosceles one,
|
|
432
|
+
the angles were rejected.
|
|
372
433
|
- polygon: Regular polygon with N sides (properties: sides, radius, color)
|
|
373
|
-
|
|
434
|
+
points additionally accepts an explicit VERTEX LIST — [[x, y], ...] or
|
|
435
|
+
[{x, y}, ...], three or more, in canvas coordinates — which builds that
|
|
436
|
+
exact, possibly IRREGULAR polygon and ignores sides. Reach for this before
|
|
437
|
+
path when the outline is straight-edged. A plain number in points is not a
|
|
438
|
+
vertex list and falls through to sides (default 6).
|
|
439
|
+
In the vertex-list form the coordinates are ABSOLUTE canvas coordinates and
|
|
440
|
+
position is ignored — the polygon lands where its points say, not where you
|
|
441
|
+
positioned it. Offset the points yourself, or use sides + radius + position.
|
|
442
|
+
- ellipse: Oval shape (properties: width, height, color) — defaults to 100x60
|
|
374
443
|
- path: Custom path with segments or SVG data (properties: segments, pathData, strokeColor, fillColor, closed, smooth)
|
|
375
444
|
- line: Line between two points (properties: from, to, strokeColor, strokeWidth)
|
|
376
445
|
- arc: Curved arc through three points (properties: from, through, to, strokeColor)
|
|
@@ -378,18 +447,27 @@ ITEM TYPES:
|
|
|
378
447
|
- hexagon: Regular 6-sided polygon (properties: radius, color)
|
|
379
448
|
- diamond: 4-sided diamond/rhombus (properties: radius, color)
|
|
380
449
|
- arrow: Right-pointing block arrow (properties: width, height, color)
|
|
381
|
-
- heart: Heart shape (properties: color)
|
|
450
|
+
- heart: Heart shape (properties: width, height, color) — defaults to 80x80
|
|
382
451
|
- disk: Filled disk — the region inside a circle (properties: radius, color)
|
|
383
452
|
- circle-outline: The circle CURVE — stroked, no interior (properties: radius,
|
|
384
453
|
strokeColor, strokeWidth)
|
|
385
454
|
- arrow-right: Alias for arrow — the same definition under the name the shape
|
|
386
|
-
grids use. Identical output
|
|
455
|
+
grids use. Identical output and the same width, height and color; both are
|
|
456
|
+
listed because both are accepted.
|
|
387
457
|
|
|
388
458
|
SPEECH AND ANNOTATION SHAPES — the engine draws these; use one instead of
|
|
389
459
|
hand-building an outline from a path. All take width, height and color, and the
|
|
390
|
-
descriptions below are the engine's own.
|
|
391
|
-
|
|
392
|
-
|
|
460
|
+
descriptions below are the engine's own. Three further parameters are each
|
|
461
|
+
read by six of these eight shapes, and THE THREE SIXES ARE NOT THE SAME SIX —
|
|
462
|
+
a shape missing from a list ignores that parameter silently, so check before
|
|
463
|
+
you pass it:
|
|
464
|
+
cornerRadius — speech-bubble, speech-bubble-pointed, comment-box,
|
|
465
|
+
callout-box, double-bubble, quote-bubble
|
|
466
|
+
tailDirection (bottom-left | bottom-right | bottom | top-left | top-right |
|
|
467
|
+
top | left | right) — speech-bubble, speech-bubble-square,
|
|
468
|
+
speech-bubble-pointed, thought-bubble, comment-box, callout-box
|
|
469
|
+
tailSize (0-1, default 0.35) — speech-bubble, speech-bubble-square,
|
|
470
|
+
speech-bubble-pointed, comment-box, callout-box, double-bubble
|
|
393
471
|
- speech-bubble: Classic round speech bubble with triangular tail.
|
|
394
472
|
- speech-bubble-square: Rectangular speech bubble with sharp corners and
|
|
395
473
|
pointed tail.
|
|
@@ -2262,7 +2340,7 @@ TWO DIFFERENT THINGS, kept apart on purpose:
|
|
|
2262
2340
|
|
|
2263
2341
|
A DESIGN SYSTEM is a real, licensed, versioned product — Material Design 3, IBM Carbon, Shopify Polaris, Fluent 2, Adobe Spectrum, GitHub Primer, USWDS, GOV.UK, Shadcn/Radix, SLDS 2, Tailwind, Chakra and more. Its tokens are facts with a licence attached, in the W3C DTCG format ($value, $type, $description). Twenty-one of them are here. Where a motion curve had to be filled in because the published system does not specify one, the token is marked "pinepaper:authored" — so you can tell a vendor's curve from ours instead of treating both as equally official.
|
|
2264
2342
|
|
|
2265
|
-
An AESTHETIC STYLE is a look: Bauhaus, Art Deco, Swiss typographic, De Stijl, vaporwave, risograph, brutalist, Memphis, claymorphism, op art, pixel art. No licence, no vendor. Thirty-
|
|
2343
|
+
An AESTHETIC STYLE is a look: Bauhaus, Art Deco, Swiss typographic, De Stijl, vaporwave, risograph, brutalist, Memphis, claymorphism, op art, pixel art. No licence, no vendor. Thirty-three are named; eighteen can COMPOSE a scene rather than only be described, and 'list_styles' says which.
|
|
2266
2344
|
|
|
2267
2345
|
- list_systems / get_system: the licensed systems and their tokens, filterable by token type.
|
|
2268
2346
|
- list_easings: every motion curve across every system as a named easing, with its licence and whether it was authored here. Use these to make a motion match a system it has to sit beside.
|
|
@@ -2294,7 +2372,9 @@ A partial composition reports as a failure with the elements that did not create
|
|
|
2294
2372
|
name: 'pinepaper_stick',
|
|
2295
2373
|
description: `The vendored stick-figure kit — a rigged figure posed, walking, travelling, holding a prop, with a garment and hair, plus the set it stands on and among.
|
|
2296
2374
|
|
|
2297
|
-
A different construction from pinepaper_character, which places a figure from the DESIGN GRAPH by concept ("pp:Pigeon"). This is the stick kit specifically
|
|
2375
|
+
A different construction from pinepaper_character, which places a figure from the DESIGN GRAPH by concept ("pp:Pigeon"). This is the stick kit specifically.
|
|
2376
|
+
|
|
2377
|
+
TO MAKE IT ACT, not just stand: gait is how it walks and is never just walking; poses is the body over time, [{at, pose}]; sequence is a named track of those. Pass gait and travel in the SAME call to cross the frame — they share one track and two calls fight over it. A mistyped gait, pose or sequence comes back NAMED in warnings with the valid list, and the figure is still built.
|
|
2298
2378
|
|
|
2299
2379
|
action 'figure' builds the figure. action 'set' builds the floor, the wall and the objects around it, so a figure has somewhere to be.
|
|
2300
2380
|
|
|
@@ -2307,26 +2387,48 @@ The geometry is vendored from mcp-cloud, which makes this a three-repo artifact:
|
|
|
2307
2387
|
kind: { type: 'string', description: 'figure: which figure. set: which piece of the kit.' },
|
|
2308
2388
|
at: { type: 'object', description: '{ x?, y? } — where it goes.' },
|
|
2309
2389
|
scale: { type: 'number', description: 'Size multiplier.' },
|
|
2310
|
-
facing: { type: 'string', enum: ['left', 'right'], description:
|
|
2311
|
-
pose: { type: 'string', description:
|
|
2390
|
+
facing: { type: 'string', enum: ['left', 'right'], description: "set: which way a CHAIR faces. A figure has none and passing it here is refused — a figure faces the way it travels." },
|
|
2391
|
+
pose: { type: 'string', enum: [...STICK_POSES], description: 'figure: ONE pose, held.' },
|
|
2312
2392
|
poseAt: { type: 'number', description: 'figure: seconds at which that pose is struck.' },
|
|
2313
|
-
|
|
2314
|
-
|
|
2315
|
-
|
|
2316
|
-
|
|
2317
|
-
|
|
2318
|
-
|
|
2319
|
-
|
|
2320
|
-
|
|
2321
|
-
|
|
2393
|
+
poses: {
|
|
2394
|
+
type: 'array',
|
|
2395
|
+
description: 'figure: THE BODY OVER TIME — [{at: seconds, pose: name}]. The counterpart of expressions, and the difference between a figure that acts and one that holds a single attitude while captions do the work.',
|
|
2396
|
+
items: { type: 'object', properties: { at: { type: 'number' }, pose: { type: 'string', enum: [...STICK_POSES] } }, required: ['at', 'pose'] },
|
|
2397
|
+
},
|
|
2398
|
+
gait: { type: 'string', enum: [...STICK_GAITS], description: 'figure: HOW it walks, and it is never just walking — trudge leans away from where it is going, sneak crouches, tiptoe raises the cadence. Pass travel in the SAME call to cross the frame; they share one track.' },
|
|
2399
|
+
gaitSeconds: { type: 'number', description: 'figure: how long the gait runs. Defaults to durationSeconds.' },
|
|
2400
|
+
gaitFrom: { type: 'number', description: 'figure: when the gait starts, in seconds.' },
|
|
2401
|
+
sequence: { type: 'string', enum: [...STICK_SEQUENCES], description: 'figure: a named pose track. Shorthand that resolves to beats and joins any poses you also pass.' },
|
|
2402
|
+
sequenceFrom: { type: 'number', description: 'figure: when the sequence starts (default 0).' },
|
|
2403
|
+
sequenceSeconds: { type: 'number', description: 'figure: how long it spans (default 4).' },
|
|
2404
|
+
expression: { type: 'string', enum: [...STICK_EXPRESSIONS], description: 'figure: one face. An unknown name costs the face, not the figure.' },
|
|
2405
|
+
expressions: {
|
|
2406
|
+
type: 'array',
|
|
2407
|
+
description: 'figure: faces over time — [{at: seconds, expression: name}]. Pass durationSeconds with these or the last face lasts one second.',
|
|
2408
|
+
items: { type: 'object', properties: { at: { type: 'number' }, expression: { type: 'string', enum: [...STICK_EXPRESSIONS] } }, required: ['at', 'expression'] },
|
|
2409
|
+
},
|
|
2410
|
+
walk: {
|
|
2411
|
+
anyOf: [{ type: 'boolean' }, { type: 'array', items: { type: 'object', properties: { seconds: { type: 'number' }, from: { type: 'number' } } } }],
|
|
2412
|
+
description: 'figure: walk cycles — true for one default cycle, or [{seconds, from}] for several. For anything other than a plain walk, use gait.',
|
|
2413
|
+
},
|
|
2414
|
+
travel: {
|
|
2415
|
+
type: 'array',
|
|
2416
|
+
description: 'figure: waypoints [{t, x, y}] carrying the figure across the scene rather than walking in place. FEWER THAN TWO IS IGNORED. Pass walk or gait in the same call or it slides without moving its legs.',
|
|
2417
|
+
items: { type: 'object', properties: { t: { type: 'number' }, x: { type: 'number' }, y: { type: 'number' } }, required: ['t', 'x', 'y'] },
|
|
2418
|
+
},
|
|
2419
|
+
prop: { type: 'string', enum: [...STICK_PROPS], description: 'figure: something held in hand.' },
|
|
2420
|
+
propSide: { type: 'string', enum: ['L', 'R'], description: "figure: which hand. 'left'/'right' are accepted and normalised." },
|
|
2421
|
+
garment: { type: 'string', description: 'figure: clothing colour.' },
|
|
2422
|
+
trouser: { type: 'string', description: 'figure: legwear colour.' },
|
|
2423
|
+
hair: { type: 'string', description: 'figure: hair colour.' },
|
|
2322
2424
|
withHair: { type: 'boolean', description: 'figure: draw hair at all.' },
|
|
2323
|
-
groundY: { type: 'number', description: '
|
|
2324
|
-
surfaceY: { type: 'number', description: '
|
|
2325
|
-
durationSeconds: { type: 'number', description: 'figure:
|
|
2326
|
-
object: { type: '
|
|
2327
|
-
items: { type: '
|
|
2328
|
-
floor: {
|
|
2329
|
-
wall: {
|
|
2425
|
+
groundY: { type: 'number', description: 'set: the y a ROOM floor sits at.' },
|
|
2426
|
+
surfaceY: { type: 'number', description: 'set: the y a TABLETOP object sits on.' },
|
|
2427
|
+
durationSeconds: { type: 'number', description: 'figure: when the tracks end, on the same clock as expressions, poses and travel.' },
|
|
2428
|
+
object: { type: 'string', description: "set: the NAME of the thing to put on a surface, with kind 'tabletop'." },
|
|
2429
|
+
items: { type: 'number', description: 'set: how many things stand on a shelf (default 3). A COUNT, not a list.' },
|
|
2430
|
+
floor: { type: 'string', description: "set: the floor COLOUR, for kind 'room'." },
|
|
2431
|
+
wall: { type: 'string', description: "set: the wall COLOUR, for kind 'room'." },
|
|
2330
2432
|
},
|
|
2331
2433
|
required: ['action'],
|
|
2332
2434
|
},
|
|
@@ -3130,6 +3232,8 @@ WHAT THE CHEAP ROUTE COSTS, so the choice is deliberate: items built and animate
|
|
|
3130
3232
|
AVAILABLE GLOBALS:
|
|
3131
3233
|
- app: PinePaper application instance
|
|
3132
3234
|
- app.create(type, params): Create items
|
|
3235
|
+
- app.executeGenerator(name, params): Run a generator — including a CUSTOM one you defined as app.<name> = function(params, options) { ...draw with paper... }. That is the whole draw contract: no registration step is required
|
|
3236
|
+
- app.registerItem(item, type, properties): THE DECISION THAT MATTERS when you draw your own. It returns a registry id and makes that item a first-class object: the USER can click it, select it and change its colour, and you can address it afterwards with modify_item, animate it, keyframe it, point a relation at it, or read it back through get_items and the ontology. An UNregistered path is pixels — it renders and exports identically, and nothing can ever touch it again without redrawing the scene. So register what someone might want to change (the kettle, the title, the sun) and leave the bulk unregistered (a thousand snow specks, a hatch field), which is exactly why generator output is only partly registered: it is a memory decision, and when you write the generator it is YOUR decision
|
|
3133
3237
|
- app.addAnimation(itemId, keyframes, options): Attach keyframe TRACKS programmatically — the other half of a procedural scene, and what makes the loop route cheap: the keyframes are generated, not typed. Accepts an id or the item itself; options.timeUnits ('seconds'|'ms') overrides the ms auto-detect, which long-form timelines need
|
|
3134
3238
|
- app.animate(item, params): Attach a LOOP animation (pulse, bounce, wobble, …) — the other kind of motion, and not what addAnimation does
|
|
3135
3239
|
- app.addRelation(sourceId, targetId, type, params): Add relations
|
|
@@ -3573,12 +3677,17 @@ Requires maskType and keyframes array.`,
|
|
|
3573
3677
|
idempotentHint: true,
|
|
3574
3678
|
openWorldHint: false,
|
|
3575
3679
|
},
|
|
3576
|
-
description: `
|
|
3680
|
+
description: `Which properties can be animated — on an ITEM, or on each mask type.
|
|
3681
|
+
|
|
3682
|
+
- With { itemId }: what THAT item can animate, filtered by its type, from the engine's own table. Each entry carries an 'interpolates' flag, and two of them are FALSE: content and blendMode are DISCRETE — they hold until the next keyframe rather than blending toward it. Treating content as tweenable is what makes every word in a cycler land half a beat early. The result also reports the default easing and every easing name the engine accepts.
|
|
3683
|
+
- With no itemId: the older MASK-TYPE table.
|
|
3577
3684
|
|
|
3578
|
-
|
|
3685
|
+
Needs a studio that publishes the item-side table; without one, the tool says so and pinepaper_keyframe_animate's own ANIMATABLE PROPERTIES section is the fallback.`,
|
|
3579
3686
|
inputSchema: {
|
|
3580
3687
|
type: 'object',
|
|
3581
|
-
properties: {
|
|
3688
|
+
properties: {
|
|
3689
|
+
itemId: { type: 'string', description: 'Ask about THIS item rather than the mask-type table. Answers what its own type can animate, and which of those are discrete.' },
|
|
3690
|
+
},
|
|
3582
3691
|
},
|
|
3583
3692
|
},
|
|
3584
3693
|
{
|
|
@@ -6608,6 +6717,11 @@ EXAMPLES:
|
|
|
6608
6717
|
// ---------------------------------------------------------------------------
|
|
6609
6718
|
// DOMAIN: GENERATOR TOOLS
|
|
6610
6719
|
// ---------------------------------------------------------------------------
|
|
6720
|
+
// @engine-surface-exempt drawMyArt — it is the ILLUSTRATIVE NAME in the draw
|
|
6721
|
+
// contract example below, not a call. Exempted narrowly rather than by
|
|
6722
|
+
// exempting tool descriptions wholesale: descriptions DO name real engine
|
|
6723
|
+
// methods, and checking them is what caught app.setTimeOffset being taught in
|
|
6724
|
+
// the agent guide when no such method exists.
|
|
6611
6725
|
{
|
|
6612
6726
|
name: 'pinepaper_execute_generator',
|
|
6613
6727
|
annotations: {
|
|
@@ -6619,6 +6733,16 @@ EXAMPLES:
|
|
|
6619
6733
|
},
|
|
6620
6734
|
description: `Execute a background generator to create procedural patterns.
|
|
6621
6735
|
|
|
6736
|
+
CUSTOM GENERATORS — the draw contract. Define one as an app method through pinepaper_execute_custom_code:
|
|
6737
|
+
app.drawMyArt = function(params, options) { ...draw with paper... };
|
|
6738
|
+
then invoke it with await app.executeGenerator('drawMyArt', params) in custom code, or through the batch execute_generator op with skipValidation:true. NO REGISTRATION IS REQUIRED — that is the whole contract. If you do register with app.generatorRegistry.register(), definition.fn (or the legacy onGenerate) is mandatory and a {draw} shape is refused by name.
|
|
6739
|
+
|
|
6740
|
+
THIS TOOL cannot invoke a custom generator: it hard-rejects any name outside its enum, deliberately, because the enum is what makes the built-ins discoverable and typo-proof. The two routes above are how you run your own.
|
|
6741
|
+
|
|
6742
|
+
Generator output is only PARTLY registered — drawSunsetScene registers 6 of its 27 objects, drawPattern none of 15 — so pinepaper_get_items and ontology queries see a partial view or nothing. The engine records the invocation instead: re-invoke with new params to "edit".
|
|
6743
|
+
|
|
6744
|
+
WHEN YOU WRITE THE GENERATOR, THAT IS YOUR CHOICE TO MAKE, and it is the important one. app.registerItem(item, type, properties) returns an id and makes the item selectable by the USER and addressable by you — colour changes, modify_item, keyframes, relations, ontology. Unregistered output is pixels: identical on screen and in the export, and untouchable afterwards without redrawing. Register the handful anyone might want to edit; leave the dense decorative bulk out, which is the memory reason the built-ins do the same.
|
|
6745
|
+
|
|
6622
6746
|
USE WHEN:
|
|
6623
6747
|
- "add a sunburst background", "bokeh effect", "gradient mesh"
|
|
6624
6748
|
- "create wave pattern", "wind field", "fluid flow"
|
|
@@ -6691,18 +6815,7 @@ COMMON PARAMS (all generators):
|
|
|
6691
6815
|
properties: {
|
|
6692
6816
|
generatorName: {
|
|
6693
6817
|
type: 'string',
|
|
6694
|
-
enum: [
|
|
6695
|
-
'drawSunburst', 'drawSunsetScene', 'drawGrid', 'drawStackedCircles',
|
|
6696
|
-
'drawCircuit', 'drawWaves', 'drawPattern',
|
|
6697
|
-
'drawBokeh', 'drawGradientMesh', 'drawGeometricAbstract', 'drawWindField',
|
|
6698
|
-
'drawFluidFlow', 'drawOrganicFlow', 'drawNoiseTexture',
|
|
6699
|
-
'drawGlobeWireframe',
|
|
6700
|
-
'drawFunctionPlot', 'drawParametricCurve', 'drawSimulation',
|
|
6701
|
-
'drawSpectrumAnalyzer', 'draw3DSurface',
|
|
6702
|
-
'drawTruchet', 'drawHalftone', 'drawRibbons',
|
|
6703
|
-
'drawFormulaArt', 'drawParametricCollection', 'drawShaderArt', 'drawYeganehMountains',
|
|
6704
|
-
'drawBlobs', 'drawLowPoly', 'drawPeaks', 'drawScatter', 'drawStackedWaves', 'draw3DParametricCurve',
|
|
6705
|
-
],
|
|
6818
|
+
enum: [...GeneratorNameSchema.options],
|
|
6706
6819
|
description: 'Generator name',
|
|
6707
6820
|
},
|
|
6708
6821
|
params: {
|
|
@@ -6890,10 +7003,12 @@ Filters can be stacked - call multiple times to combine effects.`,
|
|
|
6890
7003
|
description: `[Utility] Get all or filtered items from the canvas.
|
|
6891
7004
|
|
|
6892
7005
|
USE WHEN:
|
|
6893
|
-
- Listing
|
|
7006
|
+
- Listing REGISTERED items
|
|
6894
7007
|
- Finding items by type
|
|
6895
7008
|
- Checking animated items
|
|
6896
|
-
- Scene inspection
|
|
7009
|
+
- Scene inspection
|
|
7010
|
+
|
|
7011
|
+
AFTER A GENERATOR, THIS IS A PARTIAL VIEW. A generator may register some, all or none of what it paints: measured on a cleared canvas, drawSunsetScene registers 6 of its 27 objects, drawSunburst 1 of 18, and drawPattern none of its 15. That is by design — a large procedural field would cost memory per path — but it means the canvas can look partly addressable while the rest is silently absent, which is worse for a caller than either extreme. Do not infer canvas contents from this after running a generator; ask app.config.currentBackgroundGenerator / generatorParams for what ran.`,
|
|
6897
7012
|
inputSchema: {
|
|
6898
7013
|
type: 'object',
|
|
6899
7014
|
properties: {
|
|
@@ -7461,7 +7576,7 @@ OPERATION TYPES (13) — use in this order:
|
|
|
7461
7576
|
CANVAS SETUP:
|
|
7462
7577
|
set_canvas_size — {width, height} or {preset: "instagram"|"youtube"|"tiktok"|...}
|
|
7463
7578
|
set_background — {backgroundColor: "#hex"}
|
|
7464
|
-
execute_generator — {generatorName, generatorParams} → fills canvas with procedural art
|
|
7579
|
+
execute_generator — {generatorName, generatorParams} → fills canvas with procedural art (paints WITHOUT fully registering items — see get_items; custom generator names need skipValidation:true)
|
|
7465
7580
|
Generators: drawBokeh, drawGradientMesh, drawWaves, drawSunburst, drawSunsetScene, drawGrid, drawCircuit, drawPattern, drawStackedCircles, drawGeometricAbstract, drawWindField, drawFluidFlow, drawOrganicFlow, drawNoiseTexture, drawGlobeWireframe
|
|
7466
7581
|
PineMath: drawFunctionPlot (y=f(x) plots), drawParametricCurve (x(t),y(t)), drawSimulation (pendulum, Lorenz, spring-mass), drawSpectrumAnalyzer (FFT), draw3DSurface (torus, sphere, Klein bottle)
|
|
7467
7582
|
|
|
@@ -7541,14 +7656,14 @@ EXAMPLE — Animated sky scene with timed reveals:
|
|
|
7541
7656
|
backgroundColor: { type: 'string', description: 'For set_background: hex color' },
|
|
7542
7657
|
generatorName: {
|
|
7543
7658
|
type: 'string',
|
|
7544
|
-
enum: [
|
|
7659
|
+
enum: [...GeneratorNameSchema.options],
|
|
7545
7660
|
description: 'For execute_generator: generator name',
|
|
7546
7661
|
},
|
|
7547
7662
|
generatorParams: { type: 'object', description: 'For execute_generator: parameters' },
|
|
7548
7663
|
// Items
|
|
7549
7664
|
itemType: {
|
|
7550
7665
|
type: 'string',
|
|
7551
|
-
enum: [
|
|
7666
|
+
enum: [...ItemTypeSchema.options],
|
|
7552
7667
|
description: 'For create: item type',
|
|
7553
7668
|
},
|
|
7554
7669
|
position: {
|
|
@@ -7714,14 +7829,16 @@ EXAMPLES:
|
|
|
7714
7829
|
- {platform: "instagram", format: "mp4"} — force MP4
|
|
7715
7830
|
- {platform: "web", format: "svg"} — animated SVG
|
|
7716
7831
|
- {platform: "youtube", format: "mp4", framing: "camera"} — render only what the camera frames during the walkthrough
|
|
7717
|
-
- {platform: "youtube", format: "mp4", duration: 30, estimateOnly: true} — how big would that be? (renders nothing)
|
|
7832
|
+
- {platform: "youtube", format: "mp4", duration: 30, estimateOnly: true} — how big would that be, and what would it lose? (renders nothing)
|
|
7833
|
+
|
|
7834
|
+
Every export answers the second question too: where this scene loses something to the format you chose, the result carries "fidelity" naming it. Its ABSENCE means this scene has nothing that format would drop — not that the format is lossless.`,
|
|
7718
7835
|
inputSchema: {
|
|
7719
7836
|
type: 'object',
|
|
7720
7837
|
properties: {
|
|
7721
7838
|
platform: {
|
|
7722
7839
|
type: 'string',
|
|
7723
|
-
enum: ['instagram', 'instagram-story', 'tiktok', 'youtube', 'youtube-thumbnail', 'twitter', 'linkedin', 'web', 'print-a4', 'print-letter'],
|
|
7724
|
-
description:
|
|
7840
|
+
enum: ['auto', 'instagram', 'instagram-story', 'tiktok', 'youtube', 'youtube-thumbnail', 'twitter', 'linkedin', 'web', 'print-a4', 'print-letter'],
|
|
7841
|
+
description: "Target platform, which sets the output DIMENSIONS. 'auto' (the default) renders the canvas at its own size — use it when the canvas is already the size you want, otherwise a preset REPLACES your dimensions. Every other value forces that platform's frame regardless of the canvas.",
|
|
7725
7842
|
},
|
|
7726
7843
|
format: {
|
|
7727
7844
|
type: 'string',
|
|
@@ -7740,7 +7857,19 @@ EXAMPLES:
|
|
|
7740
7857
|
quality: {
|
|
7741
7858
|
type: 'string',
|
|
7742
7859
|
enum: ['draft', 'standard', 'high'],
|
|
7743
|
-
description: '
|
|
7860
|
+
description: 'Compression level (default: standard). It ALSO carries a default frame rate — draft 15, standard 30, high 60 — so "high" doubles the frame count and the render time against "standard" unless you set fps yourself. Set fps and scale to control those halves directly and leave quality meaning compression.',
|
|
7861
|
+
},
|
|
7862
|
+
fps: {
|
|
7863
|
+
type: 'integer',
|
|
7864
|
+
minimum: 1,
|
|
7865
|
+
maximum: 120,
|
|
7866
|
+
description: 'Video only: frames per second, overriding whatever `quality` implies. File size is bitrate x duration and does not move with fps, but the picture gets fewer bits per frame at a higher one.',
|
|
7867
|
+
},
|
|
7868
|
+
scale: {
|
|
7869
|
+
type: 'number',
|
|
7870
|
+
minimum: 0.1,
|
|
7871
|
+
maximum: 1,
|
|
7872
|
+
description: 'Video only: render at this fraction of the platform preset dimensions (0.1-1). The engine derives its encode target from RESOLUTION, so this is the size control — there is no bitrate to set, and halving the frame roughly quarters the pixels and the file. It is also the preview knob: scale 0.5 with quality "draft" is the fast look-check before committing to a full render. Rounded to even dimensions, which H.264 requires.',
|
|
7744
7873
|
},
|
|
7745
7874
|
framing: {
|
|
7746
7875
|
type: 'string',
|
|
@@ -7749,7 +7878,7 @@ EXAMPLES:
|
|
|
7749
7878
|
},
|
|
7750
7879
|
estimateOnly: {
|
|
7751
7880
|
type: 'boolean',
|
|
7752
|
-
description: 'Preflight only — return the estimated file size for these exact settings and render nothing. Modeled for mp4/webm/gif; png/pdf/svg report confidence "none" (no dimension-based model exists for them); wav reports confidence "exact", because uncompressed PCM size is arithmetic.',
|
|
7881
|
+
description: 'Preflight only — return the estimated file size for these exact settings and render nothing. Modeled for mp4/webm/gif; png/pdf/svg report confidence "none" (no dimension-based model exists for them); wav reports confidence "exact", because uncompressed PCM size is arithmetic. Also answers what THIS scene would lose to this format — a png of an animated scene is one frame, a gif drops the soundtrack — under "fidelity", which is present only when there is something to lose.',
|
|
7753
7882
|
},
|
|
7754
7883
|
duration: {
|
|
7755
7884
|
type: 'number',
|
|
@@ -7758,7 +7887,10 @@ EXAMPLES:
|
|
|
7758
7887
|
description: 'Video duration in seconds for mp4/webm/gif (default 5). Max 60 for mp4/webm; GIF is capped at 15 because it has no bitrate target, so size scales with frames × dimensions — use mp4/webm for longer clips. Static formats ignore this. If you set play_timeline to N seconds, pass the same N here.',
|
|
7759
7888
|
},
|
|
7760
7889
|
},
|
|
7761
|
-
required:
|
|
7890
|
+
// Nothing is required: platform defaults to 'auto', which is the canvas's
|
|
7891
|
+
// own size. Requiring it forced every caller to pick a preset, and a
|
|
7892
|
+
// preset silently replaces the dimensions they had already chosen.
|
|
7893
|
+
required: [],
|
|
7762
7894
|
},
|
|
7763
7895
|
},
|
|
7764
7896
|
{
|
|
@@ -7993,7 +8125,9 @@ EXAMPLES:
|
|
|
7993
8125
|
idempotentHint: true,
|
|
7994
8126
|
openWorldHint: false,
|
|
7995
8127
|
},
|
|
7996
|
-
description: `Capture the
|
|
8128
|
+
description: `Capture the REGISTERED canvas as compact pp: ontology triples + a structured item summary.
|
|
8129
|
+
|
|
8130
|
+
It reads the item registry, so it inherits the same blind spot as pinepaper_get_items: a generator may register some, all or none of what it paints — drawSunsetScene 6 of 27 objects, drawPattern none of 15 — so a scene built by a generator is described partially or not at all. That is deliberate (memory per path), not a gap to work around.
|
|
7997
8131
|
|
|
7998
8132
|
USE THIS instead of pinepaper_get_items when you need to REASON about composition (what's on the canvas, how items relate, what's animated). Typical scenes shrink 3-10× compared to a raw item dump while preserving relations, animations, effects, masks, and collage styling.
|
|
7999
8133
|
|
|
@@ -8154,7 +8288,7 @@ QUERIES (14):
|
|
|
8154
8288
|
Listing:
|
|
8155
8289
|
- list_types: All item types (filter by category, includeAbstract)
|
|
8156
8290
|
- list_edges: All relation/edge types (filter by category)
|
|
8157
|
-
- list_generators:
|
|
8291
|
+
- list_generators: every generator the engine can run — the built-ins AND the registry, merged and awaited, which on a current studio is about 74 rather than the 3 this once reported. A generator you registered at runtime DOES appear. A custom draw function passed to execute_generator does not, because it was never registered; that is the one gap. If the registry chunk has not finished loading the result says partial: true and names the retry rather than presenting the built-ins as the whole set, and an older studio that cannot merge the registry answers with the built-ins under that same flag.
|
|
8158
8292
|
- list_effects: All visual effect types
|
|
8159
8293
|
- list_patterns: All detected design patterns
|
|
8160
8294
|
- list_math_functions: All math functions used in animations
|