premiere-pro-mcp 1.22.0 → 1.24.0
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/CHANGELOG.md +39 -0
- package/README.md +41 -20
- package/after-effects-cep-plugin/CSXS/manifest.xml +3 -3
- package/artifacts/MCPBridgeCEP.zxp +0 -0
- package/cep-plugin/CSXS/manifest.xml +3 -3
- package/cep-plugin/index.html +1 -1
- package/cep-plugin/main.js +2 -0
- package/cep-plugin/updater.cjs +1 -1
- package/dist/ai/caption-authoring.d.ts +95 -0
- package/dist/ai/caption-authoring.js +213 -0
- package/dist/ai/editorial-review.d.ts +7 -7
- package/dist/ai/editorial-workflows.d.ts +197 -0
- package/dist/ai/editorial-workflows.js +199 -0
- package/dist/ai/exact-time.d.ts +39 -0
- package/dist/ai/exact-time.js +88 -0
- package/dist/ai/timeline-contract.d.ts +128 -0
- package/dist/ai/timeline-contract.js +263 -0
- package/dist/bridge/after-effects-bridge.js +4 -0
- package/dist/bridge/file-bridge.d.ts +9 -0
- package/dist/bridge/file-bridge.js +98 -11
- package/dist/bridge/host-lease.d.ts +17 -0
- package/dist/bridge/host-lease.js +157 -0
- package/dist/bridge/project-guard.d.ts +32 -0
- package/dist/bridge/project-guard.js +51 -0
- package/dist/bridge/script-builder.js +188 -17
- package/dist/bridge/uxp-websocket-bridge.d.ts +17 -0
- package/dist/bridge/uxp-websocket-bridge.js +83 -14
- package/dist/index.js +1 -1
- package/dist/interchange/bounded-file.d.ts +23 -0
- package/dist/interchange/bounded-file.js +85 -0
- package/dist/interchange/evidence.d.ts +86 -0
- package/dist/interchange/evidence.js +239 -0
- package/dist/interchange/facility.d.ts +81 -0
- package/dist/interchange/facility.js +153 -0
- package/dist/interchange/otio.d.ts +62 -0
- package/dist/interchange/otio.js +186 -0
- package/dist/platform-capabilities.d.ts +1 -0
- package/dist/platform-capabilities.js +2 -1
- package/dist/security/capabilities.js +43 -0
- package/dist/server.d.ts +2 -1
- package/dist/server.js +124 -16
- package/dist/tools/caption-authoring.d.ts +162 -5
- package/dist/tools/caption-authoring.js +81 -28
- package/dist/tools/captions.d.ts +1 -0
- package/dist/tools/captions.js +45 -36
- package/dist/tools/competitor-gaps.js +2 -0
- package/dist/tools/execution-workflows.d.ts +567 -0
- package/dist/tools/execution-workflows.js +395 -0
- package/dist/tools/export.js +32 -5
- package/dist/tools/extended-edit-plans.d.ts +140 -0
- package/dist/tools/extended-edit-plans.js +179 -0
- package/dist/tools/health.d.ts +1 -0
- package/dist/tools/interchange-workflows.d.ts +233 -0
- package/dist/tools/interchange-workflows.js +106 -0
- package/dist/tools/media-analysis-cache.d.ts +14 -0
- package/dist/tools/media-analysis-cache.js +29 -0
- package/dist/tools/media-analysis.d.ts +16 -16
- package/dist/tools/media-analysis.js +10 -5
- package/dist/tools/media.js +11 -5
- package/dist/tools/operation-recovery.d.ts +135 -0
- package/dist/tools/operation-recovery.js +105 -0
- package/dist/tools/recovery.d.ts +12 -0
- package/dist/tools/recovery.js +2 -1
- package/dist/tools/scene-review-workflow.d.ts +111 -0
- package/dist/tools/scene-review-workflow.js +92 -0
- package/dist/tools/sequence.js +12 -1
- package/dist/tools/temporal-render-evidence.d.ts +380 -0
- package/dist/tools/temporal-render-evidence.js +171 -0
- package/dist/tools/timeline-editorial.d.ts +1336 -0
- package/dist/tools/timeline-editorial.js +341 -0
- package/dist/tools/timeline.js +6 -4
- package/dist/tools/uxp.d.ts +5 -0
- package/dist/tools/uxp.js +38 -6
- package/dist/workflows/agent-instructions.js +8 -1
- package/dist/workflows/analysis-cache.d.ts +15 -0
- package/dist/workflows/analysis-cache.js +60 -0
- package/dist/workflows/catalog.d.ts +27 -2
- package/dist/workflows/catalog.js +30 -0
- package/dist/workflows/invocation-context.d.ts +31 -0
- package/dist/workflows/invocation-context.js +64 -0
- package/dist/workflows/job-contract.d.ts +29 -0
- package/dist/workflows/job-contract.js +144 -0
- package/dist/workflows/mutation-receipt.d.ts +17 -0
- package/dist/workflows/mutation-receipt.js +29 -0
- package/dist/workflows/performance-diagnostics.d.ts +55 -0
- package/dist/workflows/performance-diagnostics.js +24 -0
- package/dist/workflows/review-artifacts.d.ts +30 -0
- package/dist/workflows/review-artifacts.js +138 -0
- package/dist/workflows/strict-schema.d.ts +4 -0
- package/dist/workflows/strict-schema.js +50 -0
- package/dist/workflows/tool-metadata.d.ts +1 -1
- package/dist/workflows/tool-metadata.js +4 -3
- package/dist/workflows/tool-packs.js +6 -0
- package/docs/filmcraft-improvements.json +424 -0
- package/docs/filmcraft-improvements.md +130 -0
- package/docs/supported-actions.md +49 -8
- package/docs/temporal-render-fixtures.matrix.json +15 -0
- package/docs/temporal-render-fixtures.md +70 -0
- package/package.json +17 -8
- package/public-product-manifest.json +6 -6
- package/scripts/benchmark-planning.mjs +18 -0
- package/scripts/check-dependency-boundaries.mjs +38 -0
- package/scripts/create-temporal-host-report.mjs +20 -0
- package/scripts/create-temporal-render-fixture.mjs +16 -0
- package/scripts/validate-temporal-host-report.mjs +67 -0
- package/scripts/verify-npm-package.mjs +10 -0
- package/uxp-plugin/advanced-workflows.cjs +36 -9
- package/uxp-plugin/commands.cjs +120 -32
- package/uxp-plugin/events.cjs +51 -3
- package/uxp-plugin/index.cjs +2 -0
- package/uxp-plugin/index.html +1 -1
- package/uxp-plugin/manifest.json +1 -1
- package/uxp-plugin/operation-ledger.cjs +135 -0
- package/uxp-plugin/protocol.cjs +6 -0
package/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,45 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
|
|
|
6
6
|
|
|
7
7
|
## [Unreleased]
|
|
8
8
|
|
|
9
|
+
## [1.24.0] - 2026-10-11
|
|
10
|
+
|
|
11
|
+
### Added
|
|
12
|
+
|
|
13
|
+
- `get_caption_style_guidance` accepts an optional, bounded `custom_style` (font family/weight, font size 8-400 px, `#RRGGBB` fill, up to three strokes with width and outer/inner/center placement, drop shadow, one of nine zones, X/Y offsets, Track Style name) and returns that spec with numbered Premiere UI steps carrying the exact values. Each extra stroke is added with + next to Stroke, and the look is saved via Track Style > + Create style. Preset steps use the same workflow. Results add `track_style` (whole-track scope, reuse from the Track Style dropdown in other sequences, project item in the Project panel), `limitations`, `warnings` (for example, layered outer strokes that do not grow wider) and `applied: false`. It is still guidance only: Premiere exposes no caption style API, so nothing is applied. Verify the look with `export_frame` or `export_sequence_review_frames`. Calls that pass only `preset` keep their `style` fields.
|
|
14
|
+
- The platform capability report lists `captionTrackStyle` under the CEP `unsupported` map, so clients see that caption track styling cannot be automated and are pointed to `get_caption_style_guidance`.
|
|
15
|
+
|
|
16
|
+
### Fixed
|
|
17
|
+
|
|
18
|
+
- `__setItemMarks` now writes the same quarter-grid-biased seconds when applying a temporary overwrite range. Premiere 26.5.2 can floor exact tick-boundary seconds one media frame early, so `unnest_sequence` (16-tick default tolerance) refused a valid nest, or `replace_clip` placed a clip one frame short after the original was already removed. `replace_clip` also pulls a placed end that overshoots the original span by less than one media frame back onto that span.
|
|
19
|
+
|
|
20
|
+
- `__itemMarksForRestore` now applies that same write bias when it returns DOM marks (no private metadata, or DOM already matching the private range). Those paths previously handed exact tick-boundary seconds to restore, so a normal clip could shrink one media frame after replace/unnest on 26.5.2.
|
|
21
|
+
|
|
22
|
+
## [1.23.0] - 2026-10-11
|
|
23
|
+
|
|
24
|
+
### Added
|
|
25
|
+
|
|
26
|
+
- 41 bounded core tools and five guided workflow routes from the [52-item Filmcraft implementation ledger](docs/filmcraft-improvements.md). The source catalog now declares 434 core tools, 432 under default authority and 528 with 96 capability-gated UXP additions.
|
|
27
|
+
- Guarded execution and recovery with a private shared host lease, expected project/sequence targets, structured mutation receipts, cancellation/progress context, durable hashed UXP replay reservations and versioned command/receipt contracts. UXP writes require native cryptographic entropy and compatible durable replay storage; older unversioned panels remain read-only.
|
|
28
|
+
- Exact tick/rate timeline models, typed compound edit previews, sync and stacked-camera planning, transcript/caption/music/scene review, provenance, checkpoints and bounded edit-property fixtures.
|
|
29
|
+
- Bounded OTIO/XML inspection and loss reports, ALE/CSV adapters and audio-post turnover plans. Unsupported native round trips and opaque serializers remain explicit rather than being reported as completed exports.
|
|
30
|
+
- Verified delivery, checksum-pinned review artifacts, local job inspection/cancellation, rendered scopes and actual multi-frame RGB/ROI/PCM evidence tools, plus opt-in analysis caching, performance diagnostics and licensed-host fixture/report helpers.
|
|
31
|
+
|
|
32
|
+
### Fixed
|
|
33
|
+
|
|
34
|
+
- Folder imports now verify Premiere project-item readback instead of treating an accepted import call as proof that all requested media was imported. Counts and partial outcomes describe the observed project state.
|
|
35
|
+
- Caption imports validate supported formats before dispatch, preserve mutation readback and reject counts outside the safe integer range.
|
|
36
|
+
|
|
37
|
+
- Registered tools accept optional request-scoped `expected_project_path`; generated CEP commands refuse a different, missing or unsaved active project before the tool body. UXP and After Effects refuse this CEP-only guard. Omitting the guard preserves existing behavior.
|
|
38
|
+
|
|
39
|
+
- `unnest_sequence` now refuses, before removing the nested clip, any inner item that also carries the other media type. Premiere 26.5.2's `Track.overwriteClip` places that media on the matching track and overwrites the clips there. Same guard as `replace_clip`. Unnest a nest of video-only or audio-only items, or use Premiere's Unnest command.
|
|
40
|
+
- Shared project-item mark restore after `replace_clip`, `unnest_sequence`, and other `Track.overwriteClip` helpers now writes the quarter-frame-biased seconds from `__itemMarksForRestore`. Writing the exact tick boundary as seconds can floor one media frame early on Premiere 26.5.2 (a soft-subclip Out of `00:00:29:22` stored as `00:00:29:21`), shrinking the source item. `duplicate_clip` and `set_item_in_out` already used those seconds.
|
|
41
|
+
|
|
42
|
+
- `export_sequence` without `preset_path` no longer exports at proxy resolution when Media Encoder is not installed. Preset discovery only searched Premiere's `Settings/IngestPresets`, so the default became `IngestPresets/Proxy/00_1024x540 H.264.epr` and a 1080x1920 sequence was exported at 1024x540 while reporting `verified: true` (Premiere 24.0, macOS). Preset discovery now also searches Premiere's own `MediaIO/systempresets` when no Media Encoder presets exist, and the default never comes from `IngestPresets`; if no other H.264 preset is found, the tool asks for `preset_path`.
|
|
43
|
+
|
|
44
|
+
### Compatibility and evidence
|
|
45
|
+
|
|
46
|
+
CEP remains the production bridge; failed UXP mutations never fall back to CEP or QE. Recovery preserves unknown and partial outcomes. Native multicam switching, nonlinear/nested retime mapping, DSP music rendering, OCR and accepted-native-job cancellation remain unsupported. Local decoder tests establish artifact behavior, while licensed Premiere playback, Undo/reopen and native round-trip validation remain `not_run`.
|
|
47
|
+
|
|
9
48
|
## [1.22.0] - 2026-10-08
|
|
10
49
|
|
|
11
50
|
### Fixed
|
package/README.md
CHANGED
|
@@ -14,7 +14,7 @@ Free, MIT licensed, local-first, and published to npm as [`premiere-pro-mcp`](ht
|
|
|
14
14
|
|
|
15
15
|
[Website](https://premiere-pro-mcp.com/) · [Recorded demo](https://premiere-pro-mcp.com/demo/) · [Compare servers](https://premiere-pro-mcp.com/compare/) · [Setup guides](https://premiere-pro-mcp.com/blog/how-to-set-up-premiere-pro-mcp/) · [Search tools](https://premiere-pro-mcp.com/tools/) · [Troubleshooting](https://premiere-pro-mcp.com/docs/troubleshooting/) · [Release facts](https://premiere-pro-mcp.com/facts/)
|
|
16
16
|
|
|
17
|
-
Development source:
|
|
17
|
+
Development source: 434 core tools across 67 modules, 4 resources, and 29 guided workflows. A connected UXP host adds 96 capability-gated tools.
|
|
18
18
|
|
|
19
19
|
The [completed AE render handoff](docs/after-effects-render-handoff.md) previews and confirms importing one finished render into an existing Premiere bin, with host and file rechecks and an import receipt.
|
|
20
20
|
|
|
@@ -125,17 +125,17 @@ and repository before configuring a client. The new
|
|
|
125
125
|
VS Code, or Codex settings that point directly to this installation. It is a
|
|
126
126
|
feature included in v1.15.1 and later.
|
|
127
127
|
|
|
128
|
-
The current source exposes
|
|
128
|
+
The current source exposes 434 core tools for supported workflow steps spanning the supported ExtendScript, QE DOM, local media and interchange analysis, revisioned project-context retrieval, safe edit-planning, project-intake preview, review handoff, connection verification, and guarded After Effects MOGRT authoring, batch, library, render-queue, inspection, and Premiere-handoff workflows. A compatible, authenticated UXP panel adds 96 documented, capability-gated tools without replacing the production CEP bridge.
|
|
129
129
|
|
|
130
130
|
<a id="latest-release"></a>
|
|
131
131
|
|
|
132
|
-
### Latest release: 1.
|
|
132
|
+
### Latest release: 1.24.0
|
|
133
133
|
|
|
134
|
-
The published v1.
|
|
135
|
-
and
|
|
134
|
+
The published v1.24.0 npm artifact contains **434 core tools**, 432 in its default profile,
|
|
135
|
+
and 528 with a compatible UXP connection. The development catalog above can include
|
|
136
136
|
unreleased work. See the [versioned facts and package provenance](https://premiere-pro-mcp.com/facts/).
|
|
137
137
|
|
|
138
|
-
GitHub releases use `v<SemVer>` for both title and tag, such as `v1.
|
|
138
|
+
GitHub releases use `v<SemVer>` for both title and tag, such as `v1.24.0`.
|
|
139
139
|
See [release naming and version conventions](docs/release-conventions.md).
|
|
140
140
|
|
|
141
141
|
### Try a bounded workflow
|
|
@@ -154,6 +154,12 @@ if the connection is unavailable.
|
|
|
154
154
|
|
|
155
155
|
### Release highlights
|
|
156
156
|
|
|
157
|
+
- **1.24.0 mark-write fixes:** temporary overwrite marks and restored project-item marks are written a quarter media frame past the tick boundary, so Premiere 26.5.2 no longer floors them one frame early in `unnest_sequence`, `replace_clip` and `duplicate_clip`.
|
|
158
|
+
- **1.24.0 caption style guidance:** `get_caption_style_guidance` accepts a bounded `custom_style` and returns Properties panel and Track Style steps; it is guidance only and applies nothing.
|
|
159
|
+
- **1.23.0 bounded workflows:** 41 added core tools and five guided routes cover exact timeline planning, editorial review, interchange/turnover and guarded delivery. The [52-item implementation ledger](docs/filmcraft-improvements.md) records each supported subset and host limit.
|
|
160
|
+
- **1.23.0 execution and recovery:** cooperating processes serialize protected edits, retain recovery for uncertain outcomes and report cancellation/partial work explicitly. UXP writes require the matching updated panel; older unversioned panels remain read-only.
|
|
161
|
+
- **1.23.0 artifact evidence:** review and delivery checks pin source checksums, inspect actual decoded frames/audio and preserve unknown native-job completion. Local decoder checks do not establish Premiere playback or native round-trip compatibility.
|
|
162
|
+
- **1.23.0 import fixes:** folder imports verify actual project-item readback; caption imports validate formats and counts and preserve mutation readback. Export preset discovery avoids proxy ingest presets, and unnesting refuses mixed-media overwrite hazards.
|
|
157
163
|
- **1.22.0 readback receipts:** effect writes, stabilization, smart bins, proxies, folder imports, sequence creation, marker deletion and clip selection report what Premiere applied as `verified`, `committed_unverified` or `failed`; `create_subclip`, `add_title` and `update_marker` report the stored values; `set_sequence_frame_rate` lists clips Premiere re-snapped.
|
|
158
164
|
- **1.22.0 display codes and proxies:** `set_sequence_display_format` writes Premiere's real display codes (video 100-113, audio 200-201) and maps the older 0-11 and 0-1 inputs onto them; `manage_proxies` toggle can set a known proxy display state; the Windows ACL check waits up to 30 seconds for PowerShell.
|
|
159
165
|
- **1.21.0 Claude Desktop startup fix:** the extension starts when optional settings are blank, and Desktop's discover-only probe no longer holds the UXP port, so the real server keeps its UXP tools.
|
|
@@ -195,7 +201,7 @@ if the connection is unavailable.
|
|
|
195
201
|
local Premiere processes. See the generated [supported action catalog](docs/supported-actions.md)
|
|
196
202
|
for individual capability and verification contracts.
|
|
197
203
|
|
|
198
|
-
See the [v1.
|
|
204
|
+
See the [v1.24.0 release notes](https://github.com/leancoderkavy/premiere-pro-mcp/releases/tag/v1.24.0)
|
|
199
205
|
for complete details. Live installation in Premiere Pro still requires host verification.
|
|
200
206
|
|
|
201
207
|
### Current MCP protocol support
|
|
@@ -213,6 +219,16 @@ handshake only; leave it unset (or `auto`) for modern MCP capabilities.
|
|
|
213
219
|
|
|
214
220
|
---
|
|
215
221
|
|
|
222
|
+
### Guarding multi-project CEP sessions
|
|
223
|
+
|
|
224
|
+
Every registered tool accepts optional `expected_project_path`, an absolute path to the intended saved Premiere project. Generated CEP scripts compare the active project's host-normalized file path before the tool body; a different, missing or unsaved project refuses without running that body. The guard is scoped to the request and checked for every generated command in a multi-command tool. Omitting it preserves existing behavior.
|
|
225
|
+
|
|
226
|
+
```json
|
|
227
|
+
{"name":"get_project_info","arguments":{"expected_project_path":"/Projects/Film.prproj"}}
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
This protects against accidental active-project switches, not deliberate project switching inside unsafe scripts. It does not select a project or prove media identity. Paths remain in request context and are not telemetry. UXP and After Effects commands refuse this CEP-only guard; UXP workflows use their `expected_snapshot` identity contracts. Local-only tools do not inspect Premiere. Filesystem aliases are not resolved as a claim of project identity.
|
|
231
|
+
|
|
216
232
|
## For editors evaluating an AI workflow
|
|
217
233
|
|
|
218
234
|
Before an assistant changes an active project, use the
|
|
@@ -243,7 +259,7 @@ their bins, media rules, and organization rules before a facility uses one.
|
|
|
243
259
|
> ### Install the published package (verify the name)
|
|
244
260
|
>
|
|
245
261
|
> ```bash
|
|
246
|
-
> npm i -g premiere-pro-mcp@1.
|
|
262
|
+
> npm i -g premiere-pro-mcp@1.24.0
|
|
247
263
|
> ```
|
|
248
264
|
>
|
|
249
265
|
> This repository publishes only **`premiere-pro-mcp`**. A differently named package (`adobe-premiere-pro-mcp`) may also declare a `premiere-pro-mcp` executable. Before configuring a client, confirm:
|
|
@@ -251,7 +267,7 @@ their bins, media rules, and organization rules before a facility uses one.
|
|
|
251
267
|
> | Check | Expected |
|
|
252
268
|
> | --- | --- |
|
|
253
269
|
> | Package name | `premiere-pro-mcp` (not `adobe-premiere-pro-mcp`) |
|
|
254
|
-
> | Version | `1.
|
|
270
|
+
> | Version | `1.24.0` |
|
|
255
271
|
> | Homepage / repo | https://premiere-pro-mcp.com/ · https://github.com/leancoderkavy/premiere-pro-mcp |
|
|
256
272
|
>
|
|
257
273
|
> ```bash
|
|
@@ -264,9 +280,9 @@ their bins, media rules, and organization rules before a facility uses one.
|
|
|
264
280
|
|
|
265
281
|
### Easiest supported path: Claude Desktop
|
|
266
282
|
|
|
267
|
-
1. Download the current [Claude Desktop bundle (`.mcpb`)](https://github.com/leancoderkavy/premiere-pro-mcp/releases/download/v1.
|
|
283
|
+
1. Download the current [Claude Desktop bundle (`.mcpb`)](https://github.com/leancoderkavy/premiere-pro-mcp/releases/download/v1.24.0/premiere-pro-mcp-1.24.0.mcpb).
|
|
268
284
|
2. In Claude Desktop, open **Settings > Extensions > Advanced settings > Install Extension**, select the downloaded bundle, and restart Claude Desktop.
|
|
269
|
-
3. Download the separate [signed Premiere connector (`.zxp`)](https://github.com/leancoderkavy/premiere-pro-mcp/releases/download/v1.
|
|
285
|
+
3. Download the separate [signed Premiere connector (`.zxp`)](https://github.com/leancoderkavy/premiere-pro-mcp/releases/download/v1.24.0/MCPBridgeCEP.zxp). Open it with your trusted ZXP installer. If your computer has no ZXP installer, use the npm connector installer in **Advanced setup** below.
|
|
270
286
|
4. Restart Premiere, open a project, then open **Window > Extensions > MCP for Adobe Premiere Pro**.
|
|
271
287
|
5. In Claude, enter: `Safely check my Premiere connection with verify_premiere_connection. Make no changes.`
|
|
272
288
|
|
|
@@ -570,11 +586,11 @@ From a clone of this repository:
|
|
|
570
586
|
```bash
|
|
571
587
|
codex plugin marketplace add .
|
|
572
588
|
codex plugin add premiere-pro@premiere-pro-mcp
|
|
573
|
-
npx -y premiere-pro-mcp@1.
|
|
589
|
+
npx -y premiere-pro-mcp@1.24.0 --install-cep
|
|
574
590
|
```
|
|
575
591
|
|
|
576
592
|
Restart Premiere Pro and start a new Codex session after installation. The plugin
|
|
577
|
-
launches `premiere-pro-mcp@1.
|
|
593
|
+
launches `premiere-pro-mcp@1.24.0` through `npx`; the separate CEP installation is
|
|
578
594
|
required because the MCP server communicates with the running Premiere host through
|
|
579
595
|
the local bridge.
|
|
580
596
|
|
|
@@ -612,7 +628,7 @@ For Claude Code, add this repository as a marketplace and install the plugin:
|
|
|
612
628
|
Then install the Premiere bridge and start a new Claude Code session:
|
|
613
629
|
|
|
614
630
|
```bash
|
|
615
|
-
npx -y premiere-pro-mcp@1.
|
|
631
|
+
npx -y premiere-pro-mcp@1.24.0 --install-cep
|
|
616
632
|
```
|
|
617
633
|
|
|
618
634
|
The Claude Code package lives in
|
|
@@ -829,7 +845,7 @@ PREMIERE_UXP_TOKEN="replace-with-a-long-random-secret" premiere-pro-mcp
|
|
|
829
845
|
|
|
830
846
|
Generate that secret yourself and enter the same value in the UXP panel (**Window → UXP Plugins**, not the CEP Connector). CEP-only setups do not use a token. The listener binds only to `127.0.0.1:7777`, authenticates the WebSocket upgrade, requires a versioned capability handshake, correlates concurrent requests, and fails pending work on timeout or disconnect. Set `PREMIERE_UXP_PORT` to use another loopback port.
|
|
831
847
|
|
|
832
|
-
When enabled, MCP discovery includes
|
|
848
|
+
When enabled, MCP discovery includes 96 capability-gated UXP additions. The first expansion covers effects, deterministic timeline selection, selection batches, scene detection, proxy/ingest, relink, metadata, color conformance, read-only Premiere/After Effects environment inspection, Source Monitor audition, storage, and least-privilege workspace access. The second adds Project-panel selection, marker CRUD, single-transaction undoable beat-grid marker application, bin organization, sequence settings, imports, typed effect parameters/keyframes, track-item transforms, atomic J/L split edits, SequenceEditor timeline edits, sequence lifecycle, and AME encoding. The third wave begins with a redacted event journal, conservative AME terminal receipts, explicit host-readiness gates, safe multi-project sessions, lease-based growing-media control, namespaced workflow checkpoints, bounded media-health maintenance, caption-aware track mute state, transactional source trim/framing, guarded sequence-range updates, guarded source-media start timing, and guarded source-media frame-rate/pixel-aspect overrides documented in [the third-wave workflow matrix](docs/third-wave-uxp-workflows.md). The bounded migration surface also includes a non-ripple selected-item lift, native video-transition listing and guarded transactions, native active and explicit-GUID sequence timing inspection, opt-in installed-MOGRT directory inspection without filesystem enumeration, bounded native timeline structure inspection with opt-in source IDs, classification, and broad content category, guarded sequence display-format updates, a capped native Project-panel tree, a double-read Project-panel insertion-bin snapshot, guarded empty/default sequence creation, bounded native Project-panel schema/item-column metadata inspection, guarded direct Project-panel metadata replacements with exact state/readback guards, guarded typed Project metadata schema-field creation with non-field-level readback, guarded direct updates to three named application preferences, guarded transcript JSON replacement for one exact source clip, direct active-track-item identity readback, guarded source-only slips, guarded contiguous three-item slides, guarded append-only timeline duplicates, guarded contiguous same-track ripple deletes, guarded source-project-item color labels resolved from one timeline coordinate, guarded explicit-sequence preview-frame rectangle updates, explicit opt-in source-media provenance paths with bounded double resolution, bounded source-proxy readiness with an explicit attached-path disclosure, guarded static effect-parameter PointF x/y updates, bounded effect-parameter descriptor catalogs, bounded project/sequence Object Mask audits, native FrameRate/TickTime frame-alignment inspection with caller-owned inputs and tick readback, and native TickTime arithmetic over caller-owned canonical tick strings; it does not claim direct empty-track create/delete, global redo support, playback proof, Object Mask counts or visual validity, an atomic Project-panel metadata compare-and-set, app-preference Undo, installed-template availability or compatibility, imported transcript persistence, override-presence/clear semantics, path existence, source lineage or rights, proxy compatibility, general or keyframed effect-parameter value readback, rendered-frame correctness, linked-item sync, or licensed-host validation. A separate [hybrid benchmark gate](docs/uxp-hybrid-benchmark.md) keeps native acceleration disabled until reproducible cross-platform evidence exists. See also [the first stable workflow matrix](docs/uxp-stable-workflows.md), [the next-ten workflow matrix](docs/uxp-next-ten-workflows.md), [the guarded-slip workflow notes](docs/uxp-slip-workflows.md), [the guarded-slide workflow notes](docs/uxp-slide-workflows.md), [the guarded-duplicate workflow notes](docs/uxp-clone-workflows.md), and [the guarded-ripple-delete workflow notes](docs/uxp-ripple-delete-workflows.md). Commands are advertised only while the authenticated local UXP bridge is connected; the host capability handshake remains the authority for support in the running Premiere build. A failed UXP command is never silently retried through CEP because the first operation may have partially succeeded. UXP edits require a matching command-schema/receipt version, durable panel ledger storage and native cryptographic entropy; older unversioned panels remain read-only until the matching panel is installed.
|
|
833
849
|
|
|
834
850
|
The bounded UXP migration surface also exposes a read-only animated-PointF endpoint-displacement inspection through `automate_effect_parameters_uxp`. It requires one exact component and parameter target plus a strictly increasing time interval, double-reads native endpoint values and their distance, and refuses static, malformed, or changed parameter state. It does not modify Premiere or prove rendered appearance, playback, persistence, Undo, or licensed-host behavior.
|
|
835
851
|
|
|
@@ -938,7 +954,10 @@ See [usage, example and remaining execution adapters](docs/film-editorial-workfl
|
|
|
938
954
|
|
|
939
955
|
Reviewed assistant-editing tools now provide dialogue candidate decisions, quote paper-edit CSV, batch copy previews, sync-evidence triage, and owned-footage B-roll review. These are local evidence reviews, not new host engines. See [review workflow contracts](docs/editorial-review-workflows.md).
|
|
940
956
|
|
|
941
|
-
|
|
957
|
+
See [Filmcraft improvement ledger](docs/filmcraft-improvements.md) for exact-time
|
|
958
|
+
planning, recovery, job observation, temporal evidence and facility workflows.
|
|
959
|
+
|
|
960
|
+
## Tools (434 core total; 432 under the default profile; 528 with a connected UXP bridge)
|
|
942
961
|
|
|
943
962
|
The [complete supported-actions catalog](docs/supported-actions.md) lists every
|
|
944
963
|
registered core tool, the two tools restricted behind explicit `unsafe-script`
|
|
@@ -1090,9 +1109,11 @@ adjusted. This is a CEP contract check, not validation in a licensed Premiere Pr
|
|
|
1090
1109
|
| `encode_project_item` / `encode_file` | Direct encoding |
|
|
1091
1110
|
| `start_batch_encode` | Start render queue |
|
|
1092
1111
|
|
|
1093
|
-
Premiere
|
|
1094
|
-
|
|
1095
|
-
|
|
1112
|
+
Documented Premiere UXP exposes format-specific OTIO import/export through
|
|
1113
|
+
runtime-probed `export_interchange_uxp` and `import_interchange_uxp`. CEP has no
|
|
1114
|
+
documented native OTIO route. Native EDL, Render and Replace, cloud publishing
|
|
1115
|
+
and Content Credentials export configuration remain unavailable through the
|
|
1116
|
+
supported automation contracts. `export_sequence_edl` therefore builds the CMX 3600 list
|
|
1096
1117
|
locally from the clips Premiere reads back and validates it with the same parser
|
|
1097
1118
|
used by `inspect_cmx3600_edl`; it is not a Premiere-native export.
|
|
1098
1119
|
`get_capabilities` reports the remaining delivery gaps explicitly rather than
|
|
@@ -1427,7 +1448,7 @@ premiere-pro-mcp/
|
|
|
1427
1448
|
├── src/
|
|
1428
1449
|
│ ├── index.ts # Entry point — stdio transport setup
|
|
1429
1450
|
│ ├── http-server.ts # Entry point — HTTP/SSE transport (Fly.io / remote)
|
|
1430
|
-
│ ├── server.ts # MCP server — registers
|
|
1451
|
+
│ ├── server.ts # MCP server — registers 434 tools, filtered by authority profile
|
|
1431
1452
|
│ ├── bridge/
|
|
1432
1453
|
│ │ ├── file-bridge.ts # File-based IPC (write .jsx, poll .json)
|
|
1433
1454
|
│ │ └── script-builder.ts # ExtendScript generator with ES3 helpers
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
-
<ExtensionManifest Version="7.0" ExtensionBundleId="com.mcp.aftereffects.bridge" ExtensionBundleVersion="1.
|
|
2
|
+
<ExtensionManifest Version="7.0" ExtensionBundleId="com.mcp.aftereffects.bridge" ExtensionBundleVersion="1.24.0" ExtensionBundleName="MCP for Adobe After Effects">
|
|
3
3
|
<ExtensionList>
|
|
4
|
-
<Extension Id="com.mcp.aftereffects.bridge.panel" Version="1.
|
|
5
|
-
<Extension Id="com.mcp.aftereffects.bridge.headless" Version="1.
|
|
4
|
+
<Extension Id="com.mcp.aftereffects.bridge.panel" Version="1.24.0"/>
|
|
5
|
+
<Extension Id="com.mcp.aftereffects.bridge.headless" Version="1.24.0"/>
|
|
6
6
|
</ExtensionList>
|
|
7
7
|
<ExecutionEnvironment>
|
|
8
8
|
<HostList>
|
|
Binary file
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
-
<ExtensionManifest Version="7.0" ExtensionBundleId="com.mcp.premiere.bridge" ExtensionBundleVersion="1.
|
|
2
|
+
<ExtensionManifest Version="7.0" ExtensionBundleId="com.mcp.premiere.bridge" ExtensionBundleVersion="1.24.0" ExtensionBundleName="MCP for Adobe Premiere Pro">
|
|
3
3
|
<ExtensionList>
|
|
4
|
-
<Extension Id="com.mcp.premiere.bridge.panel" Version="1.
|
|
5
|
-
<Extension Id="com.mcp.premiere.bridge.headless" Version="1.
|
|
4
|
+
<Extension Id="com.mcp.premiere.bridge.panel" Version="1.24.0"/>
|
|
5
|
+
<Extension Id="com.mcp.premiere.bridge.headless" Version="1.24.0"/>
|
|
6
6
|
</ExtensionList>
|
|
7
7
|
<ExecutionEnvironment>
|
|
8
8
|
<HostList>
|
package/cep-plugin/index.html
CHANGED
|
@@ -81,7 +81,7 @@
|
|
|
81
81
|
<section class="update-section" aria-live="polite">
|
|
82
82
|
<div class="update-copy">
|
|
83
83
|
<span class="section-label">MCP updates</span>
|
|
84
|
-
<strong id="updateTitle">Version 1.
|
|
84
|
+
<strong id="updateTitle">Version 1.24.0</strong>
|
|
85
85
|
<span id="updateDetail">Checking the global MCP server and connector release…</span>
|
|
86
86
|
</div>
|
|
87
87
|
<button id="btnUpdate" class="button button-update" onclick="handleUpdateClick()" type="button" aria-describedby="updateDetail" disabled>
|
package/cep-plugin/main.js
CHANGED
|
@@ -248,6 +248,8 @@ function writeBridgeHeartbeat() {
|
|
|
248
248
|
try {
|
|
249
249
|
fs.writeFileSync(stagedPath, JSON.stringify({
|
|
250
250
|
protocolVersion: 1,
|
|
251
|
+
commandSchemaVersion: 1,
|
|
252
|
+
receiptVersion: 1,
|
|
251
253
|
state: bridgeRunning ? "running" : "waiting"
|
|
252
254
|
}), "utf-8");
|
|
253
255
|
fs.renameSync(stagedPath, heartbeatPath);
|
package/cep-plugin/updater.cjs
CHANGED
|
@@ -103,6 +103,101 @@ type PlatformProfile = {
|
|
|
103
103
|
/** Approximate platform UI occlusion zones as normalized rects (x, y top-left). Verify against current platform overlay guides. */
|
|
104
104
|
export declare const PLATFORM_SAFE_ZONES: Record<SafeZonePlatform, PlatformProfile>;
|
|
105
105
|
export declare function describeCaptionStyle(preset: CaptionStylePreset): CaptionStyleDescriptor;
|
|
106
|
+
export declare const CAPTION_ZONES: readonly ["top_left", "top_center", "top_right", "middle_left", "middle_center", "middle_right", "bottom_left", "bottom_center", "bottom_right"];
|
|
107
|
+
export type CaptionZone = (typeof CAPTION_ZONES)[number];
|
|
108
|
+
export declare const CAPTION_STROKE_PLACEMENTS: readonly ["outer", "inner", "center"];
|
|
109
|
+
export type CaptionStrokePlacement = (typeof CAPTION_STROKE_PLACEMENTS)[number];
|
|
110
|
+
export declare const MAX_CAPTION_STROKES = 3;
|
|
111
|
+
export declare const CUSTOM_CAPTION_STYLE_LIMITS: {
|
|
112
|
+
readonly font_family_max_length: 128;
|
|
113
|
+
readonly font_weight_max_length: 64;
|
|
114
|
+
readonly track_style_name_max_length: 80;
|
|
115
|
+
readonly font_size_px: {
|
|
116
|
+
readonly min: 8;
|
|
117
|
+
readonly max: 400;
|
|
118
|
+
};
|
|
119
|
+
readonly stroke_width_px: {
|
|
120
|
+
readonly min: 0;
|
|
121
|
+
readonly max: 100;
|
|
122
|
+
};
|
|
123
|
+
readonly offset_px: {
|
|
124
|
+
readonly min: -2000;
|
|
125
|
+
readonly max: 2000;
|
|
126
|
+
};
|
|
127
|
+
readonly shadow: {
|
|
128
|
+
readonly opacity: {
|
|
129
|
+
readonly min: 0;
|
|
130
|
+
readonly max: 100;
|
|
131
|
+
};
|
|
132
|
+
readonly angle: {
|
|
133
|
+
readonly min: 0;
|
|
134
|
+
readonly max: 360;
|
|
135
|
+
};
|
|
136
|
+
readonly distance: {
|
|
137
|
+
readonly min: 0;
|
|
138
|
+
readonly max: 200;
|
|
139
|
+
};
|
|
140
|
+
readonly size: {
|
|
141
|
+
readonly min: 0;
|
|
142
|
+
readonly max: 100;
|
|
143
|
+
};
|
|
144
|
+
readonly blur: {
|
|
145
|
+
readonly min: 0;
|
|
146
|
+
readonly max: 100;
|
|
147
|
+
};
|
|
148
|
+
};
|
|
149
|
+
};
|
|
150
|
+
export declare const CAPTION_SHADOW_DEFAULTS: {
|
|
151
|
+
readonly color: "#000000";
|
|
152
|
+
readonly opacity: 75;
|
|
153
|
+
readonly angle: 135;
|
|
154
|
+
readonly distance: 7;
|
|
155
|
+
readonly size: 0;
|
|
156
|
+
readonly blur: 40;
|
|
157
|
+
};
|
|
158
|
+
export declare const DEFAULT_TRACK_STYLE_NAME = "Caption Track Style";
|
|
159
|
+
export type CaptionStroke = {
|
|
160
|
+
color: string;
|
|
161
|
+
width_px: number;
|
|
162
|
+
placement: CaptionStrokePlacement;
|
|
163
|
+
};
|
|
164
|
+
export type CaptionShadow = {
|
|
165
|
+
color: string;
|
|
166
|
+
opacity: number;
|
|
167
|
+
angle: number;
|
|
168
|
+
distance: number;
|
|
169
|
+
size: number;
|
|
170
|
+
blur: number;
|
|
171
|
+
};
|
|
172
|
+
export type CustomCaptionStyle = {
|
|
173
|
+
font_family?: string;
|
|
174
|
+
font_weight?: string;
|
|
175
|
+
font_size_px?: number;
|
|
176
|
+
fill_color?: string;
|
|
177
|
+
strokes?: CaptionStroke[];
|
|
178
|
+
shadow?: CaptionShadow;
|
|
179
|
+
zone?: CaptionZone;
|
|
180
|
+
offset_x_px?: number;
|
|
181
|
+
offset_y_px?: number;
|
|
182
|
+
track_style_name?: string;
|
|
183
|
+
};
|
|
184
|
+
export declare function validateCustomCaptionStyle(value: unknown): CustomCaptionStyle;
|
|
185
|
+
/** Warnings about a custom style that Premiere will accept but that may not render as intended. */
|
|
186
|
+
export declare function customCaptionStyleWarnings(style: CustomCaptionStyle): string[];
|
|
187
|
+
/** Premiere 2024+ Properties-panel / Track Style steps for a custom caption style. */
|
|
188
|
+
export declare function buildCustomCaptionStyleSteps(style: CustomCaptionStyle, preset?: CaptionStylePreset): string[];
|
|
189
|
+
/** Premiere 2024+ Properties-panel / Track Style steps for a built-in preset. */
|
|
190
|
+
export declare function buildPresetCaptionStyleSteps(style: CaptionStyleDescriptor): string[];
|
|
191
|
+
export declare const CAPTION_TRACK_STYLE_GUIDANCE: {
|
|
192
|
+
readonly scope: "A Track Style applies to every caption on the caption track. Style one caption, save it with Track Style > + Create style, and the whole track updates; no multi-select is needed.";
|
|
193
|
+
readonly reusable: "A saved Track Style can be applied to the caption track of any other sequence in the project from the Track Style dropdown.";
|
|
194
|
+
readonly project_item: "Each Track Style is stored as a project item in the Project panel; keep it in a shared bin so it can be found and reused.";
|
|
195
|
+
readonly limitations: readonly ["Premiere Pro exposes no documented ExtendScript, QE DOM, or UXP API that creates, edits, or applies caption styles, so these steps must be performed in the Premiere UI.", "These steps target Premiere Pro 2024 and later. Earlier versions lack the Track Style workflow described here and were not checked; panel labels can also differ between versions and UI languages.", "Verify the rendered result with export_frame or export_sequence_review_frames; this tool cannot read the applied style back."];
|
|
196
|
+
};
|
|
197
|
+
export declare function captionSafeZoneRecommendation(): Record<SafeZonePlatform, {
|
|
198
|
+
x: number;
|
|
199
|
+
y: number;
|
|
200
|
+
}>;
|
|
106
201
|
export declare function formatCaptionTimestamp(ms: number, format: CaptionFormat): string;
|
|
107
202
|
/** Greedy word wrap that never splits a word; a single word longer than the width occupies its own line. */
|
|
108
203
|
export declare function wrapCaptionWords(words: readonly string[], maxChars: number): string[][];
|
|
@@ -154,6 +154,219 @@ export function describeCaptionStyle(preset) {
|
|
|
154
154
|
note: "Documentation only. SRT/VTT artifacts carry timing and text; apply visual styling in Premiere's caption track style after import.",
|
|
155
155
|
};
|
|
156
156
|
}
|
|
157
|
+
// ---------------------------------------------------------------------------
|
|
158
|
+
// Custom caption track style (documentation only)
|
|
159
|
+
// ---------------------------------------------------------------------------
|
|
160
|
+
export const CAPTION_ZONES = ["top_left", "top_center", "top_right", "middle_left", "middle_center", "middle_right", "bottom_left", "bottom_center", "bottom_right"];
|
|
161
|
+
export const CAPTION_STROKE_PLACEMENTS = ["outer", "inner", "center"];
|
|
162
|
+
export const MAX_CAPTION_STROKES = 3;
|
|
163
|
+
export const CUSTOM_CAPTION_STYLE_LIMITS = {
|
|
164
|
+
font_family_max_length: 128,
|
|
165
|
+
font_weight_max_length: 64,
|
|
166
|
+
track_style_name_max_length: 80,
|
|
167
|
+
font_size_px: { min: 8, max: 400 },
|
|
168
|
+
stroke_width_px: { min: 0, max: 100 },
|
|
169
|
+
offset_px: { min: -2000, max: 2000 },
|
|
170
|
+
shadow: {
|
|
171
|
+
opacity: { min: 0, max: 100 },
|
|
172
|
+
angle: { min: 0, max: 360 },
|
|
173
|
+
distance: { min: 0, max: 200 },
|
|
174
|
+
size: { min: 0, max: 100 },
|
|
175
|
+
blur: { min: 0, max: 100 },
|
|
176
|
+
},
|
|
177
|
+
};
|
|
178
|
+
export const CAPTION_SHADOW_DEFAULTS = { color: "#000000", opacity: 75, angle: 135, distance: 7, size: 0, blur: 40 };
|
|
179
|
+
export const DEFAULT_TRACK_STYLE_NAME = "Caption Track Style";
|
|
180
|
+
const CUSTOM_STYLE_KEYS = ["font_family", "font_weight", "font_size_px", "fill_color", "strokes", "shadow", "zone", "offset_x_px", "offset_y_px", "track_style_name"];
|
|
181
|
+
const STROKE_KEYS = ["color", "width_px", "placement"];
|
|
182
|
+
const SHADOW_KEYS = ["color", "opacity", "angle", "distance", "size", "blur"];
|
|
183
|
+
const HEX_COLOR = /^#[0-9A-Fa-f]{6}$/;
|
|
184
|
+
function plainObject(value, label, allowed) {
|
|
185
|
+
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
186
|
+
fail(`${label} must be an object`);
|
|
187
|
+
const record = value;
|
|
188
|
+
const unknown = Object.keys(record).find((key) => !allowed.includes(key));
|
|
189
|
+
if (unknown)
|
|
190
|
+
fail(`${label} has an unknown field: ${unknown}`);
|
|
191
|
+
return record;
|
|
192
|
+
}
|
|
193
|
+
function boundedText(value, label, maxLength) {
|
|
194
|
+
if (typeof value !== "string" || !value.trim() || value.length > maxLength)
|
|
195
|
+
fail(`${label} must be a non-empty string of at most ${maxLength} characters`);
|
|
196
|
+
return value.trim();
|
|
197
|
+
}
|
|
198
|
+
function hexColor(value, label) {
|
|
199
|
+
if (typeof value !== "string" || !HEX_COLOR.test(value))
|
|
200
|
+
fail(`${label} must be a hex colour in the form #RRGGBB`);
|
|
201
|
+
return value.toUpperCase();
|
|
202
|
+
}
|
|
203
|
+
function rangedNumber(value, label, range, integer = false) {
|
|
204
|
+
if (typeof value !== "number" || !Number.isFinite(value))
|
|
205
|
+
fail(`${label} must be a finite number`);
|
|
206
|
+
if (integer && !Number.isInteger(value))
|
|
207
|
+
fail(`${label} must be an integer`);
|
|
208
|
+
if (value < range.min || value > range.max)
|
|
209
|
+
fail(`${label} must be between ${range.min} and ${range.max}`);
|
|
210
|
+
return value;
|
|
211
|
+
}
|
|
212
|
+
export function validateCustomCaptionStyle(value) {
|
|
213
|
+
const raw = plainObject(value, "custom_style", CUSTOM_STYLE_KEYS);
|
|
214
|
+
if (!Object.keys(raw).length)
|
|
215
|
+
fail("custom_style must set at least one field");
|
|
216
|
+
const limits = CUSTOM_CAPTION_STYLE_LIMITS;
|
|
217
|
+
const style = {};
|
|
218
|
+
if (raw.font_family !== undefined)
|
|
219
|
+
style.font_family = boundedText(raw.font_family, "custom_style.font_family", limits.font_family_max_length);
|
|
220
|
+
if (raw.font_weight !== undefined)
|
|
221
|
+
style.font_weight = boundedText(raw.font_weight, "custom_style.font_weight", limits.font_weight_max_length);
|
|
222
|
+
if (raw.font_size_px !== undefined)
|
|
223
|
+
style.font_size_px = rangedNumber(raw.font_size_px, "custom_style.font_size_px", limits.font_size_px, true);
|
|
224
|
+
if (raw.fill_color !== undefined)
|
|
225
|
+
style.fill_color = hexColor(raw.fill_color, "custom_style.fill_color");
|
|
226
|
+
if (raw.strokes !== undefined) {
|
|
227
|
+
if (!Array.isArray(raw.strokes) || raw.strokes.length > MAX_CAPTION_STROKES)
|
|
228
|
+
fail(`custom_style.strokes must be an array of at most ${MAX_CAPTION_STROKES} strokes`);
|
|
229
|
+
style.strokes = raw.strokes.map((item, index) => {
|
|
230
|
+
const label = `custom_style.strokes[${index}]`;
|
|
231
|
+
const stroke = plainObject(item, label, STROKE_KEYS);
|
|
232
|
+
const placement = stroke.placement === undefined ? "outer" : stroke.placement;
|
|
233
|
+
if (typeof placement !== "string" || !CAPTION_STROKE_PLACEMENTS.includes(placement))
|
|
234
|
+
fail(`${label}.placement must be one of: ${CAPTION_STROKE_PLACEMENTS.join(", ")}`);
|
|
235
|
+
return {
|
|
236
|
+
color: hexColor(stroke.color, `${label}.color`),
|
|
237
|
+
width_px: rangedNumber(stroke.width_px, `${label}.width_px`, limits.stroke_width_px),
|
|
238
|
+
placement: placement,
|
|
239
|
+
};
|
|
240
|
+
});
|
|
241
|
+
}
|
|
242
|
+
if (raw.shadow !== undefined) {
|
|
243
|
+
const shadow = plainObject(raw.shadow, "custom_style.shadow", SHADOW_KEYS);
|
|
244
|
+
const numberOr = (key) => shadow[key] === undefined ? CAPTION_SHADOW_DEFAULTS[key] : rangedNumber(shadow[key], `custom_style.shadow.${key}`, limits.shadow[key]);
|
|
245
|
+
style.shadow = {
|
|
246
|
+
color: shadow.color === undefined ? CAPTION_SHADOW_DEFAULTS.color : hexColor(shadow.color, "custom_style.shadow.color"),
|
|
247
|
+
opacity: numberOr("opacity"),
|
|
248
|
+
angle: numberOr("angle"),
|
|
249
|
+
distance: numberOr("distance"),
|
|
250
|
+
size: numberOr("size"),
|
|
251
|
+
blur: numberOr("blur"),
|
|
252
|
+
};
|
|
253
|
+
}
|
|
254
|
+
if (raw.zone !== undefined) {
|
|
255
|
+
if (typeof raw.zone !== "string" || !CAPTION_ZONES.includes(raw.zone))
|
|
256
|
+
fail(`custom_style.zone must be one of: ${CAPTION_ZONES.join(", ")}`);
|
|
257
|
+
style.zone = raw.zone;
|
|
258
|
+
}
|
|
259
|
+
if (raw.offset_x_px !== undefined)
|
|
260
|
+
style.offset_x_px = rangedNumber(raw.offset_x_px, "custom_style.offset_x_px", limits.offset_px, true);
|
|
261
|
+
if (raw.offset_y_px !== undefined)
|
|
262
|
+
style.offset_y_px = rangedNumber(raw.offset_y_px, "custom_style.offset_y_px", limits.offset_px, true);
|
|
263
|
+
if (raw.track_style_name !== undefined)
|
|
264
|
+
style.track_style_name = boundedText(raw.track_style_name, "custom_style.track_style_name", limits.track_style_name_max_length);
|
|
265
|
+
return style;
|
|
266
|
+
}
|
|
267
|
+
const ordinal = (index) => ["first", "second", "third"][index] ?? `#${index + 1}`;
|
|
268
|
+
const zoneLabel = (zone) => zone.replace("_", "-");
|
|
269
|
+
/** Warnings about a custom style that Premiere will accept but that may not render as intended. */
|
|
270
|
+
export function customCaptionStyleWarnings(style) {
|
|
271
|
+
const warnings = [];
|
|
272
|
+
const outer = (style.strokes ?? []).filter((stroke) => stroke.placement === "outer");
|
|
273
|
+
for (let index = 1; index < outer.length; index += 1) {
|
|
274
|
+
if (outer[index].width_px <= outer[index - 1].width_px)
|
|
275
|
+
warnings.push(`outer stroke ${index + 1} (${outer[index].width_px} px) is not wider than outer stroke ${index} (${outer[index - 1].width_px} px), so it may be hidden behind it; layered outer strokes need increasing widths`);
|
|
276
|
+
}
|
|
277
|
+
if (style.shadow && style.shadow.opacity === 0)
|
|
278
|
+
warnings.push("shadow opacity is 0, so the shadow will not be visible");
|
|
279
|
+
if (style.strokes?.some((stroke) => stroke.width_px === 0))
|
|
280
|
+
warnings.push("a stroke with width 0 will not be visible");
|
|
281
|
+
return warnings;
|
|
282
|
+
}
|
|
283
|
+
const TRACK_STYLE_SELECT_STEPS = [
|
|
284
|
+
"Select one caption on the caption track in the timeline. One caption is enough: a Track Style applies to every caption on the track, so no multi-select is needed.",
|
|
285
|
+
"Open the Properties panel (Window > Properties). If your Premiere version has no Properties panel, use Window > Essential Graphics > Edit, which shows the same caption sections.",
|
|
286
|
+
];
|
|
287
|
+
function trackStyleSaveSteps(name) {
|
|
288
|
+
return [
|
|
289
|
+
`Track Style: open the Track Style dropdown in the Properties panel, choose "+ Create style", and name it "${name}". The style now applies to the whole caption track.`,
|
|
290
|
+
"Scrub through the track and confirm that the other captions show the new style.",
|
|
291
|
+
`Reuse: select a caption on the caption track in another sequence and pick "${name}" from the Track Style dropdown.`,
|
|
292
|
+
`The style is a project item in the Project panel. Move "${name}" into a shared bin (for example "Caption Styles") so other sequences and projects can reuse it.`,
|
|
293
|
+
"Verify the rendered look with export_frame or export_sequence_review_frames.",
|
|
294
|
+
];
|
|
295
|
+
}
|
|
296
|
+
const numbered = (steps) => steps.map((step, index) => `${index + 1}. ${step}`);
|
|
297
|
+
/** Premiere 2024+ Properties-panel / Track Style steps for a custom caption style. */
|
|
298
|
+
export function buildCustomCaptionStyleSteps(style, preset) {
|
|
299
|
+
const fallback = preset ? describeCaptionStyle(preset) : undefined;
|
|
300
|
+
const steps = [...TRACK_STYLE_SELECT_STEPS];
|
|
301
|
+
const text = [];
|
|
302
|
+
const family = style.font_family ?? fallback?.font_family_suggestion;
|
|
303
|
+
const weight = style.font_weight ?? fallback?.font_weight;
|
|
304
|
+
if (family)
|
|
305
|
+
text.push(`font family "${family}"`);
|
|
306
|
+
if (weight)
|
|
307
|
+
text.push(`font weight/style "${weight}"`);
|
|
308
|
+
if (style.font_size_px !== undefined)
|
|
309
|
+
text.push(`font size ${style.font_size_px}`);
|
|
310
|
+
else if (fallback)
|
|
311
|
+
text.push(`font size about ${fallback.font_size_percent_of_height}% of the frame height`);
|
|
312
|
+
if (text.length)
|
|
313
|
+
steps.push(`Text: set ${text.join(", ")}.`);
|
|
314
|
+
if (style.fill_color)
|
|
315
|
+
steps.push(`Appearance > Fill: turn Fill on and set the colour to ${style.fill_color}.`);
|
|
316
|
+
if (style.strokes) {
|
|
317
|
+
if (!style.strokes.length)
|
|
318
|
+
steps.push("Appearance > Stroke: turn Stroke off.");
|
|
319
|
+
style.strokes.forEach((stroke, index) => {
|
|
320
|
+
const values = `colour ${stroke.color}, width ${stroke.width_px}, ${stroke.placement} stroke`;
|
|
321
|
+
steps.push(index === 0
|
|
322
|
+
? `Appearance > Stroke: turn Stroke on and set the ${ordinal(index)} stroke to ${values}.`
|
|
323
|
+
: `Appearance > Stroke: press + next to Stroke to add stroke ${index + 1}, then set it to ${values}.`);
|
|
324
|
+
});
|
|
325
|
+
}
|
|
326
|
+
else if (fallback) {
|
|
327
|
+
steps.push(`Appearance > Stroke: ${fallback.stroke ? "turn Stroke on" : "leave Stroke off"} (preset ${fallback.preset}).`);
|
|
328
|
+
}
|
|
329
|
+
if (style.shadow) {
|
|
330
|
+
const shadow = style.shadow;
|
|
331
|
+
steps.push(`Appearance > Shadow: turn Shadow on and set colour ${shadow.color}, Opacity ${shadow.opacity}%, Angle ${shadow.angle}°, Distance ${shadow.distance}, Size ${shadow.size}, Blur ${shadow.blur}.`);
|
|
332
|
+
}
|
|
333
|
+
if (style.zone)
|
|
334
|
+
steps.push(`Align and Transform: choose the ${zoneLabel(style.zone)} cell in the caption region (zone) grid.`);
|
|
335
|
+
else if (fallback)
|
|
336
|
+
steps.push(`Align and Transform: place the caption centre near x=${fallback.position.x * 100}%, y=${fallback.position.y * 100}% of the frame (preset ${fallback.preset}).`);
|
|
337
|
+
if (style.offset_x_px !== undefined || style.offset_y_px !== undefined) {
|
|
338
|
+
steps.push(`Align and Transform: set the position offset to X ${style.offset_x_px ?? 0} and Y ${style.offset_y_px ?? 0} (pixels relative to the chosen zone; negative Y moves the caption up).`);
|
|
339
|
+
}
|
|
340
|
+
steps.push(...trackStyleSaveSteps(style.track_style_name ?? DEFAULT_TRACK_STYLE_NAME));
|
|
341
|
+
return numbered(steps);
|
|
342
|
+
}
|
|
343
|
+
/** Premiere 2024+ Properties-panel / Track Style steps for a built-in preset. */
|
|
344
|
+
export function buildPresetCaptionStyleSteps(style) {
|
|
345
|
+
const steps = [
|
|
346
|
+
...TRACK_STYLE_SELECT_STEPS,
|
|
347
|
+
`Text: set font family "${style.font_family_suggestion}", font weight ${style.font_weight}, and a font size of about ${style.font_size_percent_of_height}% of the frame height.`,
|
|
348
|
+
`Appearance > Stroke: ${style.stroke ? "turn Stroke on (press + next to Stroke for a second, wider outer stroke if you want a layered outline)" : "leave Stroke off"}.`,
|
|
349
|
+
`Appearance > Background: ${style.background ? "turn Background on and lower its opacity so the video stays visible" : "leave Background off"}.`,
|
|
350
|
+
`Align and Transform: centre-align the text and place the caption centre near x=${style.position.x * 100}%, y=${style.position.y * 100}% of the frame (normalized, centre-anchored).`,
|
|
351
|
+
...(style.word_highlight ? ["Word highlight: enable word highlighting for a karaoke-style progressive reveal where your Premiere version offers it."] : []),
|
|
352
|
+
...(style.uppercase_recommended ? ["Text: uppercase is recommended for this preset (use the All Caps option or the build_caption_artifact uppercase flag)."] : []),
|
|
353
|
+
...trackStyleSaveSteps(`${style.preset} captions`),
|
|
354
|
+
];
|
|
355
|
+
return numbered(steps);
|
|
356
|
+
}
|
|
357
|
+
export const CAPTION_TRACK_STYLE_GUIDANCE = {
|
|
358
|
+
scope: "A Track Style applies to every caption on the caption track. Style one caption, save it with Track Style > + Create style, and the whole track updates; no multi-select is needed.",
|
|
359
|
+
reusable: "A saved Track Style can be applied to the caption track of any other sequence in the project from the Track Style dropdown.",
|
|
360
|
+
project_item: "Each Track Style is stored as a project item in the Project panel; keep it in a shared bin so it can be found and reused.",
|
|
361
|
+
limitations: [
|
|
362
|
+
"Premiere Pro exposes no documented ExtendScript, QE DOM, or UXP API that creates, edits, or applies caption styles, so these steps must be performed in the Premiere UI.",
|
|
363
|
+
"These steps target Premiere Pro 2024 and later. Earlier versions lack the Track Style workflow described here and were not checked; panel labels can also differ between versions and UI languages.",
|
|
364
|
+
"Verify the rendered result with export_frame or export_sequence_review_frames; this tool cannot read the applied style back.",
|
|
365
|
+
],
|
|
366
|
+
};
|
|
367
|
+
export function captionSafeZoneRecommendation() {
|
|
368
|
+
return safeZoneRecommendation();
|
|
369
|
+
}
|
|
157
370
|
const toMs = (seconds) => Math.round(seconds * 1000);
|
|
158
371
|
const msToSeconds = (ms) => Number((ms / 1000).toFixed(3));
|
|
159
372
|
function pad(value, width) {
|