@pinepaper.studio/mcp-server 1.6.26 → 1.6.28
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 +155 -2
- package/SECURITY.md +4 -3
- package/dist/agent/types.d.ts +3 -3
- package/dist/browser/puppeteer-controller.d.ts +11 -0
- package/dist/browser/puppeteer-controller.d.ts.map +1 -1
- package/dist/browser/puppeteer-controller.js +38 -2
- package/dist/browser/puppeteer-controller.js.map +1 -1
- package/dist/build-info.json +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -3
- package/dist/index.js.map +1 -1
- package/dist/ontology/hints.d.ts +3 -1
- package/dist/ontology/hints.d.ts.map +1 -1
- package/dist/ontology/hints.js +4 -2
- package/dist/ontology/hints.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 +2 -0
- package/dist/ontology/vocabulary.js.map +1 -1
- package/dist/tools/choreograph.d.ts.map +1 -1
- package/dist/tools/choreograph.js +7 -0
- package/dist/tools/choreograph.js.map +1 -1
- package/dist/tools/definitions.d.ts.map +1 -1
- package/dist/tools/definitions.js +58 -28
- package/dist/tools/definitions.js.map +1 -1
- package/dist/tools/engine-lists.d.ts +20 -3
- package/dist/tools/engine-lists.d.ts.map +1 -1
- package/dist/tools/engine-lists.js +156 -3
- 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 +2 -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 +19 -4
- package/dist/tools/engine-surface.js.map +1 -1
- package/dist/tools/export-file-receipt.d.ts +64 -0
- package/dist/tools/export-file-receipt.d.ts.map +1 -1
- package/dist/tools/export-file-receipt.js +91 -13
- package/dist/tools/export-file-receipt.js.map +1 -1
- package/dist/tools/expression-grammar.d.ts +10 -0
- package/dist/tools/expression-grammar.d.ts.map +1 -0
- package/dist/tools/expression-grammar.js +33 -0
- package/dist/tools/expression-grammar.js.map +1 -0
- package/dist/tools/handlers/export.d.ts.map +1 -1
- package/dist/tools/handlers/export.js +58 -4
- package/dist/tools/handlers/export.js.map +1 -1
- package/dist/tools/handlers/generate.js +2 -2
- package/dist/tools/handlers/generate.js.map +1 -1
- package/dist/tools/handlers.d.ts +5 -0
- package/dist/tools/handlers.d.ts.map +1 -1
- package/dist/tools/handlers.js +74 -2
- package/dist/tools/handlers.js.map +1 -1
- package/dist/tools/lane.d.ts +10 -5
- package/dist/tools/lane.d.ts.map +1 -1
- package/dist/tools/lane.js +49 -8
- package/dist/tools/lane.js.map +1 -1
- package/dist/tools/scene-cache-export.d.ts +52 -0
- package/dist/tools/scene-cache-export.d.ts.map +1 -0
- package/dist/tools/scene-cache-export.js +231 -0
- package/dist/tools/scene-cache-export.js.map +1 -0
- package/dist/tools/shape-params.d.ts +2 -2
- package/dist/tools/shape-params.js +2 -2
- package/dist/tools/stick-vocabulary.d.ts +1 -1
- package/dist/tools/stick-vocabulary.js +1 -1
- package/dist/tools/toolkits.d.ts +1 -1
- package/dist/tools/toolkits.d.ts.map +1 -1
- package/dist/tools/toolkits.js +8 -2
- package/dist/tools/toolkits.js.map +1 -1
- package/dist/types/code-generator.d.ts +1 -0
- package/dist/types/code-generator.d.ts.map +1 -1
- package/dist/types/code-generator.js +536 -255
- package/dist/types/code-generator.js.map +1 -1
- package/dist/types/schemas.d.ts +238 -201
- package/dist/types/schemas.d.ts.map +1 -1
- package/dist/types/schemas.js +14 -24
- package/dist/types/schemas.js.map +1 -1
- package/dist/utils/asset-paths.d.ts.map +1 -1
- package/dist/utils/asset-paths.js +11 -0
- package/dist/utils/asset-paths.js.map +1 -1
- package/dist/utils/capabilities.d.ts +15 -0
- package/dist/utils/capabilities.d.ts.map +1 -0
- package/dist/utils/capabilities.js +63 -0
- package/dist/utils/capabilities.js.map +1 -0
- package/dist/utils/env.d.ts.map +1 -1
- package/dist/utils/env.js +2 -1
- package/dist/utils/env.js.map +1 -1
- package/manifest.json +18 -2
- package/package.json +1 -1
|
@@ -13,7 +13,8 @@ import { craftToolDefinitions } from './craft-tools.js';
|
|
|
13
13
|
import { TOOL_TAGS } from './toolkits.js';
|
|
14
14
|
import { STICK_GAITS, STICK_POSES, STICK_SEQUENCES, STICK_EXPRESSIONS, STICK_PROPS } from './stick-vocabulary.js';
|
|
15
15
|
import { AgentBatchOperationTypeSchema, GeneratorNameSchema, ItemTypeSchema } from '../types/schemas.js';
|
|
16
|
-
import {
|
|
16
|
+
import { expressionGrammarText } from './expression-grammar.js';
|
|
17
|
+
import { DESIGN_MEDIA, DESIGN_MEDIA_APPLY, FILTER_TYPES, FILTER_DOCS, LINEAGE_KINDS, STYLED_SCENE_STYLES, STYLED_SCENE_STYLE_INFO, PATTERN_KINDS, ANIMATION_TYPES, ANIMATION_WAVEFORMS, ANIMATION_ORIGINS } from './engine-lists.js';
|
|
17
18
|
import { EffectTypeSchema, AgentExportFormatSchema, RelationTypeSchema, SimpleAnimationTypeSchema, EasingSchema, KEYFRAME_EASINGS, EASING_DESCRIPTIONS, KEYFRAME_EASING_JSON_SCHEMA, GEOMETRY_OPERATIONS, THREAD_STITCHES, } from '../types/schemas.js';
|
|
18
19
|
/**
|
|
19
20
|
* Vocabulary lists derived from Zod schemas so tool descriptions stay in
|
|
@@ -1639,7 +1640,7 @@ warp (optional): chained parametric warp(s) — displace each sampled point by {
|
|
|
1639
1640
|
|
|
1640
1641
|
RETURNS: { success, kind, itemId } — itemId is the created path. Bad expressions / empty ranges return { success:false, error }.
|
|
1641
1642
|
|
|
1642
|
-
To make an item TRAVEL along an equation curve (instead of drawing it), use pinepaper_add_relation relationType moves_along_path with params.equation
|
|
1643
|
+
To make an item TRAVEL along an equation curve (instead of drawing it), use pinepaper_add_relation relationType moves_along_path with params.equation. The same flipY applies there: by default y is math-up, so the item rides the curve mirrored about cy compared with screen coordinates (y down). Pass flipY: false to author the curve in screen coordinates.
|
|
1643
1644
|
|
|
1644
1645
|
EXAMPLES:
|
|
1645
1646
|
- Sine wave: { kind: "function", expr: "sin(x/40) * 60", min: -300, max: 300, style: { strokeColor: "#4f46e5" } }
|
|
@@ -3069,7 +3070,7 @@ The engine names each refusal — "a boolean needs at least two paths", "that pa
|
|
|
3069
3070
|
description: `A real 3D WORLD under the canvas — depth-buffered terrain, sky, sun shadows, an addressable actor stage and a directed camera. ADDITIVE: Paper.js keeps every vector item, hit-test and export path; the world composites underneath the (transparent) Paper canvas.
|
|
3070
3071
|
|
|
3071
3072
|
ACTIONS:
|
|
3072
|
-
- create: { spec? ('forest' | 'snowMountain' | 'field' | 'jungle' | a full spec object), character? (true/config → a walkable character) } → { configurableKeys }
|
|
3073
|
+
- create: { spec? ('forest' | 'snowMountain' | 'field' | 'jungle' | a full spec object), character? (true/config → a walkable character), control? (true: a viewer walks the character with the keyboard — arrows/WASD, Space jumps, Shift runs — when the scene plays in the studio; the editor's own shortcuts pause while it is on) } → { configurableKeys, control }
|
|
3073
3074
|
- describe: {} → the ENGINE'S OWN parameter schema — every world parameter with type, range and description. Call this before configure; the tool does not restate the schema, so it cannot drift from the engine.
|
|
3074
3075
|
- configure: { patch } — live deep-merged change to anything describe lists (colours, fog, sun, terrain amplitude/ridge, seed…). Schema-validated: a wrong key errors NAMING the right one, never a silent no-op.
|
|
3075
3076
|
- add_actor: { actorId?, x, z, height?, sprite? (a canvas item id), live? } → { actorId }. live: true re-rasterizes the item as it animates — a RIGGED character (walk cycle, expressions) PERFORMS in the world instead of standing there as a photograph of itself.
|
|
@@ -3131,6 +3132,10 @@ RECIPE — a character walking through a forest: create {spec:'forest'} → impo
|
|
|
3131
3132
|
anyOf: [{ type: 'boolean' }, { type: 'object' }],
|
|
3132
3133
|
description: 'create: include the walkable character (boolean or config).',
|
|
3133
3134
|
},
|
|
3135
|
+
control: {
|
|
3136
|
+
type: 'boolean',
|
|
3137
|
+
description: 'create: true lets a viewer walk the character with the keyboard (arrows/WASD, Space jumps, Shift runs) when the scene plays in the studio. Needs the character (not character: false).',
|
|
3138
|
+
},
|
|
3134
3139
|
patch: { type: 'object', description: 'configure: partial world spec, validated against describe. Colours (env.zenith, env.horizon, env.fogColor, env.sunColor, env.ambient, env.lowColor … env.propColorB) take hex ("#03050c") or [r, g, b] in 0..1.' },
|
|
3135
3140
|
actorId: { type: 'string', description: 'Actor id.' },
|
|
3136
3141
|
x: { type: 'number', description: 'add_actor: world x.' },
|
|
@@ -3420,6 +3425,8 @@ EXAMPLE doc: { "nodes": [ {"id":"bar","type":"pp:Rectangle","width":300,"height"
|
|
|
3420
3425
|
description: `Audit the LIVE scene's relational structure (FxTool S12-E2) — read-only, nothing is changed. Answers "is this scene composed with relations, or just a pile of absolutely-positioned items?" and proposes fixes.
|
|
3421
3426
|
|
|
3422
3427
|
RETURNS:
|
|
3428
|
+
- relations: every relation bound — [{ from, fromName?, to, type, params }], the first 200 (relationCount says how many when there are more). Use it to find the relation to change, then a batch relation op with update: true.
|
|
3429
|
+
- customRelations: each pinepaper_register_custom_relation definition as it was given (name, params, computeFunction, applyFunction).
|
|
3423
3430
|
- density: { itemCount, relationalItemCount, relationalDensity (0..1 — fraction of items touching the relation graph), edgeCount, componentCount }. A low relationalDensity means items are placed by hardcoded coordinates and won't hold together if something moves.
|
|
3424
3431
|
- suggestions: structural relations for unrelated item pairs that ALREADY sit in a structural configuration — [{ from, to, type (on_top_of/below/beside/inside/centered_on/aligned_with), params, confidence }], ranked by confidence. Apply the good ones with pinepaper_add_relation to make the layout robust.
|
|
3425
3432
|
|
|
@@ -3454,6 +3461,8 @@ PARAMS: { eps? (bounds-match tolerance px, default 4), cap? (max suggestions, de
|
|
|
3454
3461
|
MOVES_ALONG_PATH — ride a path (a hand tracing a stroke, a car on a road):
|
|
3455
3462
|
- sourceId: the item that moves. The path comes from ONE of: targetId (or params.pathId) naming a PATH ITEM, sampled into points for you; params.path as points [[x, y], …]; or params.equation.
|
|
3456
3463
|
- params.duration: seconds for one traversal (or pass speed directly, 1 ≈ 150 px/s). params.delay: seconds on the timeline before it starts; until then the item waits at the path start. params.offset: [dx, dy] added to the point on the path — set it to (centre - pen tip) so a hand image's TIP, not its centre, rides the stroke. closed (loop back to the start; default from the path item), phase (0–1 start point), easing (linear | easeIn | easeOut | easeInOut | sine | bounce | pingpong), signal (deterministic, frame-rate-invariant — prefer it for export).
|
|
3464
|
+
- The item travels at CONSTANT SPEED along the route: the fraction of the duration elapsed is the fraction of the route's LENGTH covered, not of the equation's parameter or of the point count. Where the curve is long it moves the same speed as where it is short; easing reshapes that progress. For a route timed by the parameter instead, key the position with pinepaper_keyframe_animate.
|
|
3465
|
+
- params.equation is in math coordinates with y UP (flipY: true by default), placed at cx, cy: on screen the curve is mirrored about cy. Write flipY: false to author it in screen coordinates (y down).
|
|
3457
3466
|
- With no path from any of those it is refused, not accepted as a still item.
|
|
3458
3467
|
|
|
3459
3468
|
USE WHEN:
|
|
@@ -3489,8 +3498,9 @@ RELATION TYPES:
|
|
|
3489
3498
|
- syncs_with: Run the source's animation on the TARGET's timeline (params: offset, speedRatio) — they share a clock and stay in step even when the target's timing changes, which merely starting together does not give you.
|
|
3490
3499
|
- triggers_animation: Start the target's animation on a condition (params: trigger, delay, atTime). The declarative "and then": sequencing in the graph instead of in a callback nobody can query.
|
|
3491
3500
|
- tours / synced_to_audio: Move through a sequence of targets; bind playback to an audio track.
|
|
3492
|
-
-
|
|
3493
|
-
-
|
|
3501
|
+
- localizes_sound: a sound pans with an item. sourceId is the sound item (pinepaper_sound create's itemId), targetId the item it follows; the sound's stereo position follows the item across the frame, in the preview and in exported audio. params: axis (x | y, default x), spread (0..1: pan at the frame edge, default 0.85), reference (camera | canvas, default camera), distanceGain (true also quietens it away from the centre), smoothing (ms, default 80).
|
|
3502
|
+
- connects_to: Diagram edge from source to target (params: via = the connector's item id, sourcePort / targetPort = auto | top | bottom | left | right, label). A RECORD of the connection: it draws nothing itself.
|
|
3503
|
+
- attached_to_tail / head_points_to: source = the connector, target = the item; params: port (auto | top | bottom | left | right). They record which port each end belongs to; the diagram system is what moves a connector's ends when an item moves, and it does so only for connectors made with pinepaper_connect. On a plain line (create itemType 'line') they record the structure and move nothing: for a connector that follows the items, make it with pinepaper_connect.
|
|
3494
3504
|
- expresses: Play a facial expression over a root's part_of children (params: expression — blink|smile|surprise…, interval, duration, easing). No interval means sustained. It walks part_of from the ROOT, so parts with roles but no parent are INERT: the relation applies to nothing and reports success, which is what makes an unparented pair of eyes look finished while being unable to blink.
|
|
3495
3505
|
- part_of: Semantic membership with a named role (params: role, offset, structural). structural: true records the part WITHOUT driving its position — the right choice when the parent is a group that already transforms its children, since driving it too would fight the group.
|
|
3496
3506
|
- staggered_with: Delay an item's animation by its place in a sequence (params: index, stagger, effect). For a SHAPED stagger — outward from the centre, converging from the edges, across a grid — also pass count (required: without it there is no "end" to measure distance from), plus from (start|end|center|edges|random), amount (total seconds for the whole run, overrides stagger), grid ("rows,cols" or "auto"), axis (x|y) and distributeEase. Plain index x stagger still works and is taken first. To stagger items directly rather than through a relation, use pinepaper_stagger.
|
|
@@ -3523,7 +3533,7 @@ RELATION COMPATIBILITY:
|
|
|
3523
3533
|
Text→Text: font blend
|
|
3524
3534
|
Cross-type: particle denoising transition
|
|
3525
3535
|
- group_morphs_to: pair-by-index morph between two paper.Groups (any two — graph vertices+edges, letter collages, dashboard clusters). Path.Line children deform via endpoints; other children translate; excess children fade. Params: duration, hold, loop, easing (linear|easeIn|easeOut|easeInOut), deformLines.
|
|
3526
|
-
- moves_along_path: self-relation (targetId=null); item is driven along a path. Source the path EITHER from params.path (array of {x,y} or [x,y]) OR from params.equation (S10 B5) — a math curve the item TRAVERSES, sampled deterministically on the Expression IR: params.equation = { kind: function|parametric|fourier|preset, expr | xExpr/yExpr | harmonics | preset, min, max, samples, scale, cx, cy, flipY, warp } (same equation contract as pinepaper_equation_path, but origin is cx/cy, default 0).
|
|
3536
|
+
- moves_along_path: self-relation (targetId=null); item is driven along a path. Source the path EITHER from params.path (array of {x,y} or [x,y]) OR from params.equation (S10 B5) — a math curve the item TRAVERSES, sampled deterministically on the Expression IR: params.equation = { kind: function|parametric|fourier|preset, expr | xExpr/yExpr | harmonics | preset, min, max, samples, scale, cx, cy, flipY, warp } (same equation contract as pinepaper_equation_path, but origin is cx/cy, default 0). y is MATH-UP by default (flipY: true): on screen the curve is mirrored about cy, so a curve written in screen coordinates (y down) needs flipY: false. Params: path OR equation, speed, closed, phase, easing (linear|easeIn|easeOut|easeInOut|sine|bounce|pingpong).
|
|
3527
3537
|
|
|
3528
3538
|
GEOMETRIC CONSTRUCTION CONSTRAINTS (Layer 2) — the source item is RE-DERIVED every frame from its anchor item(s), so dragging an anchor updates the dependent live (GeoGebra-style), and the construction persists as relation graph data (edit it by editing relations, not by re-running code). Anchor A is the relation target; extra anchors ride in params:
|
|
3529
3539
|
- is_midpoint_of: source = midpoint(target, params.other). params.other = id of the second endpoint (B).
|
|
@@ -3535,7 +3545,7 @@ GEOMETRIC CONSTRUCTION CONSTRAINTS (Layer 2) — the source item is RE-DERIVED e
|
|
|
3535
3545
|
|
|
3536
3546
|
PROCEDURAL / DETERMINISTIC BINDING (Expression IR — S10 G1) — bind a property to another property or to a math function of time. Pass params.signal:true to route through the pure, seed/frame-deterministic signal interpreter (replay-stable — same time → identical output); omit it for the per-frame compute fallback.
|
|
3537
3547
|
- driven_by: source's sourceProperty = target's targetProperty * multiplier + offset (optionally clamped). sourceProperty ∈ x|y|rotation|opacity|scale|strokeWidth|fillColor|strokeColor; targetProperty ∈ x|y|rotation|opacity|scale. For fillColor/strokeColor the (clamped 0..1) driven value interpolates colorFrom→colorTo — so a relation drives COLOR. NEEDS a target (the property source). params: sourceProperty, targetProperty, multiplier, offset, clamp {min,max}, colorFrom, colorTo, signal. e.g. tint a dot by a planet's x: sourceProperty 'fillColor', targetProperty 'x', colorFrom '#0055ff', colorTo '#ff3300', signal true.
|
|
3538
|
-
- time_expression: self-relation (targetId=null); the source's params.property is driven by a
|
|
3548
|
+
- time_expression: self-relation (targetId=null); the source's params.property (x, y, rotation, opacity or scale) is driven by a formula of t (scene time) and v (params.baseValue). params: property (default 'y'), expression (e.g. 'sin(t*2)*50 + v'), baseValue, signal (true also evaluates it as a pure f(t) via the Expression IR). The formula grammar: ${expressionGrammarText()}. A name outside it, or a wrong argument count, is refused by name: it would parse to nothing and the item would not move.
|
|
3539
3549
|
|
|
3540
3550
|
EVENT-DRIVEN SCENE CHAINS (S11) — build a LONG scene as a graph of timed events, not a keyframe track. First make events with pinepaper_event (action:'create' → eventId). The relations below have an EVENT as their sourceId; firing the event runs the reaction. Chain beats over animation time with on_event_fire_after (timeline:'canvas'), have beats mutate the scene with on_event_add_relation, then kick it off with pinepaper_event action:'pulse'. Because canvas-timed fires are on the animation clock, the whole chain is scrub-, loop-, and replay-stable.
|
|
3541
3551
|
- on_event_fire_after: sourceId=event, targetId=the NEXT event. When source fires, pulse target after params.delay ms. params.timeline: 'canvas' (animation clock — use for scene chains) | 'wall' (real setTimeout). This is the chaining primitive.
|
|
@@ -3578,7 +3588,7 @@ Relations are COMPOSITIONAL - an item can have multiple relations that work toge
|
|
|
3578
3588
|
},
|
|
3579
3589
|
relationType: {
|
|
3580
3590
|
type: 'string',
|
|
3581
|
-
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'],
|
|
3591
|
+
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', 'localizes_sound', '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'],
|
|
3582
3592
|
description: 'Type of relationship. A name registered with pinepaper_register_custom_relation in this session is accepted too.',
|
|
3583
3593
|
},
|
|
3584
3594
|
params: {
|
|
@@ -3621,7 +3631,7 @@ USE WHEN:
|
|
|
3621
3631
|
targetId: { type: 'string', description: 'Target item ID' },
|
|
3622
3632
|
relationType: {
|
|
3623
3633
|
type: 'string',
|
|
3624
|
-
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'],
|
|
3634
|
+
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', 'localizes_sound', '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'],
|
|
3625
3635
|
description: 'Specific relation type to remove (optional - removes all if not specified)',
|
|
3626
3636
|
},
|
|
3627
3637
|
},
|
|
@@ -3649,7 +3659,7 @@ USE WHEN:
|
|
|
3649
3659
|
itemId: { type: 'string', description: 'Item to query relations for' },
|
|
3650
3660
|
relationType: {
|
|
3651
3661
|
type: 'string',
|
|
3652
|
-
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'],
|
|
3662
|
+
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', 'localizes_sound', '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'],
|
|
3653
3663
|
description: 'Filter by relation type (optional)',
|
|
3654
3664
|
},
|
|
3655
3665
|
direction: {
|
|
@@ -3664,15 +3674,17 @@ USE WHEN:
|
|
|
3664
3674
|
{
|
|
3665
3675
|
name: 'pinepaper_register_custom_relation',
|
|
3666
3676
|
annotations: {
|
|
3667
|
-
title: 'Register Custom Relation',
|
|
3677
|
+
title: 'Register Custom Relation (needs PINEPAPER_ALLOW_CODE)',
|
|
3668
3678
|
readOnlyHint: false,
|
|
3669
3679
|
destructiveHint: false,
|
|
3670
3680
|
idempotentHint: false,
|
|
3671
3681
|
openWorldHint: false,
|
|
3672
3682
|
},
|
|
3673
|
-
description: `
|
|
3683
|
+
description: `SECURITY SWITCH: needs a server started with PINEPAPER_ALLOW_CODE=1 (off by default; only the person running the server can turn it on). Otherwise it is refused and nothing runs.
|
|
3684
|
+
|
|
3685
|
+
PARAMS ARE DEFINITIONS, not values: { gap: { type: 'number', default: 60, min: 0 } } (type is number | string | boolean | array | object). Once registered, the name is a valid relationType for pinepaper_add_relation in this session.
|
|
3674
3686
|
|
|
3675
|
-
Register a custom relation type with compute and apply functions.
|
|
3687
|
+
Register a custom relation type with compute and apply functions. For motion without code, use time_expression.
|
|
3676
3688
|
|
|
3677
3689
|
USE WHEN:
|
|
3678
3690
|
- Creating physics-based behaviors (attraction, repulsion, collision)
|
|
@@ -3735,13 +3747,15 @@ applyFunction: \`
|
|
|
3735
3747
|
{
|
|
3736
3748
|
name: 'pinepaper_execute_custom_code',
|
|
3737
3749
|
annotations: {
|
|
3738
|
-
title: 'Execute Custom Code',
|
|
3750
|
+
title: 'Execute Custom Code (needs PINEPAPER_ALLOW_CODE)',
|
|
3739
3751
|
readOnlyHint: false,
|
|
3740
3752
|
destructiveHint: true,
|
|
3741
3753
|
idempotentHint: false,
|
|
3742
3754
|
openWorldHint: true,
|
|
3743
3755
|
},
|
|
3744
|
-
description: `
|
|
3756
|
+
description: `SECURITY SWITCH: needs a server started with PINEPAPER_ALLOW_CODE=1 (off by default; only the person running the server can turn it on). Otherwise it is refused and nothing runs.
|
|
3757
|
+
|
|
3758
|
+
Execute arbitrary JavaScript code in the PinePaper context.
|
|
3745
3759
|
|
|
3746
3760
|
USE WHEN:
|
|
3747
3761
|
- Advanced Paper.js operations not covered by other tools
|
|
@@ -3841,6 +3855,9 @@ ANIMATION TYPES (18 — the list the driver actually switches on):
|
|
|
3841
3855
|
- scrollLeft / scrollRight / scrollUp / scrollDown: Continuous scroll, wrapping
|
|
3842
3856
|
- path: Travel along an assigned path
|
|
3843
3857
|
- typewriter: Character-by-character reveal
|
|
3858
|
+
- ripple: An opacity wave. On a GROUP it sweeps through the children outward from origin, each a little later; on a single item it pulses the item.
|
|
3859
|
+
- undulate: A vertical lift wave, swept through a group's children the same way (intensity 0.4 ≈ 14 px).
|
|
3860
|
+
ripple and undulate take waveform (the shape of one cycle) and origin (where the wave starts on a group). SVG and Lottie exports draw them static; export MP4, WebM or GIF to keep the wave.
|
|
3844
3861
|
|
|
3845
3862
|
There is NO 'slide'. An unknown type is stored and then ignored — the item sits still while its data claims otherwise, and the call still reports success — so use the exact names above.`,
|
|
3846
3863
|
inputSchema: {
|
|
@@ -3849,7 +3866,7 @@ There is NO 'slide'. An unknown type is stored and then ignored — the item sit
|
|
|
3849
3866
|
itemId: { type: 'string', description: 'Registry ID of the item' },
|
|
3850
3867
|
animationType: {
|
|
3851
3868
|
type: 'string',
|
|
3852
|
-
enum: [
|
|
3869
|
+
enum: [...ANIMATION_TYPES],
|
|
3853
3870
|
description: 'Type of animation',
|
|
3854
3871
|
},
|
|
3855
3872
|
speed: {
|
|
@@ -3864,6 +3881,8 @@ There is NO 'slide'. An unknown type is stored and then ignored — the item sit
|
|
|
3864
3881
|
type: 'number',
|
|
3865
3882
|
description: 'Animation start delay in seconds.',
|
|
3866
3883
|
},
|
|
3884
|
+
waveform: { type: 'string', enum: [...ANIMATION_WAVEFORMS], description: 'ripple / undulate: the shape of one cycle (default sine).' },
|
|
3885
|
+
origin: { type: 'string', enum: [...ANIMATION_ORIGINS], description: 'ripple / undulate on a group: where the wave starts (default center).' },
|
|
3867
3886
|
},
|
|
3868
3887
|
required: ['itemId', 'animationType'],
|
|
3869
3888
|
},
|
|
@@ -3906,7 +3925,7 @@ ANIMATABLE PROPERTIES:
|
|
|
3906
3925
|
- strokeColor: Color string
|
|
3907
3926
|
- strokeWidth, width, height, radius, shadowBlur, shadowColor: Numbers / colours
|
|
3908
3927
|
- fontSize: Number
|
|
3909
|
-
- TEXT (current studio): fontStyle ('normal' / 'italic' / 'oblique', discrete — switches at the next key), textAlign ('left' / 'center' / 'right', discrete; the anchor stays put), lineHeight (px, or a multiple of fontSize up to 5), letterSpacing (px, or a CSS length such as '0.1em'). An older studio stores these keys without drawing them; the result names any it did not animate (ignoredProperties).
|
|
3928
|
+
- TEXT (current studio): fontStyle ('normal' / 'italic' / 'oblique', discrete — switches at the next key), textAlign ('left' / 'center' / 'right', discrete; the anchor stays put), lineHeight (px, or a multiple of fontSize up to 5), letterSpacing (px, or a CSS length such as '0.1em'). An older studio stores these keys without drawing them; the result names any it did not animate (ignoredProperties). fontWeight keys STEP: a font with fixed weights switches from one weight to the next once, partway through the move, and does not ramp. Key fontSize or scale for a smooth change.
|
|
3910
3929
|
- STROKE DRAW-ON (paths): trimStart, trimEnd (0-1 of the path's length), trimOffset (shifts the visible window along it), dashArray. A draw-on is trimEnd 0 -> 1.
|
|
3911
3930
|
The authoritative list for a given item is pinepaper_get_animatable_properties — ask it rather than guessing.
|
|
3912
3931
|
|
|
@@ -3916,7 +3935,7 @@ ${EASING_LINES}
|
|
|
3916
3935
|
- 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.
|
|
3917
3936
|
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.
|
|
3918
3937
|
|
|
3919
|
-
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).
|
|
3938
|
+
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). A DISCRETE change (a bar turning red at 2 s, a label switching colour) needs this too: without hold / step every key ramps from the one before it, so the colour fades across the whole gap instead of switching. This applies to batch keyframe ops the same way.
|
|
3920
3939
|
|
|
3921
3940
|
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.
|
|
3922
3941
|
|
|
@@ -4588,7 +4607,7 @@ SUPPORTED ANIMATIONS: bounce, breathe, fade, glow, jelly, path, pulse, rotate, s
|
|
|
4588
4607
|
target: { type: 'string', description: 'Name of target item' },
|
|
4589
4608
|
type: {
|
|
4590
4609
|
type: 'string',
|
|
4591
|
-
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'],
|
|
4610
|
+
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', 'localizes_sound', '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'],
|
|
4592
4611
|
},
|
|
4593
4612
|
params: {
|
|
4594
4613
|
type: 'object',
|
|
@@ -4852,6 +4871,7 @@ KINDS:
|
|
|
4852
4871
|
- phase_wave — members move on a sine, each a phase later than the one before. params: property ('y' default, 'x', 'rotation', 'opacity'), amplitude (px, degrees or 0..1), period (seconds per cycle), wavelength (members per full cycle), phase (radians). window { from, to } limits when it plays; time counts from \`from\`.
|
|
4853
4872
|
- stagger — each member's animationDelay, derived from its place. params: step (s between neighbours), start (s), order: index | reverse | center | edges.
|
|
4854
4873
|
- ring / orbit (the same motion) — members spaced evenly round a circle that turns. params: center ([x, y] or {x, y}; default 960, 540), target (an item id or name: the centre follows it), radius (px, default 200), period (seconds per turn, default 6), phase (RADIANS, the first member's angle), direction (1 clockwise, -1 or 'ccw'). Each member's own position is overwritten while it plays and comes back when the pattern is removed. window as for phase_wave.
|
|
4874
|
+
- STACKING. phase_wave patterns on the same member and property add their offsets to one shared base on the current studio, so sequenced windows combine without drift (an older studio re-based them on each other's writes and could leave the member displaced: there, give a member one pattern per property and sequence by modifying its params and window). ring and orbit write the member's absolute position, so two of them on one member conflict: give each member one ring or orbit.
|
|
4855
4875
|
|
|
4856
4876
|
MEMBERS — by names (a '*' matches any run: "letter-*"), ids, or a tag, in the order they are given; an array is taken as ids or names. A name that matches nothing is reported in the result, not ignored.
|
|
4857
4877
|
|
|
@@ -8061,6 +8081,7 @@ SPEC:
|
|
|
8061
8081
|
UNITS (a number, or a [min, max] range picked per particle where it says range):
|
|
8062
8082
|
- count: particles per burst, at most 10000 on the current studio (2000 on older studios) — a larger count is drawn at the cap and the reply warns with the number drawn. For more, add a second burst at the same t.
|
|
8063
8083
|
- speed: px/s (range). angle: degrees, 0 = right, 90 = down (range). gravity: px/s². lifetime: seconds (range, > 0). size: px (range).
|
|
8084
|
+
- gravity, drag, friction, opacity, sizeEnd and jitter also take a range on the current studio, sampled per particle; an older studio draws the midpoint and warns emitter-range-not-read.
|
|
8064
8085
|
- fadeIn / fadeOut: SECONDS at the start / end of each particle's life. fadeOut is capped at that particle's lifetime (a 0.5 s life cannot fade for 2 s; it fades over its whole life instead), and the current studio warns when it caps one. Omitted (or fade: 'linear'), the particle fades linearly over its WHOLE life; fade: 'none' turns both off.
|
|
8065
8086
|
- spin: DEGREES PER SECOND, positive = clockwise on screen (range; spinAlternate flips every other particle). It turns rect, confetti, star and dash particles; a circle has no orientation, so spin on circles shows nothing (the current studio warns when every particle is a circle).
|
|
8066
8087
|
- jitter: PIXELS — on the current studio each particle is displaced up to ±jitter px on each axis from its path, at full size from birth; jitterGrow: true keeps the older ramp (zero at birth, the full ±jitter at the end of life). Older studios (before jitterGrow) displace up to ±jitter/2, growing from 0 at birth. jitterHz: how many times a second that offset is re-rolled (0, the default, keeps one offset per particle).
|
|
@@ -8080,8 +8101,10 @@ EXAMPLE — confetti at 2 s:
|
|
|
8080
8101
|
},
|
|
8081
8102
|
{
|
|
8082
8103
|
name: 'pinepaper_render_hook',
|
|
8083
|
-
annotations: { title: 'Render Hook', readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: false },
|
|
8084
|
-
description: `
|
|
8104
|
+
annotations: { title: 'Render Hook (register needs PINEPAPER_ALLOW_CODE)', readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: false },
|
|
8105
|
+
description: `SECURITY SWITCH: register needs a server started with PINEPAPER_ALLOW_CODE=1 (off by default; only the person running the server can turn it on). list and unregister always work.
|
|
8106
|
+
|
|
8107
|
+
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.)
|
|
8085
8108
|
|
|
8086
8109
|
ACTIONS:
|
|
8087
8110
|
- 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.
|
|
@@ -8141,7 +8164,7 @@ EXAMPLE — a ball comes to life and crosses the frame:
|
|
|
8141
8164
|
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 }] },
|
|
8142
8165
|
beats: {
|
|
8143
8166
|
type: 'array',
|
|
8144
|
-
description: 'Beats in time order: [{at, verb, to?, duration?, height?, times?, decay?, arc?, edge?, from?, amount?, hold?, intensity?}].',
|
|
8167
|
+
description: 'Beats in time order: [{at, verb, to?, duration?, height?, times?, decay?, arc?, edge?, from?, amount?, hold?, intensity?}]. intensity is the amplitude of shake in px; no other verb reads it.',
|
|
8145
8168
|
items: {
|
|
8146
8169
|
type: 'object',
|
|
8147
8170
|
properties: {
|
|
@@ -8292,12 +8315,14 @@ EXAMPLE: { action: 'apply', target: 'item_4', graph: { nodes: [{ id: 'in', type:
|
|
|
8292
8315
|
The engine validates the document before applying it: a truncated file, a foreign JSON blob or a document from a newer major version is refused, not half-applied. Returns counts (items, animated items, keyframes, relations): compare them with the export's to confirm nothing was lost.
|
|
8293
8316
|
|
|
8294
8317
|
- path: the file the export wrote (absolute, or relative to the server's working directory).
|
|
8295
|
-
- strict: false loads a document with validation problems anyway and returns them as warnings (default true: refuse)
|
|
8318
|
+
- strict: false loads a document with validation problems anyway and returns them as warnings (default true: refuse).
|
|
8319
|
+
- registerCustomRelations: true registers the custom relation definitions the file carries (a full export saves them with the scene) before loading, so its relations of those types run. Their compute and apply code runs in the studio, so pass it only for a file you trust; without it the result names them and they stay unregistered.`,
|
|
8296
8320
|
inputSchema: {
|
|
8297
8321
|
type: 'object',
|
|
8298
8322
|
properties: {
|
|
8299
8323
|
path: { type: 'string', description: 'The project document file.' },
|
|
8300
8324
|
strict: { type: 'boolean', description: 'Refuse a document with validation problems (default true).' },
|
|
8325
|
+
registerCustomRelations: { type: 'boolean', description: 'Register the custom relation definitions saved in the file first (their code runs in the studio: only for a file you trust).' },
|
|
8301
8326
|
},
|
|
8302
8327
|
required: ['path'],
|
|
8303
8328
|
},
|
|
@@ -8857,7 +8882,8 @@ EXAMPLE — Animated sky scene with timed reveals:
|
|
|
8857
8882
|
append: { type: 'boolean', description: "For keyframe_animate: add these keys to the item's existing track instead of replacing it (a key at the same time merges, the new values win). Without it the op replaces the track; the op's result says which happened." },
|
|
8858
8883
|
mode: { type: 'string', description: "For keyframe_animate: the studio's spelling of append — 'merge' is append: true; 'replace' (the default) replaces the track." },
|
|
8859
8884
|
// Relations
|
|
8860
|
-
sourceId: { type: 'string', description: 'For relation: source item ID or $N' },
|
|
8885
|
+
sourceId: { type: 'string', description: 'For relation: source item ID or $N, or a name pattern ("dot-*"): every item named like it, in name order, each with index and count added to relationOptions; re-sending it after adding members binds the new ones and updates index and count' },
|
|
8886
|
+
update: { type: 'boolean', description: 'relation: true changes the relationOptions of the relation already bound (same sourceId, targetId, relationType) instead of binding another' },
|
|
8861
8887
|
targetId: { type: 'string', description: 'For relation: target item ID or $N' },
|
|
8862
8888
|
relationType: {
|
|
8863
8889
|
type: 'string',
|
|
@@ -9058,7 +9084,7 @@ VERIFY MOTION BEFORE YOU RENDER. An export takes seconds to minutes and shows yo
|
|
|
9058
9084
|
loop: { anyOf: [{ type: 'boolean' }, { type: 'integer', minimum: 0, maximum: 1000 }], description: 'gif / apng: true = loop forever, false / 0 / 1 = play once, n = play n times (email clients often want a few plays, not forever). Refused on video formats — see SEAMLESS LOOPS.' },
|
|
9059
9085
|
broadcast: { type: 'boolean', description: 'mp4 only: broadcast-safe — BT.709, limited range (16-235), tagged bt709, constant bitrate with an 8 Mbps floor at 720p+ (4 below). result.video reports what the encoder did.' },
|
|
9060
9086
|
frames: { type: 'integer', minimum: 1, maximum: 36000, description: 'Animated formats: exactly this many frames instead of duration. A duration makes ceil(duration x fps) frames (7.91667 s at 24 fps is 191, not 190), so use frames for frame-exact segments.' },
|
|
9061
|
-
deterministic: { type: 'boolean', description: 'mp4 / webm: byte-identical
|
|
9087
|
+
deterministic: { type: 'boolean', description: 'mp4 / webm: pins the container timestamps. WebM then comes out byte-identical; an MP4\'s encoded bytes can still differ run to run (the H.264 encoder is not bit-exact), so compare MP4s by the receipt\'s frameDigest, which is the same for the same frames, not by sha256.' },
|
|
9062
9088
|
motionBlur: {
|
|
9063
9089
|
type: 'object',
|
|
9064
9090
|
description: 'mp4 / webm: real motion blur. Each frame is rendered `subframes` times across the shutter and averaged, so fast movement smears instead of strobing. Costs subframes× the render time: run estimateOnly first (it reports renders and renderCost). The result carries motionBlur (what the exporter applied).',
|
|
@@ -9117,6 +9143,8 @@ VERIFY MOTION BEFORE YOU RENDER. An export takes seconds to minutes and shows yo
|
|
|
9117
9143
|
enum: ['canvas', 'camera'],
|
|
9118
9144
|
description: 'Output framing. "canvas" (default) renders the full canvas. "camera" renders only the first-keyframe viewport of a camera_animates walkthrough — video formats only.',
|
|
9119
9145
|
},
|
|
9146
|
+
startTime: { type: 'number', description: 'mp4 / webm: start at this time (seconds) on the timeline, the chain\'s when there is one; duration is the length of the range. Frames match a full export exactly; the frames before startTime are still rendered (not encoded). result.video.range says where it snapped.' },
|
|
9147
|
+
perScene: { type: 'boolean', description: 'mp4 / webm of a scene chain: one cached segment per scene, joined (video copied, audio re-encoded), so after an edit only the scenes that changed render again. Needs ffmpeg on PATH; a chain with crossfades or cut sounds is exported whole and the result says why.' },
|
|
9120
9148
|
estimateOnly: {
|
|
9121
9149
|
type: 'boolean',
|
|
9122
9150
|
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.',
|
|
@@ -9195,13 +9223,15 @@ EXAMPLE RESPONSE:
|
|
|
9195
9223
|
{
|
|
9196
9224
|
name: 'pinepaper_p5_draw',
|
|
9197
9225
|
annotations: {
|
|
9198
|
-
title: 'p5.js Draw',
|
|
9226
|
+
title: 'p5.js Draw (needs PINEPAPER_ALLOW_CODE)',
|
|
9199
9227
|
readOnlyHint: false,
|
|
9200
9228
|
destructiveHint: false,
|
|
9201
9229
|
idempotentHint: false,
|
|
9202
9230
|
openWorldHint: false,
|
|
9203
9231
|
},
|
|
9204
|
-
description: `
|
|
9232
|
+
description: `SECURITY SWITCH: needs a server started with PINEPAPER_ALLOW_CODE=1 (off by default; only the person running the server can turn it on). Otherwise it is refused and nothing runs.
|
|
9233
|
+
|
|
9234
|
+
Execute p5.js-style drawing code on the PinePaper canvas.
|
|
9205
9235
|
|
|
9206
9236
|
AI assistants can use familiar p5.js syntax - the code is translated to Paper.js automatically.
|
|
9207
9237
|
This is a SUBSET of p5.js functions optimized for static drawings.
|
|
@@ -9662,7 +9692,7 @@ VERBOSITY:
|
|
|
9662
9692
|
toolkit: {
|
|
9663
9693
|
type: 'string',
|
|
9664
9694
|
description: 'Toolkit profile: core (default), full, agent, diagram, map, font, minimal, lane',
|
|
9665
|
-
enum: ['core', 'full', 'agent', 'diagram', 'map', 'font', 'minimal', 'lane'],
|
|
9695
|
+
enum: ['core', 'full', 'agent', 'diagram', 'map', 'font', 'minimal', 'lane', 'edit'],
|
|
9666
9696
|
},
|
|
9667
9697
|
load: {
|
|
9668
9698
|
type: 'array',
|