@pinepaper.studio/mcp-server 1.6.14 → 1.6.16
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.de.md +6 -1
- package/README.es.md +6 -1
- package/README.fr.md +6 -1
- package/README.hi.md +6 -1
- package/README.ja.md +6 -1
- package/README.ko.md +6 -1
- package/README.md +130 -6
- package/README.pt-BR.md +6 -1
- package/README.zh-CN.md +6 -1
- package/assets/brand/pinepaper-lockup-horizontal-white.svg +1 -0
- package/assets/brand/pinepaper-lockup-horizontal.svg +1 -0
- package/assets/edit-whenever.svg +1 -1
- package/dist/browser/puppeteer-controller.js +2 -2
- package/dist/browser/puppeteer-controller.js.map +1 -1
- package/dist/build-info.json +2 -2
- package/dist/ontology/upstream-vocabulary.d.ts +2 -2
- package/dist/ontology/upstream-vocabulary.js +2 -2
- package/dist/tools/definitions.d.ts.map +1 -1
- package/dist/tools/definitions.js +107 -9
- package/dist/tools/definitions.js.map +1 -1
- package/dist/tools/engine-methods.d.ts.map +1 -1
- package/dist/tools/engine-methods.js +1 -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 +59 -12
- package/dist/tools/engine-surface.js.map +1 -1
- package/dist/tools/handlers/camera.d.ts.map +1 -1
- package/dist/tools/handlers/camera.js +11 -0
- package/dist/tools/handlers/camera.js.map +1 -1
- package/dist/tools/handlers/generate.d.ts +324 -0
- package/dist/tools/handlers/generate.d.ts.map +1 -0
- package/dist/tools/handlers/generate.js +264 -0
- package/dist/tools/handlers/generate.js.map +1 -0
- package/dist/tools/handlers.d.ts.map +1 -1
- package/dist/tools/handlers.js +39 -4
- package/dist/tools/handlers.js.map +1 -1
- package/dist/tools/minimal-descriptions.d.ts.map +1 -1
- package/dist/tools/minimal-descriptions.js +3 -0
- package/dist/tools/minimal-descriptions.js.map +1 -1
- package/dist/tools/shape-params.d.ts +2 -2
- package/dist/tools/shape-params.d.ts.map +1 -1
- package/dist/tools/shape-params.js +20 -3
- package/dist/tools/shape-params.js.map +1 -1
- package/dist/tools/stick-vocabulary.d.ts +1 -1
- package/dist/tools/stick-vocabulary.js +1 -1
- package/dist/tools/toolkits.d.ts.map +1 -1
- package/dist/tools/toolkits.js +3 -0
- package/dist/tools/toolkits.js.map +1 -1
- 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 +339 -29
- package/dist/types/code-generator.js.map +1 -1
- package/dist/types/schemas.d.ts +532 -82
- package/dist/types/schemas.d.ts.map +1 -1
- package/dist/types/schemas.js +26 -10
- package/dist/types/schemas.js.map +1 -1
- package/dist/vendor/design/design-style.js +1 -1
- package/icon.png +0 -0
- package/icon.svg +1 -0
- package/manifest.json +15 -2
- package/package.json +3 -1
|
@@ -1755,6 +1755,91 @@ EXAMPLE: { checks: ["contrast", "flash"], duration: 6, fps: 20 }`,
|
|
|
1755
1755
|
},
|
|
1756
1756
|
},
|
|
1757
1757
|
},
|
|
1758
|
+
{
|
|
1759
|
+
name: 'pinepaper_generate',
|
|
1760
|
+
annotations: { title: 'Generate Image (cloud)', readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: true },
|
|
1761
|
+
description: `Generate images with an AI model in the PinePaper cloud, and optionally place the first one on the canvas. CHARGED per output — price it first with pinepaper_generate_estimate (free).
|
|
1762
|
+
|
|
1763
|
+
Needs a service-account key in PINEPAPER_API_KEY (pp_sa_…, render:create scope). It is an internal beta enabled per organisation: without it the result says "not enabled for your organisation", and nothing is charged. Every refusal says whether anything was charged.
|
|
1764
|
+
|
|
1765
|
+
- model or useCase: a model id from pinepaper_generate_estimate {listModels: true}, or a use case and the cloud picks its default (hero stills, plates, text in the image, character-consistent edits).
|
|
1766
|
+
- input: { prompt, aspect ('16:9' | '9:16' | '1:1' | '4:5'), n (1-4), seed?, negativePrompt?, imageUrls? (https references for edit models) }.
|
|
1767
|
+
- brief / designRef: always passed on; the cloud records each generation against the design.
|
|
1768
|
+
- place: 'cover' (fill the canvas, centred; default when true) or 'contain' — places the first asset: an image as an image item, a video as a video layer (with its durationSeconds). The fit uses the asset's delivered size, not the requested aspect.
|
|
1769
|
+
- timeoutSec: how long to wait (default 180). A job that outlives it keeps running and is only charged if it delivers; collect it with pinepaper_generate_status.
|
|
1770
|
+
|
|
1771
|
+
WORDS ARE VECTOR: give words as input.text [{content, role?: headline|subhead|caption|cta|label, font?}]. The model makes a text-free plate; the words come back as textLayers (plus a hint), and with place they are added as real, editable text over it: headline top-left (Anton by default), subhead below, caption / cta bottom-left, label top-right, inside title-safe, each contrast-checked against the plate (a dark scrim is added only where it falls short of WCAG 4.5:1, or 3:1 for large text). Their item ids are in placement.text.
|
|
1772
|
+
|
|
1773
|
+
The result: assets [{assetId, ref, width, height}] — the sizes the files HAVE (a model may pick its own size for an aspect), chargedUsd, and any model notes (e.g. a SynthID watermark) to pass on.`,
|
|
1774
|
+
inputSchema: {
|
|
1775
|
+
type: 'object',
|
|
1776
|
+
properties: {
|
|
1777
|
+
model: { type: 'string' },
|
|
1778
|
+
useCase: { type: 'string' },
|
|
1779
|
+
input: {
|
|
1780
|
+
type: 'object',
|
|
1781
|
+
properties: {
|
|
1782
|
+
prompt: { type: 'string' },
|
|
1783
|
+
aspect: { type: 'string', enum: ['16:9', '9:16', '1:1', '4:5'] },
|
|
1784
|
+
n: { type: 'integer', minimum: 1, maximum: 4 },
|
|
1785
|
+
seed: { type: 'integer' },
|
|
1786
|
+
negativePrompt: { type: 'string' },
|
|
1787
|
+
imageUrls: { type: 'array', items: { type: 'string' }, maxItems: 14, description: 'Reference / start-frame images: https URLs, or your own generated images as their ref "/scene-assets/<id>" (chain a still into a video or a character edit).' },
|
|
1788
|
+
seconds: { type: 'number', exclusiveMinimum: 0, maximum: 60, description: 'Video models: clip length; each model allows its own lengths (listModels).' },
|
|
1789
|
+
text: { type: 'array', maxItems: 12, items: { type: 'object', properties: { content: { type: 'string' }, role: { type: 'string', enum: ['headline', 'subhead', 'caption', 'cta', 'label'] }, font: { type: 'string' } }, required: ['content'] }, description: 'Words for the design. The model never draws them: the plate comes back text-free and these return as textLayers — with place, laid out as real PinePaper text.' },
|
|
1790
|
+
allowText: { type: 'boolean', description: 'Let the MODEL draw text — eval-tier models only (e.g. ideogram-v3); refused (422) elsewhere. Prefer text.' },
|
|
1791
|
+
},
|
|
1792
|
+
required: ['prompt'],
|
|
1793
|
+
},
|
|
1794
|
+
brief: { type: 'string' },
|
|
1795
|
+
designRef: { type: 'object', properties: { kind: { type: 'string' }, id: { type: 'string' } }, required: ['kind', 'id'] },
|
|
1796
|
+
place: { anyOf: [{ type: 'boolean' }, { type: 'string', enum: ['cover', 'contain'] }] },
|
|
1797
|
+
timeoutSec: { type: 'integer', minimum: 10, maximum: 1800 },
|
|
1798
|
+
},
|
|
1799
|
+
required: ['input'],
|
|
1800
|
+
},
|
|
1801
|
+
},
|
|
1802
|
+
{
|
|
1803
|
+
name: 'pinepaper_generate_estimate',
|
|
1804
|
+
annotations: { title: 'Estimate Generation (free)', readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: true },
|
|
1805
|
+
description: `Free: price a pinepaper_generate call before making it, or list the models. { listModels: true } returns every model you may use with its price per output, use cases, licence notes and the defaults per use case; { model | useCase, input } returns the estimate for that request. Needs PINEPAPER_API_KEY, like pinepaper_generate.`,
|
|
1806
|
+
inputSchema: {
|
|
1807
|
+
type: 'object',
|
|
1808
|
+
properties: {
|
|
1809
|
+
model: { type: 'string' },
|
|
1810
|
+
useCase: { type: 'string' },
|
|
1811
|
+
input: {
|
|
1812
|
+
type: 'object',
|
|
1813
|
+
properties: {
|
|
1814
|
+
prompt: { type: 'string' },
|
|
1815
|
+
aspect: { type: 'string', enum: ['16:9', '9:16', '1:1', '4:5'] },
|
|
1816
|
+
n: { type: 'integer', minimum: 1, maximum: 4 },
|
|
1817
|
+
seed: { type: 'integer' },
|
|
1818
|
+
negativePrompt: { type: 'string' },
|
|
1819
|
+
imageUrls: { type: 'array', items: { type: 'string' }, maxItems: 14, description: 'Reference / start-frame images: https URLs, or your own generated images as their ref "/scene-assets/<id>" (chain a still into a video or a character edit).' },
|
|
1820
|
+
seconds: { type: 'number', exclusiveMinimum: 0, maximum: 60, description: 'Video models: clip length; each model allows its own lengths (listModels).' },
|
|
1821
|
+
text: { type: 'array', maxItems: 12, items: { type: 'object', properties: { content: { type: 'string' }, role: { type: 'string', enum: ['headline', 'subhead', 'caption', 'cta', 'label'] }, font: { type: 'string' } }, required: ['content'] }, description: 'Words for the design. The model never draws them: the plate comes back text-free and these return as textLayers — with place, laid out as real PinePaper text.' },
|
|
1822
|
+
allowText: { type: 'boolean', description: 'Let the MODEL draw text — eval-tier models only (e.g. ideogram-v3); refused (422) elsewhere. Prefer text.' },
|
|
1823
|
+
},
|
|
1824
|
+
required: ['prompt'],
|
|
1825
|
+
},
|
|
1826
|
+
listModels: { type: 'boolean' },
|
|
1827
|
+
},
|
|
1828
|
+
},
|
|
1829
|
+
},
|
|
1830
|
+
{
|
|
1831
|
+
name: 'pinepaper_generate_status',
|
|
1832
|
+
annotations: { title: 'Generation Status', readOnlyHint: false, destructiveHint: false, idempotentHint: true, openWorldHint: true },
|
|
1833
|
+
description: `Collect a pinepaper_generate job that outlived its timeoutSec: its status, and when done its assets and chargedUsd. place: 'cover' | 'contain' places the first image, as pinepaper_generate does.`,
|
|
1834
|
+
inputSchema: {
|
|
1835
|
+
type: 'object',
|
|
1836
|
+
properties: {
|
|
1837
|
+
jobId: { type: 'string' },
|
|
1838
|
+
place: { anyOf: [{ type: 'boolean' }, { type: 'string', enum: ['cover', 'contain'] }] },
|
|
1839
|
+
},
|
|
1840
|
+
required: ['jobId'],
|
|
1841
|
+
},
|
|
1842
|
+
},
|
|
1758
1843
|
{
|
|
1759
1844
|
name: 'pinepaper_render_batch',
|
|
1760
1845
|
annotations: {
|
|
@@ -2043,15 +2128,18 @@ EXAMPLE: { times: [0, 0.5, 1, 1.5, 2], seed: 42 }`,
|
|
|
2043
2128
|
description: `Bring VIDEO and AUDIO onto the canvas from a URL, and control playback. Uploaded video is a first-class canvas item (drag, scale, animate, export like any shape); audio rides the timeline.
|
|
2044
2129
|
|
|
2045
2130
|
ACTIONS:
|
|
2046
|
-
- upload_video: { url (required), position?, scale?, timeOffset? (timeline start, s), clipInPoint?, clipOutPoint? (trim, s) } → { id, duration, width, height, name }
|
|
2047
|
-
- upload_audio: { url (required), volume? (0–1, default 1), loop?, muted?, timeOffset? } → { id, registryId, duration, name }. Pass loop EXPLICITLY — loop:true for a music bed, loop:false for a voice-over or sting; when omitted, the studio's own default applies and differs between builds.
|
|
2131
|
+
- upload_video: { url (required), position?, scale?, timeOffset? (timeline start, s) or atPlayhead?: true (start at the current playback time), clipInPoint?, clipOutPoint? (trim, s) } → { id, duration, width, height, name }
|
|
2132
|
+
- upload_audio: { url (required), volume? (0–1, default 1), loop?, muted?, timeOffset? or atPlayhead? } → { id, registryId, duration, name }. Pass loop EXPLICITLY — loop:true for a music bed, loop:false for a voice-over or sting; when omitted, the studio's own default applies and differs between builds.
|
|
2048
2133
|
- list: → all media [{ id, kind, duration, … }]
|
|
2049
2134
|
- remove: { id } → removed boolean
|
|
2050
2135
|
- set_playback_rate: { id, rate (0.25–4) } → applies to video or audio
|
|
2051
|
-
- set_clip: { id, inPoint, outPoint (media-time s, outPoint > inPoint) } → re-trim an ALREADY-uploaded clip (video or audio)
|
|
2136
|
+
- set_clip: { id, inPoint, outPoint (media-time s, outPoint > inPoint), timeOffset? (canvas s: also MOVE the clip to start there) } → re-trim an ALREADY-uploaded clip (video or audio). A studio that cannot move clips refuses timeOffset rather than ignoring it.
|
|
2137
|
+
- split: { id, at (canvas s) } → cut a clip in two: { leftId, rightId, leftMediaId, rightMediaId, at }. The first half keeps its id. Refused (not claimed) where the studio cannot split or the time is outside the clip.
|
|
2138
|
+
- add_transition: { fromItemId (ends at the cut), toItemId (starts at it), transition?: { type: 'crossfade'|'dip', seconds, color } } → the same in preview and export. Split a clip, then transition between its halves, or join two clips that meet.
|
|
2139
|
+
- For an IMAGE on the timeline, use pinepaper_import_image with bornAt / ttl (seconds on screen).
|
|
2052
2140
|
|
|
2053
2141
|
NOTES:
|
|
2054
|
-
-
|
|
2142
|
+
- The server fetches the URL (or reads a local path / data: URL) and hands the page the bytes, so it does not need to be CORS-permitted.
|
|
2055
2143
|
- Use the returned id with set_playback_rate / set_clip / remove, and (for video) modify/animate it like any item.
|
|
2056
2144
|
|
|
2057
2145
|
VIDEO EDITING:
|
|
@@ -2065,14 +2153,16 @@ EXAMPLE: { action: 'upload_video', url: 'https://…/clip.mp4', scale: 0.5, time
|
|
|
2065
2153
|
inputSchema: {
|
|
2066
2154
|
type: 'object',
|
|
2067
2155
|
properties: {
|
|
2068
|
-
action: { type: 'string', enum: ['upload_video', 'upload_audio', 'list', 'remove', 'set_playback_rate', 'set_clip', 'set_time_remap', 'speed_ramp', 'match_cut', 'apply_track_matte', 'stop_live_matte'], description: "Media action" },
|
|
2156
|
+
action: { type: 'string', enum: ['upload_video', 'upload_audio', 'list', 'remove', 'set_playback_rate', 'set_clip', 'split', 'add_transition', 'set_time_remap', 'speed_ramp', 'match_cut', 'apply_track_matte', 'stop_live_matte'], description: "Media action" },
|
|
2157
|
+
transition: { type: 'object', properties: { type: { type: 'string', enum: ['crossfade', 'dip'] }, seconds: { type: 'number', exclusiveMinimum: 0, maximum: 10 }, color: { type: 'string' } }, description: "add_transition: { type ('crossfade' default | 'dip'), seconds, color (dip) }." },
|
|
2158
|
+
atPlayhead: { type: 'boolean', description: 'upload_video / upload_audio: start at the current playback time (instead of timeOffset).' },
|
|
2069
2159
|
remapTrack: { type: 'array', items: { type: 'object', properties: { time: { type: 'number' }, value: { type: 'number' }, easing: { type: 'string' } }, required: ['time', 'value'] }, description: 'set_time_remap: canvas-seconds → source-seconds curve (≥2 points). null clears the remap.' },
|
|
2070
2160
|
segments: { type: 'array', items: { type: 'object', properties: { duration: { type: 'number' }, speed: { type: 'number' } }, required: ['duration', 'speed'] }, description: 'speed_ramp: consecutive {duration, speed} segments. speed 0 = freeze frame, negative = reverse.' },
|
|
2071
2161
|
fromItemId: { type: 'string', description: 'match_cut: outgoing shot item id.' },
|
|
2072
2162
|
toItemId: { type: 'string', description: 'match_cut: incoming shot item id.' },
|
|
2073
2163
|
subject: { type: 'string', enum: ['detect', 'bounds'], description: "match_cut: subject source — 'detect' (on-device DETR, needs consent on first use) or 'bounds'." },
|
|
2074
2164
|
label: { type: 'string', description: 'match_cut: narrow detection to one class ("person") when the biggest object is not the subject.' },
|
|
2075
|
-
at: { type: 'number', description: 'match_cut: cut time in seconds (default 0).' },
|
|
2165
|
+
at: { type: 'number', description: 'match_cut: cut time in seconds (default 0). split: the canvas time to cut at (required).' },
|
|
2076
2166
|
settle: { type: 'number', description: 'match_cut: seconds to relax to natural framing (default 0.8).' },
|
|
2077
2167
|
fade: { type: 'number', description: 'match_cut: crossfade seconds; 0 = hard cut (default 0.12).' },
|
|
2078
2168
|
consent: { type: 'boolean', description: 'match_cut: allow the detection model download (a first run without it returns needsConsent instead of downloading silently).' },
|
|
@@ -2089,7 +2179,7 @@ EXAMPLE: { action: 'upload_video', url: 'https://…/clip.mp4', scale: 0.5, time
|
|
|
2089
2179
|
outPoint: { type: 'number', description: 'Clip out-point (media-time s, > inPoint) — set_clip.' },
|
|
2090
2180
|
position: { type: 'object', properties: { x: { type: 'number' }, y: { type: 'number' } }, description: 'Canvas position — upload_video.' },
|
|
2091
2181
|
scale: { type: 'number', description: 'Scale factor — upload_video.' },
|
|
2092
|
-
timeOffset: { type: 'number', description: 'Timeline start offset (s) — upload_video / upload_audio.' },
|
|
2182
|
+
timeOffset: { type: 'number', description: 'Timeline start offset (s) — upload_video / upload_audio; set_clip: move the clip to start here.' },
|
|
2093
2183
|
clipInPoint: { type: 'number', description: 'Trim in-point (s) — upload_video.' },
|
|
2094
2184
|
clipOutPoint: { type: 'number', description: 'Trim out-point (s) — upload_video.' },
|
|
2095
2185
|
volume: { type: 'number', description: 'Volume 0–1 (default 1) — upload_audio.' },
|
|
@@ -3571,6 +3661,10 @@ EXAMPLE — Reveal at 2s, skip first second of keyframe data, end at 4s of keyfr
|
|
|
3571
3661
|
type: 'number',
|
|
3572
3662
|
description: 'Stop at N seconds into the keyframe data (tail trim). Default: lastKeyframeTime.',
|
|
3573
3663
|
},
|
|
3664
|
+
append: {
|
|
3665
|
+
type: 'boolean',
|
|
3666
|
+
description: 'Add these keys to the item\'s existing track (same-time keys merge, new values win) instead of replacing it — e.g. a button press after an entrance. Without it, a second call replaces the track. result.track says whether the track was appended to or replaced; studios without merge replace, and say so.',
|
|
3667
|
+
},
|
|
3574
3668
|
},
|
|
3575
3669
|
required: ['itemId', 'keyframes'],
|
|
3576
3670
|
},
|
|
@@ -4901,7 +4995,9 @@ ACTIONS:
|
|
|
4901
4995
|
- update_from_instance: Promote an instance's edits back into the master. Params: instanceId
|
|
4902
4996
|
- detach: Make an instance an ordinary independent item. Params: instanceId
|
|
4903
4997
|
|
|
4904
|
-
Overrides are the point: an instance can differ from its master and still receive master updates
|
|
4998
|
+
Overrides are the point: an instance can differ from its master and still receive master updates.
|
|
4999
|
+
|
|
5000
|
+
Instances carry the master's LOOK (geometry, style, text), not its animation: instantiate and sync copy what the master is, not its keyframes or animations. To animate instances, animate each one (keyframe_animate on its instanceId, or stagger across them).`,
|
|
4905
5001
|
inputSchema: {
|
|
4906
5002
|
type: 'object',
|
|
4907
5003
|
properties: {
|
|
@@ -8046,9 +8142,11 @@ VERIFY MOTION BEFORE YOU RENDER. An export takes seconds to minutes and shows yo
|
|
|
8046
8142
|
maxBytes: { type: 'integer', minimum: 1, description: 'Upload size budget (zip for html5-ad, HTML for playable). html5-ad default 150000 (Google Ads display); set your network figure.' },
|
|
8047
8143
|
},
|
|
8048
8144
|
},
|
|
8049
|
-
transparent: { type: 'boolean', description: 'apng
|
|
8145
|
+
transparent: { type: 'boolean', description: 'apng: keep the alpha channel (the default; false fills the background colour). webm: true writes a VP9 alpha channel where the studio supports it; result.video.alpha confirms it, and fidelity says when it did not. Not for mp4 / gif.' },
|
|
8146
|
+
alphaQuantizer: { type: 'integer', minimum: 0, maximum: 63, description: 'webm with transparent: alpha-stream quality, 0 = lossless … 63.' },
|
|
8050
8147
|
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.' },
|
|
8051
8148
|
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.' },
|
|
8149
|
+
deterministic: { type: 'boolean', description: 'mp4 / webm: byte-identical files for the same scene (pins the container timestamps), so exports can be checksummed or cached by hash.' },
|
|
8052
8150
|
broadcastHeadroom: { type: 'integer', minimum: 0, maximum: 40, description: 'mp4 with broadcast only, default 12: luma codes kept clear at both ends, so encoder ringing stays legal (12 measured clean on hard edges; 4 = ~100x fewer out-of-range samples, 12 = ~1000x; never zero). Fidelity raises luma_out_of_range with the legaliser command when any remain.' },
|
|
8053
8151
|
bitrate: { type: 'integer', minimum: 100000, maximum: 200000000, description: 'mp4 / webm: target bits/s, replacing the quality-derived one. The browser encoder treats it as a CEILING; result.video.achievedBitrate is what it produced.' },
|
|
8054
8152
|
minBitrate: { type: 'integer', minimum: 100000, maximum: 200000000, description: 'mp4 / webm: a floor; a miss is a fidelity warning naming the re-encode a delivery spec needs.' },
|