@pinepaper.studio/mcp-server 1.6.16 → 1.6.18
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.de.md +1 -1
- package/README.es.md +1 -1
- package/README.fr.md +1 -1
- package/README.hi.md +1 -1
- package/README.ja.md +1 -1
- package/README.ko.md +1 -1
- package/README.md +142 -4
- package/README.pt-BR.md +1 -1
- package/README.zh-CN.md +1 -1
- package/dist/browser/puppeteer-controller.d.ts +61 -1
- package/dist/browser/puppeteer-controller.d.ts.map +1 -1
- package/dist/browser/puppeteer-controller.js +168 -6
- package/dist/browser/puppeteer-controller.js.map +1 -1
- package/dist/build-info.json +2 -2
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +75 -10
- package/dist/index.js.map +1 -1
- package/dist/ontology/ontology-validator.d.ts.map +1 -1
- package/dist/ontology/ontology-validator.js +9 -5
- package/dist/ontology/ontology-validator.js.map +1 -1
- 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 +198 -47
- package/dist/tools/definitions.js.map +1 -1
- package/dist/tools/engine-lists.d.ts +20 -0
- package/dist/tools/engine-lists.d.ts.map +1 -0
- package/dist/tools/engine-lists.js +86 -0
- package/dist/tools/engine-lists.js.map +1 -0
- package/dist/tools/engine-methods.d.ts.map +1 -1
- package/dist/tools/engine-methods.js +8 -0
- package/dist/tools/engine-methods.js.map +1 -1
- package/dist/tools/engine-surface.d.ts +1 -1
- package/dist/tools/engine-surface.d.ts.map +1 -1
- package/dist/tools/engine-surface.js +20 -4
- package/dist/tools/engine-surface.js.map +1 -1
- package/dist/tools/handlers/beats.d.ts +64 -0
- package/dist/tools/handlers/beats.d.ts.map +1 -0
- package/dist/tools/handlers/beats.js +83 -0
- package/dist/tools/handlers/beats.js.map +1 -0
- package/dist/tools/handlers/brand-intake.d.ts +95 -0
- package/dist/tools/handlers/brand-intake.d.ts.map +1 -0
- package/dist/tools/handlers/brand-intake.js +242 -0
- package/dist/tools/handlers/brand-intake.js.map +1 -0
- package/dist/tools/handlers.d.ts +23 -11
- package/dist/tools/handlers.d.ts.map +1 -1
- package/dist/tools/handlers.js +265 -14
- package/dist/tools/handlers.js.map +1 -1
- package/dist/tools/minimal-descriptions.d.ts.map +1 -1
- package/dist/tools/minimal-descriptions.js +5 -3
- package/dist/tools/minimal-descriptions.js.map +1 -1
- 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.map +1 -1
- package/dist/tools/toolkits.js +2 -0
- package/dist/tools/toolkits.js.map +1 -1
- package/dist/types/code-generator.d.ts +63 -2
- package/dist/types/code-generator.d.ts.map +1 -1
- package/dist/types/code-generator.js +533 -49
- package/dist/types/code-generator.js.map +1 -1
- package/dist/types/schemas.d.ts +2199 -640
- package/dist/types/schemas.d.ts.map +1 -1
- package/dist/types/schemas.js +186 -50
- package/dist/types/schemas.js.map +1 -1
- package/dist/utils/a11y.d.ts +2 -0
- package/dist/utils/a11y.d.ts.map +1 -1
- package/dist/utils/a11y.js +1 -1
- package/dist/utils/a11y.js.map +1 -1
- package/dist/utils/beats.d.ts +58 -0
- package/dist/utils/beats.d.ts.map +1 -0
- package/dist/utils/beats.js +110 -0
- package/dist/utils/beats.js.map +1 -0
- package/dist/utils/mcp-log.d.ts +16 -0
- package/dist/utils/mcp-log.d.ts.map +1 -0
- package/dist/utils/mcp-log.js +10 -0
- package/dist/utils/mcp-log.js.map +1 -0
- package/dist/utils/progress.d.ts +28 -0
- package/dist/utils/progress.d.ts.map +1 -0
- package/dist/utils/progress.js +24 -0
- package/dist/utils/progress.js.map +1 -0
- package/dist/utils/svg-size.d.ts +22 -0
- package/dist/utils/svg-size.d.ts.map +1 -0
- package/dist/utils/svg-size.js +43 -0
- package/dist/utils/svg-size.js.map +1 -0
- package/dist/vendor/design/design-style.js +1 -1
- package/manifest.json +9 -1
- package/package.json +7 -4
package/README.de.md
CHANGED
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
|
|
20
20
|
Der PinePaper MCP-Server lässt KI-Assistenten über das Model Context Protocol Grafiken in [PinePaper Studio](https://pinepaper.studio) erstellen und animieren. Funktioniert mit jeder KI, die MCP-Tool-Aufrufe unterstützt (Claude, GPT, Gemini, lokale Modelle usw.).
|
|
21
21
|
|
|
22
|
-
Der Server bietet **
|
|
22
|
+
Der Server bietet **159 Tools**: Zeichnen, Animation, Diagramme, Karten, Typografie, Physik, Bildbearbeitung, Datenvisualisierung und Export:
|
|
23
23
|
|
|
24
24
|
- Text, Formen, Geometrie und komplexe Grafiken erstellen
|
|
25
25
|
- Mit deklarativen **Relationen** animieren statt mit Keyframes
|
package/README.es.md
CHANGED
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
|
|
20
20
|
El servidor MCP de PinePaper permite a los asistentes de IA crear y animar gráficos en [PinePaper Studio](https://pinepaper.studio) a través del Model Context Protocol. Funciona con cualquier IA que soporte llamadas a herramientas MCP (Claude, GPT, Gemini, modelos locales, etc.).
|
|
21
21
|
|
|
22
|
-
Expone **
|
|
22
|
+
Expone **159 herramientas**: dibujo, animación, diagramas, mapas, tipografía, física, edición de imágenes, visualización de datos y exportación:
|
|
23
23
|
|
|
24
24
|
- Crear texto, formas, geometría y gráficos complejos
|
|
25
25
|
- Animar con **relaciones** declarativas en lugar de fotogramas clave
|
package/README.fr.md
CHANGED
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
|
|
20
20
|
Le serveur MCP PinePaper permet aux assistants IA de créer et d'animer des graphiques dans [PinePaper Studio](https://pinepaper.studio) via le Model Context Protocol. Compatible avec toute IA gérant les appels d'outils MCP (Claude, GPT, Gemini, modèles locaux, etc.).
|
|
21
21
|
|
|
22
|
-
Il expose **
|
|
22
|
+
Il expose **159 outils** : dessin, animation, diagrammes, cartes, typographie, physique, retouche d'image, visualisation de données et export :
|
|
23
23
|
|
|
24
24
|
- Créer du texte, des formes, de la géométrie et des graphiques complexes
|
|
25
25
|
- Animer avec des **relations** déclaratives plutôt que des images clés
|
package/README.hi.md
CHANGED
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
|
|
20
20
|
PinePaper MCP सर्वर AI असिस्टेंट्स को Model Context Protocol के ज़रिए [PinePaper Studio](https://pinepaper.studio) में ग्राफ़िक्स बनाने और एनिमेट करने देता है। MCP टूल कॉलिंग वाले किसी भी AI (Claude, GPT, Gemini, लोकल मॉडल आदि) के साथ काम करता है।
|
|
21
21
|
|
|
22
|
-
सर्वर **
|
|
22
|
+
सर्वर **159 टूल** देता है — ड्रॉइंग, एनिमेशन, डायग्राम, नक्शे, टाइपोग्राफ़ी, फिज़िक्स, इमेज एडिटिंग, डेटा विज़ुअलाइज़ेशन और एक्सपोर्ट:
|
|
23
23
|
|
|
24
24
|
- टेक्स्ट, आकृतियाँ, ज्यामिति और जटिल ग्राफ़िक्स बनाना
|
|
25
25
|
- कीफ़्रेम की जगह व्यवहार बताने वाले **रिलेशन** से एनिमेशन
|
package/README.ja.md
CHANGED
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
|
|
20
20
|
PinePaper MCP サーバーは、MCP 経由で AI アシスタントが [PinePaper Studio](https://pinepaper.studio) 上にグラフィックを作成・アニメーションさせるためのサーバーです。MCP ツールコールに対応した AI(Claude、GPT、Gemini、ローカルモデルなど)で動作します。
|
|
21
21
|
|
|
22
|
-
**
|
|
22
|
+
**159 個のツール**を提供 — 描画・アニメーション・図・地図・タイポグラフィ・物理・画像編集・データ可視化・エクスポート:
|
|
23
23
|
|
|
24
24
|
- テキスト、図形、ジオメトリ、複雑なグラフィックの作成
|
|
25
25
|
- キーフレームではなく、ふるまいを宣言する**リレーション**でアニメーション
|
package/README.ko.md
CHANGED
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
|
|
20
20
|
PinePaper MCP 서버는 AI 어시스턴트가 MCP를 통해 [PinePaper Studio](https://pinepaper.studio)에서 그래픽을 만들고 애니메이션하게 해줍니다. MCP 툴 콜을 지원하는 모든 AI(Claude, GPT, Gemini, 로컬 모델 등)와 호환됩니다.
|
|
21
21
|
|
|
22
|
-
**
|
|
22
|
+
**159개의 툴** 제공 — 드로잉, 애니메이션, 다이어그램, 지도, 타이포그래피, 물리, 이미지 편집, 데이터 시각화, 내보내기:
|
|
23
23
|
|
|
24
24
|
- 텍스트·도형·기하·복잡한 그래픽 생성
|
|
25
25
|
- 키프레임 대신 행동을 선언하는 **릴레이션**으로 애니메이션
|
package/README.md
CHANGED
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
|
|
31
31
|
PinePaper MCP Server enables AI assistants to create and animate graphics in [PinePaper Studio](https://pinepaper.studio) via the Model Context Protocol (MCP). Works with any AI that supports MCP tool calling (Claude, GPT, Gemini, local models, etc.).
|
|
32
32
|
|
|
33
|
-
The server exposes **
|
|
33
|
+
The server exposes **159 tools** across drawing, animation, diagrams, maps, typography, physics, image editing, data visualization, and export. Using natural language, you can:
|
|
34
34
|
|
|
35
35
|
- Create geometric shapes, text collages, diagrams, and data charts
|
|
36
36
|
- Apply 37+ character-level text effects and 28+ vertex deformation presets
|
|
@@ -41,7 +41,7 @@ The server exposes **157 tools** across drawing, animation, diagrams, maps, typo
|
|
|
41
41
|
|
|
42
42
|
## Running it: local or hosted
|
|
43
43
|
|
|
44
|
-
**Local is free and complete.** Every one of the
|
|
44
|
+
**Local is free and complete.** Every one of the 159 tools works when you run
|
|
45
45
|
this server yourself. There is no reduced tier and nothing held back.
|
|
46
46
|
|
|
47
47
|
What it needs:
|
|
@@ -246,6 +246,142 @@ If you do not want an agent executing anything, `code` mode is a first-class pat
|
|
|
246
246
|
- Puppeteer mode launches Chrome with `--no-sandbox` and `--disable-setuid-sandbox`. That is routine for headless automation and it does weaken Chrome's own process sandbox. If that matters where you are running it, use `code` mode or put the server in a container.
|
|
247
247
|
- Puppeteer itself is an **optional** peer dependency, kept out of the default tree precisely because a headless browser plus an install script is what scanners flag hardest. Install it only if you want the executing mode.
|
|
248
248
|
|
|
249
|
+
## What's new in 1.6.18
|
|
250
|
+
|
|
251
|
+
### New: spring easings, the standard easing set, and custom curves
|
|
252
|
+
|
|
253
|
+
Keyframes take three spring easings: `spring` (settles with no overshoot),
|
|
254
|
+
`springSnappy` (quick, one small overshoot) and `springPlayful` (bouncy, a few
|
|
255
|
+
visible wobbles).
|
|
256
|
+
|
|
257
|
+
The standard easings are here too: sine, quad, cubic, quart, quint, expo,
|
|
258
|
+
circ and back as `easeIn…`, `easeOut…` and `easeInOut…` (for example
|
|
259
|
+
`easeOutExpo`, `easeInOutQuart`), plus in and out bounce and elastic.
|
|
260
|
+
`pinepaper_get_available_easings` lists every name.
|
|
261
|
+
|
|
262
|
+
`pinepaper_keyframe_animate` and `pinepaper_camera_animate` also take a custom
|
|
263
|
+
cubic-bezier `[x1, y1, x2, y2]`: x within 0..1, y may go outside it for
|
|
264
|
+
overshoot.
|
|
265
|
+
|
|
266
|
+
Every easing renders exactly in video, GIF and APNG. Lottie and CSS get the
|
|
267
|
+
closest single curve, so `springPlayful` loses its wobble there and the in-out
|
|
268
|
+
quart, quint, expo and circ curves are within a few percent.
|
|
269
|
+
|
|
270
|
+
### New: look at your own animation
|
|
271
|
+
|
|
272
|
+
`pinepaper_capture_frames` takes `sheet`: many frames tiled into one small
|
|
273
|
+
image, saved to a file, with a rubric to score it against (hook, phone
|
|
274
|
+
readability, motion, variety, composition, brand, sound sync). Choose the
|
|
275
|
+
frames by time, every N seconds, a strip around a moment, or the loop's last
|
|
276
|
+
frame beside its first. Tiles are 360 px wide by default, the width of a
|
|
277
|
+
phone.
|
|
278
|
+
|
|
279
|
+
### New: make one like this
|
|
280
|
+
|
|
281
|
+
`pinepaper_media` takes `analyze_reference`: give it an uploaded reference
|
|
282
|
+
video and it measures the format: where it cuts, how long each shot runs,
|
|
283
|
+
each shot's colours, how fast it opens, and its beat. `remake_from_reference`
|
|
284
|
+
then builds a new piece on that structure in your own words. Nothing of the
|
|
285
|
+
reference's footage, words or sound is copied.
|
|
286
|
+
|
|
287
|
+
### New: start from the real brand
|
|
288
|
+
|
|
289
|
+
`pinepaper_brand_kit` takes `from_url`: give it a product's site and it saves
|
|
290
|
+
screenshots and the logo, and proposes a brand kit from the colours and fonts
|
|
291
|
+
the site actually uses, ready to review and apply. The site is read in a
|
|
292
|
+
separate browser context; your canvas is not touched.
|
|
293
|
+
|
|
294
|
+
### New: watercolour, oil paint and cut paper
|
|
295
|
+
|
|
296
|
+
`pinepaper_design_medium` takes `apply`: render any shape in watercolour, oil
|
|
297
|
+
paint, cut paper, thread or hatching, with that medium's own options. A medium
|
|
298
|
+
the studio cannot make, or one that is a brush rather than a fill, is refused
|
|
299
|
+
with the reason.
|
|
300
|
+
|
|
301
|
+
### New: motion blur
|
|
302
|
+
|
|
303
|
+
`pinepaper_agent_export` takes `motionBlur` for MP4 and WebM: each frame is
|
|
304
|
+
rendered several times across the shutter and averaged, so fast movement
|
|
305
|
+
smears the way it does on camera instead of strobing. It multiplies render
|
|
306
|
+
time; `estimateOnly` reports by how much before you commit to it.
|
|
307
|
+
|
|
308
|
+
### Changed: plan generations before paying for them
|
|
309
|
+
|
|
310
|
+
`pinepaper_generate` and `pinepaper_generate_estimate` now tell agents to plan
|
|
311
|
+
the whole timeline and price the whole plan before the first paid call, to
|
|
312
|
+
reuse images already generated, and to pick video lengths the model supports
|
|
313
|
+
rather than generating long and cropping. `pinepaper_beat_cuts` treats a
|
|
314
|
+
generated song as the backbone of the edit, used whole.
|
|
315
|
+
|
|
316
|
+
### Fixed
|
|
317
|
+
|
|
318
|
+
- The scene validator no longer flags valid easings as unknown.
|
|
319
|
+
- `pinepaper_agent_export` always saves PNG, JPG and WebP to a file and
|
|
320
|
+
returns its path. Small images used to come back inline as base64, which
|
|
321
|
+
could exceed a client's response limit.
|
|
322
|
+
- `pinepaper_execute_custom_code`: when the code fails part-way, the items it
|
|
323
|
+
created are removed, so the scene is not left half-built. The error says
|
|
324
|
+
what was removed. Edits to items that already existed are not reverted. The
|
|
325
|
+
4-second loop limit is this tool's, per call: split long work across several
|
|
326
|
+
calls.
|
|
327
|
+
- `pinepaper_design_medium` `apply_thread`: the spine points format is
|
|
328
|
+
documented (`{x, y}` or `[x, y]`).
|
|
329
|
+
- `pinepaper_world3d`: colours take hex (`"#03050c"`) everywhere: the world's
|
|
330
|
+
sky, fog, light and ground colours, and material and light colours. A
|
|
331
|
+
refused `configure` now says why, naming the key. `ground_height` takes
|
|
332
|
+
`{x, z}`. `create` lists the configurable parameters by name.
|
|
333
|
+
- A browser session lost while idle recovers by itself: `pinepaper_refresh_page`
|
|
334
|
+
and every other tool relaunch the browser when no page answers, restore the
|
|
335
|
+
canvas size, and say in the result that the canvas was reset.
|
|
336
|
+
- `pinepaper_world3d` `extrude_path` takes `upright` (stand a drawing up, like
|
|
337
|
+
a sign) and `placement` (`centered`, the default, stands the mesh on the
|
|
338
|
+
ground at the point you give). JPG and WebP stills of a 3D world scene show
|
|
339
|
+
the world rather than a white frame.
|
|
340
|
+
|
|
341
|
+
## What's new in 1.6.17
|
|
342
|
+
|
|
343
|
+
### New: tell an agent "at 4 s, make it orange"
|
|
344
|
+
|
|
345
|
+
`pinepaper_modify_item` takes `atTime`: the change is written as a keyframe at
|
|
346
|
+
that moment, the same as dragging with auto-key on, eased from the previous
|
|
347
|
+
value and without disturbing the rest of the animation.
|
|
348
|
+
`pinepaper_query_mutations` shows a property's values over time.
|
|
349
|
+
|
|
350
|
+
### New: cuts on the beat
|
|
351
|
+
|
|
352
|
+
`pinepaper_beat_cuts` analyses a music track, fits a beat grid and returns cut
|
|
353
|
+
points on every beat, every bar or every N beats — and can split a clip at each.
|
|
354
|
+
When the tempo is uncertain it says so and lists the likely alternatives;
|
|
355
|
+
`bpm` or `bpmHint` settles it.
|
|
356
|
+
|
|
357
|
+
### New: exact frame counts, and larger canvases
|
|
358
|
+
|
|
359
|
+
- `pinepaper_agent_export` takes `frames` for an exact frame count (a duration
|
|
360
|
+
rounds up), for segments that must line up.
|
|
361
|
+
- Canvases up to 16384 px per side, for digital out-of-home and projection;
|
|
362
|
+
above 8192 the result notes that Safari and iOS may not manage it.
|
|
363
|
+
- `pinepaper_import_image` takes `maxEdge` (or `'native'`) and `nativeSize`, and
|
|
364
|
+
says when the studio stored an image smaller than its source.
|
|
365
|
+
- `pinepaper_media` `upload_video` takes `fit` (`contain`, `cover`, `none`), and
|
|
366
|
+
`scale` is documented as relative to it.
|
|
367
|
+
|
|
368
|
+
### Changed: exports say more about what they produced
|
|
369
|
+
|
|
370
|
+
- When an MP4 cannot be made at the requested size, the file is named by what it
|
|
371
|
+
is (WebM) and a warning says why.
|
|
372
|
+
- A video whose animation did not play, or whose encoder froze, is flagged.
|
|
373
|
+
- Asking for ProRes or HAP explains the route that works (a PNG sequence).
|
|
374
|
+
- Frame captures, region stills and flash checks wait for video on screen, and
|
|
375
|
+
report whether they could.
|
|
376
|
+
- The engine's structured warnings reach the caller whole.
|
|
377
|
+
|
|
378
|
+
### Fixed
|
|
379
|
+
|
|
380
|
+
- `pinepaper_accessibility_check` judged text only at the current playhead, so
|
|
381
|
+
timed captions could pass unchecked; it now samples the timeline, and says
|
|
382
|
+
when no text was visible rather than passing.
|
|
383
|
+
- `pinepaper_agent_export` accepts `fps` and `scale` for APNG.
|
|
384
|
+
|
|
249
385
|
## What's new in 1.6.16
|
|
250
386
|
|
|
251
387
|
### New: video editing on the timeline
|
|
@@ -1226,7 +1362,7 @@ Fourteen new tools (121 → 135) and new actions across the surface — the rele
|
|
|
1226
1362
|
|
|
1227
1363
|
## Toolkits & Token Budget
|
|
1228
1364
|
|
|
1229
|
-
|
|
1365
|
+
159 tools is a lot of context. The server ships a **toolkit** system that serves only the tools a given client needs, plus a **verbosity** system that controls how long each tool description is.
|
|
1230
1366
|
|
|
1231
1367
|
**Toolkit profiles** (`PINEPAPER_TOOLKIT`):
|
|
1232
1368
|
|
|
@@ -1431,7 +1567,7 @@ Generate instruction/code pairs for LLM fine-tuning:
|
|
|
1431
1567
|
|
|
1432
1568
|
## Tools Reference
|
|
1433
1569
|
|
|
1434
|
-
All
|
|
1570
|
+
All 159 tools, grouped by the tag used for toolkit filtering.
|
|
1435
1571
|
|
|
1436
1572
|
### Canvas (`canvas`)
|
|
1437
1573
|
| Tool | Description |
|
|
@@ -1653,6 +1789,8 @@ All 157 tools, grouped by the tag used for toolkit filtering.
|
|
|
1653
1789
|
| `pinepaper_analyze_design` | Analyze design quality |
|
|
1654
1790
|
| `pinepaper_validate_design` | Validate against design rules |
|
|
1655
1791
|
| `pinepaper_validate` | General validation |
|
|
1792
|
+
| `pinepaper_beat_cuts` | Cut points on the music's beats or bars; split a clip at each |
|
|
1793
|
+
| `pinepaper_query_mutations` | A property's keyframe series over time |
|
|
1656
1794
|
| `pinepaper_accessibility_check` | Text contrast and flashing (WCAG), as a heuristic screen |
|
|
1657
1795
|
| `pinepaper_validate_scene` | Validate scene integrity |
|
|
1658
1796
|
| `pinepaper_instantiate_ontology` | Compile a pp: design graph into a scene |
|
package/README.pt-BR.md
CHANGED
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
|
|
20
20
|
O servidor MCP do PinePaper permite que assistentes de IA criem e animem gráficos no [PinePaper Studio](https://pinepaper.studio) via Model Context Protocol. Funciona com qualquer IA que suporte chamadas de ferramenta MCP (Claude, GPT, Gemini, modelos locais etc.).
|
|
21
21
|
|
|
22
|
-
São **
|
|
22
|
+
São **159 ferramentas**: desenho, animação, diagramas, mapas, tipografia, física, edição de imagens, visualização de dados e exportação:
|
|
23
23
|
|
|
24
24
|
- Criar texto, formas, geometria e gráficos complexos
|
|
25
25
|
- Animar com **relações** declarativas em vez de keyframes
|
package/README.zh-CN.md
CHANGED
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
|
|
20
20
|
PinePaper MCP 服务器让 AI 助手通过 MCP 协议在 [PinePaper Studio](https://pinepaper.studio) 中创建和驱动图形动画。兼容任何支持 MCP 工具调用的 AI(Claude、GPT、Gemini、本地模型等)。
|
|
21
21
|
|
|
22
|
-
服务器提供 **
|
|
22
|
+
服务器提供 **159 个工具**,覆盖绘图、动画、图表、地图、排版、物理、图像编辑、数据可视化与导出:
|
|
23
23
|
|
|
24
24
|
- 创建文本、形状、几何图形与复杂图稿
|
|
25
25
|
- 用行为驱动的**关系(relations)**做动画,而不是逐帧关键帧
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
* Controls a real browser instance running PinePaper Studio.
|
|
5
5
|
* Executes code directly via page.evaluate() and provides screenshots.
|
|
6
6
|
*/
|
|
7
|
+
import type { Page } from 'puppeteer';
|
|
7
8
|
/**
|
|
8
9
|
* What a navigation waits for. Puppeteer's own union, spelled out here so the
|
|
9
10
|
* env var can be validated against it without importing puppeteer — which is
|
|
@@ -123,6 +124,16 @@ export interface ExecuteResult {
|
|
|
123
124
|
* keep referencing item ids from before the reload. undefined = unknown.
|
|
124
125
|
*/
|
|
125
126
|
canvasReset?: boolean;
|
|
127
|
+
/**
|
|
128
|
+
* Set alongside `recovered` when no live tab could be re-bound and the
|
|
129
|
+
* browser was RELAUNCHED: the scene is gone for certain (canvasReset true).
|
|
130
|
+
*/
|
|
131
|
+
relaunched?: boolean;
|
|
132
|
+
/** The canvas size put back after a relaunch, when one was known. */
|
|
133
|
+
canvasSizeRestored?: {
|
|
134
|
+
width: number;
|
|
135
|
+
height: number;
|
|
136
|
+
};
|
|
126
137
|
}
|
|
127
138
|
/**
|
|
128
139
|
* Is PinePaper Studio actually usable? Evaluated IN THE PAGE, so it closes over
|
|
@@ -182,6 +193,28 @@ export declare class PinePaperBrowserController {
|
|
|
182
193
|
* Check if connected to browser
|
|
183
194
|
*/
|
|
184
195
|
get connected(): boolean;
|
|
196
|
+
/**
|
|
197
|
+
* The studio's video export, if one is running: its 0..100 progress. Read
|
|
198
|
+
* concurrently with the call that started it (the export awaits between
|
|
199
|
+
* frames, so a second evaluate gets a turn). null when nothing is exporting
|
|
200
|
+
* or the page cannot be read.
|
|
201
|
+
*/
|
|
202
|
+
exportStatus(): Promise<{
|
|
203
|
+
percent: number;
|
|
204
|
+
} | null>;
|
|
205
|
+
/**
|
|
206
|
+
* Stop a running video export (VideoExporter.cancel: closes the encoders and
|
|
207
|
+
* the muxer). For a cancelled MCP request, so the studio does not keep
|
|
208
|
+
* rendering minutes of video nobody will receive. True if one was stopped.
|
|
209
|
+
*/
|
|
210
|
+
cancelExport(): Promise<boolean>;
|
|
211
|
+
/**
|
|
212
|
+
* Run `fn` on a page in a fresh, ISOLATED browser context (its own cookies
|
|
213
|
+
* and storage), closed afterwards. For reading a site that is not the
|
|
214
|
+
* studio (brand intake): the studio tab, and the canvas in it, is never
|
|
215
|
+
* navigated away, and the site's cookies never mix with the studio's.
|
|
216
|
+
*/
|
|
217
|
+
withIsolatedPage<T>(fn: (page: Page) => Promise<T>): Promise<T>;
|
|
185
218
|
/**
|
|
186
219
|
* Get current studio URL (always includes agent parameters for MCP server)
|
|
187
220
|
*/
|
|
@@ -229,6 +262,20 @@ export declare class PinePaperBrowserController {
|
|
|
229
262
|
* @returns true when a responsive page was re-bound.
|
|
230
263
|
*/
|
|
231
264
|
private reacquirePage;
|
|
265
|
+
/**
|
|
266
|
+
* The last canvas size seen on a healthy page. A relaunched browser comes
|
|
267
|
+
* up at the studio's default (800x600), so without this a session that
|
|
268
|
+
* died idle came back at the wrong size, silently (M6, 2026-10-02).
|
|
269
|
+
*/
|
|
270
|
+
private lastCanvasSize;
|
|
271
|
+
private rememberCanvasSize;
|
|
272
|
+
/**
|
|
273
|
+
* Get a working page back after a stale-frame error. First re-bind a live
|
|
274
|
+
* tab (the scene may survive); if none answers, as after days idle when
|
|
275
|
+
* every frame is detached, relaunch ONCE and put the canvas size back.
|
|
276
|
+
* 'relaunched' means the scene is gone. false means even that failed.
|
|
277
|
+
*/
|
|
278
|
+
private recoverSession;
|
|
232
279
|
/** Number of registry items currently on the canvas, or null if unknown. */
|
|
233
280
|
private canvasItemCount;
|
|
234
281
|
/**
|
|
@@ -255,7 +302,20 @@ export declare class PinePaperBrowserController {
|
|
|
255
302
|
* Refresh the page and wait for PinePaper to be ready again.
|
|
256
303
|
* This is the most reliable way to get a clean canvas.
|
|
257
304
|
*/
|
|
258
|
-
|
|
305
|
+
/**
|
|
306
|
+
* Reload the studio. The tool whose job is recovery could not recover: on a
|
|
307
|
+
* detached frame, page.reload() threw the same "detached Frame" error as
|
|
308
|
+
* every other call (M6, after ~2 days idle). A stale page is now recovered
|
|
309
|
+
* first: re-bound and reloaded, or the browser relaunched at the remembered
|
|
310
|
+
* canvas size. The return says which, so the caller knows the scene is gone.
|
|
311
|
+
*/
|
|
312
|
+
refreshPage(): Promise<{
|
|
313
|
+
relaunched?: boolean;
|
|
314
|
+
canvasSizeRestored?: {
|
|
315
|
+
width: number;
|
|
316
|
+
height: number;
|
|
317
|
+
};
|
|
318
|
+
}>;
|
|
259
319
|
/**
|
|
260
320
|
* Check if PinePaper API is available
|
|
261
321
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"puppeteer-controller.d.ts","sourceRoot":"","sources":["../../src/browser/puppeteer-controller.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;
|
|
1
|
+
{"version":3,"file":"puppeteer-controller.d.ts","sourceRoot":"","sources":["../../src/browser/puppeteer-controller.ts"],"names":[],"mappings":"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"}
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
* Controls a real browser instance running PinePaper Studio.
|
|
5
5
|
* Executes code directly via page.evaluate() and provides screenshots.
|
|
6
6
|
*/
|
|
7
|
+
import { mcpLog } from '../utils/mcp-log.js';
|
|
7
8
|
import { LAZY_HEAVY_SUBSYSTEMS, LAZY_HEAVY_CLASSES, ENGINE_SURFACE } from '../tools/engine-surface.js';
|
|
8
9
|
export const PAGE_WAIT_UNTIL = ['load', 'domcontentloaded', 'networkidle0', 'networkidle2'];
|
|
9
10
|
/**
|
|
@@ -157,6 +158,69 @@ export class PinePaperBrowserController {
|
|
|
157
158
|
get connected() {
|
|
158
159
|
return this.isConnected && this.page !== null;
|
|
159
160
|
}
|
|
161
|
+
/**
|
|
162
|
+
* The studio's video export, if one is running: its 0..100 progress. Read
|
|
163
|
+
* concurrently with the call that started it (the export awaits between
|
|
164
|
+
* frames, so a second evaluate gets a turn). null when nothing is exporting
|
|
165
|
+
* or the page cannot be read.
|
|
166
|
+
*/
|
|
167
|
+
async exportStatus() {
|
|
168
|
+
if (!this.page || !this.isConnected)
|
|
169
|
+
return null;
|
|
170
|
+
try {
|
|
171
|
+
return await this.page.evaluate(() => {
|
|
172
|
+
const app = window.app || window.PinePaper;
|
|
173
|
+
const ve = app && app.exportEngine && app.exportEngine.videoExporter;
|
|
174
|
+
if (!ve || !ve.isRecording)
|
|
175
|
+
return null;
|
|
176
|
+
const p = Number(ve.progress);
|
|
177
|
+
return { percent: Number.isFinite(p) ? Math.max(0, Math.min(100, p)) : 0 };
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
catch {
|
|
181
|
+
return null;
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
/**
|
|
185
|
+
* Stop a running video export (VideoExporter.cancel: closes the encoders and
|
|
186
|
+
* the muxer). For a cancelled MCP request, so the studio does not keep
|
|
187
|
+
* rendering minutes of video nobody will receive. True if one was stopped.
|
|
188
|
+
*/
|
|
189
|
+
async cancelExport() {
|
|
190
|
+
if (!this.page || !this.isConnected)
|
|
191
|
+
return false;
|
|
192
|
+
try {
|
|
193
|
+
return await this.page.evaluate(async () => {
|
|
194
|
+
const app = window.app || window.PinePaper;
|
|
195
|
+
const ve = app && app.exportEngine && app.exportEngine.videoExporter;
|
|
196
|
+
if (!ve || !ve.isRecording || typeof ve.cancel !== 'function')
|
|
197
|
+
return false;
|
|
198
|
+
await ve.cancel();
|
|
199
|
+
return true;
|
|
200
|
+
});
|
|
201
|
+
}
|
|
202
|
+
catch {
|
|
203
|
+
return false;
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
/**
|
|
207
|
+
* Run `fn` on a page in a fresh, ISOLATED browser context (its own cookies
|
|
208
|
+
* and storage), closed afterwards. For reading a site that is not the
|
|
209
|
+
* studio (brand intake): the studio tab, and the canvas in it, is never
|
|
210
|
+
* navigated away, and the site's cookies never mix with the studio's.
|
|
211
|
+
*/
|
|
212
|
+
async withIsolatedPage(fn) {
|
|
213
|
+
if (!this.browser)
|
|
214
|
+
throw new Error('Not connected to browser');
|
|
215
|
+
const context = await this.browser.createBrowserContext();
|
|
216
|
+
try {
|
|
217
|
+
const page = await context.newPage();
|
|
218
|
+
return await fn(page);
|
|
219
|
+
}
|
|
220
|
+
finally {
|
|
221
|
+
await context.close().catch(() => { });
|
|
222
|
+
}
|
|
223
|
+
}
|
|
160
224
|
/**
|
|
161
225
|
* Get current studio URL (always includes agent parameters for MCP server)
|
|
162
226
|
*/
|
|
@@ -340,6 +404,68 @@ export class PinePaperBrowserController {
|
|
|
340
404
|
return false;
|
|
341
405
|
}
|
|
342
406
|
}
|
|
407
|
+
/**
|
|
408
|
+
* The last canvas size seen on a healthy page. A relaunched browser comes
|
|
409
|
+
* up at the studio's default (800x600), so without this a session that
|
|
410
|
+
* died idle came back at the wrong size, silently (M6, 2026-10-02).
|
|
411
|
+
*/
|
|
412
|
+
lastCanvasSize = null;
|
|
413
|
+
async rememberCanvasSize() {
|
|
414
|
+
if (!this.page)
|
|
415
|
+
return;
|
|
416
|
+
try {
|
|
417
|
+
const size = await this.page.evaluate(() => {
|
|
418
|
+
const app = window.app || window.PinePaper;
|
|
419
|
+
const s = app && typeof app.getCanvasSize === 'function' ? app.getCanvasSize() : null;
|
|
420
|
+
return s && s.width > 0 && s.height > 0 ? { width: s.width, height: s.height } : null;
|
|
421
|
+
});
|
|
422
|
+
if (size)
|
|
423
|
+
this.lastCanvasSize = size;
|
|
424
|
+
}
|
|
425
|
+
catch { /* keep the last known size */ }
|
|
426
|
+
}
|
|
427
|
+
/**
|
|
428
|
+
* Get a working page back after a stale-frame error. First re-bind a live
|
|
429
|
+
* tab (the scene may survive); if none answers, as after days idle when
|
|
430
|
+
* every frame is detached, relaunch ONCE and put the canvas size back.
|
|
431
|
+
* 'relaunched' means the scene is gone. false means even that failed.
|
|
432
|
+
*/
|
|
433
|
+
async recoverSession() {
|
|
434
|
+
if (await this.reacquirePage())
|
|
435
|
+
return { kind: 'reacquired' };
|
|
436
|
+
const size = this.lastCanvasSize;
|
|
437
|
+
try {
|
|
438
|
+
await this.disconnect();
|
|
439
|
+
await this.connect();
|
|
440
|
+
}
|
|
441
|
+
catch (e) {
|
|
442
|
+
console.error('[PinePaper] Relaunch after a lost session failed:', e instanceof Error ? e.message : e);
|
|
443
|
+
mcpLog('error', { event: 'session_lost', message: 'The browser session was lost and could not be relaunched: call pinepaper_browser_disconnect, then pinepaper_browser_connect.' });
|
|
444
|
+
return false;
|
|
445
|
+
}
|
|
446
|
+
if (!this.page || !this.isConnected)
|
|
447
|
+
return false;
|
|
448
|
+
let restored;
|
|
449
|
+
if (size) {
|
|
450
|
+
try {
|
|
451
|
+
const ok = await this.page.evaluate((w, h) => {
|
|
452
|
+
const app = window.app || window.PinePaper;
|
|
453
|
+
if (!app || typeof app.setCanvasSize !== 'function')
|
|
454
|
+
return false;
|
|
455
|
+
app.setCanvasSize(w, h);
|
|
456
|
+
return true;
|
|
457
|
+
}, size.width, size.height);
|
|
458
|
+
if (ok) {
|
|
459
|
+
restored = size;
|
|
460
|
+
this.lastCanvasSize = size;
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
catch { /* reported as not restored */ }
|
|
464
|
+
}
|
|
465
|
+
console.error('[PinePaper] Session lost; browser relaunched' + (restored ? ` at ${restored.width}x${restored.height}` : ''));
|
|
466
|
+
mcpLog('warning', { event: 'session_relaunched', message: 'The browser session was lost; the browser was relaunched and the canvas is empty.', ...(restored ? { canvasSizeRestored: restored } : {}) });
|
|
467
|
+
return { kind: 'relaunched', ...(restored ? { canvasSizeRestored: restored } : {}) };
|
|
468
|
+
}
|
|
343
469
|
/** Number of registry items currently on the canvas, or null if unknown. */
|
|
344
470
|
async canvasItemCount() {
|
|
345
471
|
if (!this.page)
|
|
@@ -538,6 +664,8 @@ export class PinePaperBrowserController {
|
|
|
538
664
|
if (takeScreenshot && result.success) {
|
|
539
665
|
screenshot = await this.takeScreenshot();
|
|
540
666
|
}
|
|
667
|
+
if (result.success)
|
|
668
|
+
await this.rememberCanvasSize();
|
|
541
669
|
return {
|
|
542
670
|
...result,
|
|
543
671
|
screenshot,
|
|
@@ -548,7 +676,8 @@ export class PinePaperBrowserController {
|
|
|
548
676
|
// so every later call hit the same error until the caller manually
|
|
549
677
|
// disconnected — and disconnect+connect relaunches the browser, losing
|
|
550
678
|
// the canvas. Re-bind to the live page and retry ONCE instead.
|
|
551
|
-
|
|
679
|
+
const recovery = PinePaperBrowserController.isStaleFrameError(error) ? await this.recoverSession() : false;
|
|
680
|
+
if (recovery) {
|
|
552
681
|
try {
|
|
553
682
|
// Forward `options`: a recovered export that silently reverted to the
|
|
554
683
|
// 10s governor budget would die at the same place the retry exists to
|
|
@@ -557,6 +686,15 @@ export class PinePaperBrowserController {
|
|
|
557
686
|
// The page reloaded under us, so the scene may be gone even though
|
|
558
687
|
// execution now succeeds. Say so explicitly — silently continuing
|
|
559
688
|
// against vanished item ids is how this bug wasted a whole rebuild.
|
|
689
|
+
if (recovery.kind === 'relaunched') {
|
|
690
|
+
return {
|
|
691
|
+
...retry,
|
|
692
|
+
recovered: true,
|
|
693
|
+
relaunched: true,
|
|
694
|
+
canvasReset: true,
|
|
695
|
+
...(recovery.canvasSizeRestored ? { canvasSizeRestored: recovery.canvasSizeRestored } : {}),
|
|
696
|
+
};
|
|
697
|
+
}
|
|
560
698
|
const items = await this.canvasItemCount();
|
|
561
699
|
return {
|
|
562
700
|
...retry,
|
|
@@ -572,9 +710,12 @@ export class PinePaperBrowserController {
|
|
|
572
710
|
};
|
|
573
711
|
}
|
|
574
712
|
}
|
|
713
|
+
const message = error instanceof Error ? error.message : 'Unknown execution error';
|
|
575
714
|
return {
|
|
576
715
|
success: false,
|
|
577
|
-
error:
|
|
716
|
+
error: PinePaperBrowserController.isStaleFrameError(error)
|
|
717
|
+
? `${message}. The browser session was lost and could not be recovered automatically: call pinepaper_browser_disconnect, then pinepaper_browser_connect.`
|
|
718
|
+
: message,
|
|
578
719
|
};
|
|
579
720
|
}
|
|
580
721
|
}
|
|
@@ -641,18 +782,39 @@ export class PinePaperBrowserController {
|
|
|
641
782
|
* Refresh the page and wait for PinePaper to be ready again.
|
|
642
783
|
* This is the most reliable way to get a clean canvas.
|
|
643
784
|
*/
|
|
785
|
+
/**
|
|
786
|
+
* Reload the studio. The tool whose job is recovery could not recover: on a
|
|
787
|
+
* detached frame, page.reload() threw the same "detached Frame" error as
|
|
788
|
+
* every other call (M6, after ~2 days idle). A stale page is now recovered
|
|
789
|
+
* first: re-bound and reloaded, or the browser relaunched at the remembered
|
|
790
|
+
* canvas size. The return says which, so the caller knows the scene is gone.
|
|
791
|
+
*/
|
|
644
792
|
async refreshPage() {
|
|
645
793
|
if (!this.page) {
|
|
646
794
|
throw new Error('Not connected to browser');
|
|
647
795
|
}
|
|
648
796
|
console.error('[PinePaper] Refreshing page...');
|
|
649
|
-
|
|
650
|
-
waitUntil: this.config.waitUntil,
|
|
651
|
-
|
|
652
|
-
|
|
797
|
+
try {
|
|
798
|
+
await this.page.reload({ waitUntil: this.config.waitUntil, timeout: this.config.timeout });
|
|
799
|
+
}
|
|
800
|
+
catch (error) {
|
|
801
|
+
if (!PinePaperBrowserController.isStaleFrameError(error))
|
|
802
|
+
throw error;
|
|
803
|
+
const recovery = await this.recoverSession();
|
|
804
|
+
if (!recovery) {
|
|
805
|
+
throw new Error('The browser session was lost and could not be recovered: call pinepaper_browser_disconnect, then pinepaper_browser_connect.');
|
|
806
|
+
}
|
|
807
|
+
if (recovery.kind === 'relaunched') {
|
|
808
|
+
console.error('[PinePaper] Page refreshed by relaunching the browser');
|
|
809
|
+
return { relaunched: true, ...(recovery.canvasSizeRestored ? { canvasSizeRestored: recovery.canvasSizeRestored } : {}) };
|
|
810
|
+
}
|
|
811
|
+
await this.page.reload({ waitUntil: this.config.waitUntil, timeout: this.config.timeout });
|
|
812
|
+
}
|
|
653
813
|
// Wait for PinePaper to be ready again
|
|
654
814
|
await this.waitForPinePaper();
|
|
815
|
+
await this.rememberCanvasSize();
|
|
655
816
|
console.error('[PinePaper] Page refreshed and ready');
|
|
817
|
+
return {};
|
|
656
818
|
}
|
|
657
819
|
/**
|
|
658
820
|
* Check if PinePaper API is available
|