afterpresets 0.0.0-stage → 0.2.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/LICENSE +25 -0
- package/README.md +20 -2
- package/bin/ap.js +2 -0
- package/package.json +39 -4
- package/runtime/docs/cep/host-after-effects.md +57 -0
- package/runtime/docs/cep/host-premiere.md +84 -0
- package/runtime/docs/cep/host.md +128 -0
- package/runtime/docs/common/README.md +65 -0
- package/runtime/docs/common/assets.md +88 -0
- package/runtime/docs/common/boot.md +103 -0
- package/runtime/docs/common/licensing.md +261 -0
- package/runtime/docs/common/panels.md +114 -0
- package/runtime/docs/common/storage.md +82 -0
- package/runtime/docs/common/updates.md +251 -0
- package/runtime/package.json +5 -0
- package/runtime/runtime-files.json +14 -0
- package/runtime/src/boot.js +1 -0
- package/runtime/src/computer-id.js +1 -0
- package/runtime/src/core.js +1 -0
- package/runtime/src/events.js +1 -0
- package/runtime/src/host.js +1 -0
- package/runtime/src/license.js +1 -0
- package/runtime/src/panels.js +1 -0
- package/runtime/src/storage.js +1 -0
- package/runtime/src/updates.js +1 -0
- package/runtime/src/vendor/CSInterface.js +1 -0
- package/runtime/src/vendor/json2.jsx +506 -0
- package/runtime/src/zip.js +1 -0
- package/src/api/client.js +1 -0
- package/src/api/error-messages.js +1 -0
- package/src/api/session.js +1 -0
- package/src/args.js +1 -0
- package/src/auth/credentials.js +2 -0
- package/src/auth/logout.js +1 -0
- package/src/build/assets.js +1 -0
- package/src/build/build.js +9 -0
- package/src/build/bundle.js +5 -0
- package/src/build/html.js +4 -0
- package/src/build/jsx.js +3 -0
- package/src/build/jsxbin.js +1 -0
- package/src/build/runtime.js +4 -0
- package/src/check/check.js +3 -0
- package/src/check/extendscript-globals.d.ts +6 -0
- package/src/check/pricing.js +1 -0
- package/src/check/types.js +3 -0
- package/src/cli.js +5 -0
- package/src/commands/add.js +11 -0
- package/src/commands/build.js +6 -0
- package/src/commands/check.js +13 -0
- package/src/commands/config.js +7 -0
- package/src/commands/dev.js +6 -0
- package/src/commands/docs.js +1 -0
- package/src/commands/init.js +12 -0
- package/src/commands/login.js +3 -0
- package/src/commands/logout.js +1 -0
- package/src/commands/mcp.js +7 -0
- package/src/commands/push.js +7 -0
- package/src/commands/releases.js +5 -0
- package/src/commands/testers.js +1 -0
- package/src/commands/upgrade.js +2 -0
- package/src/commands/whoami.js +1 -0
- package/src/config.js +1 -0
- package/src/context.js +1 -0
- package/src/dev/cep-link.js +1 -0
- package/src/dev/debug-file.js +10 -0
- package/src/dev/debug-mode.js +1 -0
- package/src/dev/session.js +4 -0
- package/src/errors.js +1 -0
- package/src/mcp/capture.js +1 -0
- package/src/mcp/extendscript.js +9 -0
- package/src/mcp/panels.js +1 -0
- package/src/mcp/protocol.js +4 -0
- package/src/mcp/redact.js +1 -0
- package/src/mcp/server.js +2 -0
- package/src/mcp/snapshot.js +2 -0
- package/src/mcp/tools/account.js +3 -0
- package/src/mcp/tools/host.js +1 -0
- package/src/mcp/tools/panel.js +7 -0
- package/src/mcp/tools/project.js +40 -0
- package/src/mcp/tools/releases.js +29 -0
- package/src/output.js +6 -0
- package/src/project/add-panel.js +11 -0
- package/src/project/docs.js +3 -0
- package/src/project/manifest.js +6 -0
- package/src/project/panels.js +1 -0
- package/src/project/project.js +2 -0
- package/src/project/semver.js +1 -0
- package/src/project/template.js +4 -0
- package/src/prompt.js +1 -0
- package/src/release/installers.js +4 -0
- package/src/release/package.js +1 -0
- package/src/release/publish.js +1 -0
- package/src/system/run-command.js +1 -0
- package/src/system/update-check.js +2 -0
- package/src/targets.js +1 -0
- package/src/user-config.js +2 -0
- package/template/cep/.mcp.json +8 -0
- package/template/cep/AGENTS.md +169 -0
- package/template/cep/README.md +78 -0
- package/template/cep/docs/initial_setup.md +69 -0
- package/template/cep/gitignore +12 -0
- package/template/cep/package.json +14 -0
- package/template/cep/src/features/home/home.css +67 -0
- package/template/cep/src/features/home/home.html +23 -0
- package/template/cep/src/features/home/home.js +40 -0
- package/template/cep/src/features/license-screen/license-screen.css +80 -0
- package/template/cep/src/features/license-screen/license-screen.html +72 -0
- package/template/cep/src/features/license-screen/license-screen.js +60 -0
- package/template/cep/src/features/update-screen/update-screen.css +173 -0
- package/template/cep/src/features/update-screen/update-screen.html +57 -0
- package/template/cep/src/features/update-screen/update-screen.js +196 -0
- package/template/cep/src/panels/main/index.html +21 -0
- package/template/cep/src/panels/main/main.js +39 -0
- package/template/cep/src/shared/lib/dom.js +29 -0
- package/template/cep/src/shared/lib/host-theme.js +17 -0
- package/template/cep/src/shared/lib/markdown.js +109 -0
- package/template/cep/src/shared/lib/view.js +82 -0
- package/template/cep/src/shared/ui/base.css +60 -0
- package/template/cep/src/shared/ui/button.css +61 -0
- package/template/cep/src/shared/ui/card.css +22 -0
- package/template/cep/src/shared/ui/field.css +25 -0
- package/template/cep/src/shared/ui/index.css +7 -0
- package/template/cep/src/shared/ui/tokens.css +21 -0
- package/template/hosts/aeft/AGENTS.host.md +10 -0
- package/template/hosts/aeft/jsx/aeft/home.jsx +16 -0
- package/template/hosts/ppro/AGENTS.host.md +15 -0
- package/template/hosts/ppro/jsx/ppro/home.jsx +20 -0
- package/vendor/afterpresets-additions/AfterEffects.d.ts +291 -0
- package/vendor/afterpresets-additions/Premiere.d.ts +179 -0
- package/vendor/types-for-adobe/AfterEffects/26.0/index.d.ts +3403 -0
- package/vendor/types-for-adobe/LICENSE.md +21 -0
- package/vendor/types-for-adobe/Premiere/24.0/index.d.ts +2567 -0
- package/vendor/types-for-adobe/README.md +13 -0
- package/vendor/types-for-adobe/shared/JavaScript.d.ts +2761 -0
- package/vendor/types-for-adobe/shared/PlugPlugExternalObject.d.ts +91 -0
- package/vendor/types-for-adobe/shared/ScriptUI.d.ts +3012 -0
- package/vendor/types-for-adobe/shared/XMPScript.d.ts +72 -0
- package/vendor/types-for-adobe/shared/global.d.ts +152 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
AfterPresets CLI and Runtime License
|
|
2
|
+
|
|
3
|
+
Copyright (c) AfterPresets. All rights reserved.
|
|
4
|
+
|
|
5
|
+
This package ("the Software") contains the AfterPresets command-line tool and
|
|
6
|
+
the AfterPresets runtime.
|
|
7
|
+
|
|
8
|
+
You may install and use the Software only to create, test, build and publish
|
|
9
|
+
Adobe After Effects extensions that are distributed through AfterPresets
|
|
10
|
+
(afterpresets.com), and you may include the runtime in those extensions as
|
|
11
|
+
the Software's build process does.
|
|
12
|
+
|
|
13
|
+
You may not, except as the law expressly allows:
|
|
14
|
+
- modify, decompile, deobfuscate or reverse engineer the runtime, or remove,
|
|
15
|
+
disable or work around its licensing, signing or update checks;
|
|
16
|
+
- copy or redistribute the Software, or the runtime outside an extension
|
|
17
|
+
built with the Software;
|
|
18
|
+
- use the Software to build or distribute extensions outside AfterPresets.
|
|
19
|
+
|
|
20
|
+
Use of AfterPresets services is also governed by the AfterPresets Terms of
|
|
21
|
+
Service at https://afterpresets.com.
|
|
22
|
+
|
|
23
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
24
|
+
IMPLIED. IN NO EVENT SHALL AFTERPRESETS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
|
25
|
+
OTHER LIABILITY ARISING FROM THE SOFTWARE OR ITS USE.
|
package/README.md
CHANGED
|
@@ -1,3 +1,21 @@
|
|
|
1
|
-
#
|
|
1
|
+
# AfterPresets CLI
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Make Adobe After Effects extensions with an AI agent, and sell them on
|
|
4
|
+
[AfterPresets](https://afterpresets.com) with licensing, signed auto-updates
|
|
5
|
+
and checkout handled.
|
|
6
|
+
|
|
7
|
+
You do not need to write code. Open an empty folder in your agent (the Code
|
|
8
|
+
tab of the Claude desktop app, Claude Code, Codex, Cursor...) and follow the
|
|
9
|
+
**[Quickstart](https://docs.afterpresets.com/get-started/quickstart/)**.
|
|
10
|
+
|
|
11
|
+
```sh
|
|
12
|
+
npx afterpresets login
|
|
13
|
+
npx afterpresets init my-extension
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
Inside a project, `ap dev` puts the extension into After Effects and reloads
|
|
17
|
+
it on every save, `ap push` publishes a release, and `ap upgrade` updates
|
|
18
|
+
this package. Every project includes `AGENTS.md` and an MCP server
|
|
19
|
+
(`ap mcp`) so your agent can see, click and test the live panel.
|
|
20
|
+
|
|
21
|
+
Docs: https://docs.afterpresets.com
|
package/bin/ap.js
ADDED
package/package.json
CHANGED
|
@@ -1,6 +1,41 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "afterpresets",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"description": "Create, develop, and publish Adobe CEP extensions on AfterPresets.",
|
|
5
|
+
"license": "SEE LICENSE IN LICENSE",
|
|
6
|
+
"homepage": "https://docs.afterpresets.com",
|
|
7
|
+
"keywords": [
|
|
8
|
+
"after effects",
|
|
9
|
+
"adobe",
|
|
10
|
+
"cep",
|
|
11
|
+
"extension",
|
|
12
|
+
"afterpresets",
|
|
13
|
+
"mcp"
|
|
14
|
+
],
|
|
15
|
+
"bin": {
|
|
16
|
+
"ap": "bin/ap.js",
|
|
17
|
+
"afterpresets": "bin/ap.js"
|
|
18
|
+
},
|
|
19
|
+
"files": [
|
|
20
|
+
"bin",
|
|
21
|
+
"src",
|
|
22
|
+
"runtime",
|
|
23
|
+
"template",
|
|
24
|
+
"vendor",
|
|
25
|
+
"LICENSE"
|
|
26
|
+
],
|
|
27
|
+
"engines": {
|
|
28
|
+
"node": ">=20"
|
|
29
|
+
},
|
|
30
|
+
"dependencies": {
|
|
31
|
+
"adm-zip": "0.5.16",
|
|
32
|
+
"chokidar": "3.6.0",
|
|
33
|
+
"esbuild": "0.25.12",
|
|
34
|
+
"jsxbin": "2.3.0",
|
|
35
|
+
"playwright-core": "1.64.1",
|
|
36
|
+
"typescript": "5.9.3"
|
|
37
|
+
},
|
|
38
|
+
"afterpresets": {
|
|
39
|
+
"runtimeVersion": "0.4.0"
|
|
40
|
+
}
|
|
41
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: After Effects ExtendScript
|
|
3
|
+
description: "Rules for ExtendScript in After Effects (jsx/aeft/): undo groups, the active composition, 1-based collections, and the version range."
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# After Effects ExtendScript
|
|
7
|
+
|
|
8
|
+
Read [host.md](host.md) first: it explains `AP.host.eval` and how `jsx/` is
|
|
9
|
+
loaded. This page is about code that runs in After Effects. Put code that only
|
|
10
|
+
makes sense in After Effects in `jsx/aeft/`.
|
|
11
|
+
|
|
12
|
+
## Undo
|
|
13
|
+
|
|
14
|
+
Wrap every change in one undo group so the user undoes the whole action with
|
|
15
|
+
one Ctrl/Cmd+Z, and close it in `finally`:
|
|
16
|
+
|
|
17
|
+
```js
|
|
18
|
+
app.beginUndoGroup("Rename layers");
|
|
19
|
+
try {
|
|
20
|
+
/* changes */
|
|
21
|
+
} finally {
|
|
22
|
+
app.endUndoGroup();
|
|
23
|
+
}
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
The MCP `host_eval` tool already wraps each call in an undo group named
|
|
27
|
+
"AfterPresets MCP".
|
|
28
|
+
|
|
29
|
+
## The active composition
|
|
30
|
+
|
|
31
|
+
`app.project.activeItem` is often null or not a composition (a footage item, a
|
|
32
|
+
folder, or nothing selected). Check before using it:
|
|
33
|
+
|
|
34
|
+
```js
|
|
35
|
+
var comp = app.project.activeItem;
|
|
36
|
+
if (!comp || !(comp instanceof CompItem)) {
|
|
37
|
+
return JSON.stringify({ ok: false, message: "Open or select a composition first." });
|
|
38
|
+
}
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## Collections and times
|
|
42
|
+
|
|
43
|
+
- Collections are 1-based: `comp.layer(1)`, `app.project.item(1)`,
|
|
44
|
+
`comp.selectedLayers[0]` (a plain array, 0-based).
|
|
45
|
+
- Times are seconds (floating point). `comp.frameDuration` is one frame.
|
|
46
|
+
|
|
47
|
+
## Versions
|
|
48
|
+
|
|
49
|
+
The extension's range is `hosts[].minVersion` in afterpresets.json (default
|
|
50
|
+
17.0, After Effects 2020). Check `parseFloat(app.version)` before using newer
|
|
51
|
+
APIs and return `{ ok: false, message }` when they are missing.
|
|
52
|
+
|
|
53
|
+
## Type hints
|
|
54
|
+
|
|
55
|
+
`ap check --types` checks `jsx/` against the After Effects 26.0 declarations
|
|
56
|
+
from types-for-adobe and lists likely mistakes. Hints can be wrong; confirm
|
|
57
|
+
with the MCP `host_eval` tool before changing working code.
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Premiere Pro ExtendScript
|
|
3
|
+
description: "Rules for ExtendScript in Premiere Pro (jsx/ppro/): no undo groups, times in ticks, 0-based track and clip collections, no QE DOM, and the version range."
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Premiere Pro ExtendScript
|
|
7
|
+
|
|
8
|
+
Read [host.md](host.md) first: it explains `AP.host.eval` and how `jsx/` is
|
|
9
|
+
loaded. This page is about code that runs in Premiere Pro. Put code that only
|
|
10
|
+
makes sense in Premiere Pro in `jsx/ppro/`.
|
|
11
|
+
|
|
12
|
+
## No undo groups
|
|
13
|
+
|
|
14
|
+
Premiere Pro's ExtendScript has no `beginUndoGroup`. Every change a script
|
|
15
|
+
makes (a clip moved, a marker added, a property set) is its own step in
|
|
16
|
+
Edit → Undo. Keep scripted edits small, do the checks before the first change,
|
|
17
|
+
and tell the user how many undo steps an action adds. The MCP `host_eval`
|
|
18
|
+
tool cannot group them either.
|
|
19
|
+
|
|
20
|
+
## The active sequence
|
|
21
|
+
|
|
22
|
+
`app.project.activeSequence` is null when no sequence is open. Check it:
|
|
23
|
+
|
|
24
|
+
```js
|
|
25
|
+
function myTool_sequenceInfo() {
|
|
26
|
+
var sequence = app.project.activeSequence;
|
|
27
|
+
if (!sequence) return JSON.stringify({ ok: false, message: "Open a sequence first." });
|
|
28
|
+
var clips = 0;
|
|
29
|
+
for (var i = 0; i < sequence.videoTracks.numTracks; i++) {
|
|
30
|
+
clips += sequence.videoTracks[i].clips.numItems;
|
|
31
|
+
}
|
|
32
|
+
return JSON.stringify({ ok: true, name: sequence.name, videoClips: clips });
|
|
33
|
+
}
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## Collections
|
|
37
|
+
|
|
38
|
+
Tracks, clips, sequences and project items are 0-based collections with a
|
|
39
|
+
count property: `sequence.videoTracks[0]` with `numTracks`,
|
|
40
|
+
`track.clips[0]` with `numItems`, `app.project.sequences[0]` with
|
|
41
|
+
`numSequences`, `app.project.rootItem.children[0]` with `numItems`. Use a
|
|
42
|
+
`for` loop; they are not arrays.
|
|
43
|
+
|
|
44
|
+
## Times are ticks
|
|
45
|
+
|
|
46
|
+
Premiere measures time in ticks: **254016000000 ticks per second**. A `Time`
|
|
47
|
+
object has `.seconds` (a number) and `.ticks` (a string). Create one with
|
|
48
|
+
`new Time()` and set either:
|
|
49
|
+
|
|
50
|
+
```js
|
|
51
|
+
var t = new Time();
|
|
52
|
+
t.seconds = 2.5;
|
|
53
|
+
app.project.activeSequence.setPlayerPosition(t.ticks); // move the playhead to 2.5 s
|
|
54
|
+
var startSeconds = clip.start.seconds; // read a clip's start
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
Frame-accurate maths: convert with the sequence's timebase
|
|
58
|
+
(`sequence.timebase`, ticks per frame, a string) instead of rounding seconds.
|
|
59
|
+
|
|
60
|
+
## Things not to use
|
|
61
|
+
|
|
62
|
+
- **The QE DOM** (`app.enableQE()`, `qe.*`): undocumented, unsupported, and
|
|
63
|
+
it changes between versions. Do not ship code that needs it.
|
|
64
|
+
- Dialogs (`alert`, `confirm`, `File.openDialog`) block Premiere Pro while
|
|
65
|
+
open; the panel can show its own UI instead.
|
|
66
|
+
|
|
67
|
+
## Projects
|
|
68
|
+
|
|
69
|
+
- `app.project` is the active project. Premiere Pro can have several projects
|
|
70
|
+
open (`app.projects`, `numProjects`).
|
|
71
|
+
- Save with `app.project.save()`. The MCP `host_scratch_project` tool creates a
|
|
72
|
+
new project in the temp folder and leaves the user's project open.
|
|
73
|
+
|
|
74
|
+
## Versions
|
|
75
|
+
|
|
76
|
+
The extension's range is `hosts[].minVersion` in afterpresets.json (default
|
|
77
|
+
14.0, Premiere Pro 2020). Check `app.version` before using newer APIs and
|
|
78
|
+
return `{ ok: false, message }` when they are missing.
|
|
79
|
+
|
|
80
|
+
## Type hints
|
|
81
|
+
|
|
82
|
+
`ap check --types` checks `jsx/` against the Premiere Pro 24.0 declarations
|
|
83
|
+
from types-for-adobe (the newest set; newer APIs may be missing) and lists
|
|
84
|
+
likely mistakes. Hints can be wrong; confirm with the MCP `host_eval` tool.
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Calling the app (ExtendScript)
|
|
3
|
+
description: Call ExtendScript functions in After Effects or Premiere Pro from a panel with AP.host.eval, write jsx/ functions in ES3 that return JSON, keep app-only code in jsx/aeft/ and jsx/ppro/, and handle host errors.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Calling the app (ExtendScript)
|
|
7
|
+
|
|
8
|
+
Panel code runs in a browser. Anything that touches the app (the project, its
|
|
9
|
+
compositions or sequences, layers or clips, files through `File`/`Folder`) runs
|
|
10
|
+
in ExtendScript, in `jsx/`. `AP.host.eval` connects the two. It works the same
|
|
11
|
+
in After Effects and Premiere Pro. What you can do in each app:
|
|
12
|
+
|
|
13
|
+
- [host-after-effects.md](host-after-effects.md): After Effects
|
|
14
|
+
- [host-premiere.md](host-premiere.md): Premiere Pro
|
|
15
|
+
|
|
16
|
+
## Where JSX lives
|
|
17
|
+
|
|
18
|
+
Put ExtendScript in `jsx/`, one file per feature (for example
|
|
19
|
+
`jsx/layers.jsx`; subfolders are fine). Every `.jsx` file there is loaded into
|
|
20
|
+
the app once, before your app starts, and its functions are shared by
|
|
21
|
+
all panels. Call one from panel code with `ctx.host.eval("fnName", [args], cb)`.
|
|
22
|
+
|
|
23
|
+
Two folders are special (afterpresets.json `hosts` lists the apps):
|
|
24
|
+
|
|
25
|
+
| Folder | Loaded in |
|
|
26
|
+
|---|---|
|
|
27
|
+
| `jsx/aeft/` | After Effects only |
|
|
28
|
+
| `jsx/ppro/` | Premiere Pro only |
|
|
29
|
+
| everything else in `jsx/` | every app the extension targets |
|
|
30
|
+
|
|
31
|
+
An extension for both apps can define the same function in `jsx/aeft/` and
|
|
32
|
+
`jsx/ppro/` (for example `myTool_activeItemName`) and call it from shared panel
|
|
33
|
+
code; each app loads its own version. `ap check` warns about a folder for an
|
|
34
|
+
app the project does not target.
|
|
35
|
+
|
|
36
|
+
- There is no list to keep: the CLI joins every `.jsx` file in alphabetical
|
|
37
|
+
path order, with JSON support (json2) first, embeds the result in every
|
|
38
|
+
panel's `main.js` (readable in `ap dev`, compiled to JSXBIN for releases),
|
|
39
|
+
and the runtime evaluates it as soon as `AP.boot` runs, before `start`.
|
|
40
|
+
Every `AP.host.eval` waits for that load.
|
|
41
|
+
- Order only matters for code that runs at the top level of a file while it
|
|
42
|
+
loads (not inside a function). Keep files to function declarations.
|
|
43
|
+
|
|
44
|
+
## Writing a JSX function
|
|
45
|
+
|
|
46
|
+
ExtendScript is **ES3**: `var` only, no `let`/`const`, no arrow functions, no
|
|
47
|
+
`Array.prototype.forEach`/`map`/`indexOf`, no `trim()`, no template strings.
|
|
48
|
+
`JSON` is always available (the CLI adds json2).
|
|
49
|
+
|
|
50
|
+
Rules:
|
|
51
|
+
|
|
52
|
+
1. Declare a named top-level function. Avoid generic names; prefix them
|
|
53
|
+
(`myTool_addNull`), because every extension shares one ExtendScript engine.
|
|
54
|
+
2. Take JSON-compatible arguments (strings, numbers, booleans, arrays, plain
|
|
55
|
+
objects).
|
|
56
|
+
3. Return `JSON.stringify(...)`. Return a result object such as `{ ok: true, ... }`
|
|
57
|
+
or `{ ok: false, message: "..." }` for expected problems.
|
|
58
|
+
4. Undo: in After Effects wrap changes in one undo group; Premiere Pro has
|
|
59
|
+
none (every change is its own undo step). See the app pages.
|
|
60
|
+
|
|
61
|
+
```js
|
|
62
|
+
/* jsx/aeft/layers.jsx (After Effects) */
|
|
63
|
+
function myTool_addNull(name) {
|
|
64
|
+
var comp = app.project.activeItem;
|
|
65
|
+
if (!comp || !(comp instanceof CompItem)) {
|
|
66
|
+
return JSON.stringify({ ok: false, message: "Select a composition first." });
|
|
67
|
+
}
|
|
68
|
+
app.beginUndoGroup("Add null");
|
|
69
|
+
try {
|
|
70
|
+
var layer = comp.layers.addNull();
|
|
71
|
+
layer.name = name;
|
|
72
|
+
return JSON.stringify({ ok: true, index: layer.index });
|
|
73
|
+
} finally {
|
|
74
|
+
app.endUndoGroup();
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
## Calling it from the panel
|
|
80
|
+
|
|
81
|
+
```js
|
|
82
|
+
AP.host.eval("myTool_addNull", ["Controller"], function (result) {
|
|
83
|
+
if (!result || result.error) {
|
|
84
|
+
showError(result ? result.error : "No answer from the app.");
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
if (!result.ok) {
|
|
88
|
+
showMessage(result.message);
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
showMessage("Added layer " + result.index);
|
|
92
|
+
});
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
`AP.host.eval(fnName, args, cb)`:
|
|
96
|
+
|
|
97
|
+
- `fnName` is a function name or dotted path (`"myTool.addNull"`). Anything else
|
|
98
|
+
is refused with `{ error }`.
|
|
99
|
+
- `args` is an array. Each value is passed as a JSON literal, so quotes,
|
|
100
|
+
newlines, and code in strings are safe. `undefined` becomes `null`.
|
|
101
|
+
- `cb(result)` receives the parsed JSON your function returned, `null` when it
|
|
102
|
+
returned nothing, or `{ error: "message" }` when anything failed.
|
|
103
|
+
|
|
104
|
+
Never build ExtendScript source by joining strings with user input. Always pass
|
|
105
|
+
values through `args`.
|
|
106
|
+
|
|
107
|
+
## Errors
|
|
108
|
+
|
|
109
|
+
| `result` | Cause |
|
|
110
|
+
|---|---|
|
|
111
|
+
| `{ error: "<message>" }` | Your function threw; the message is the thrown error's message. |
|
|
112
|
+
| `{ error: "...is undefined" }` or similar | The function does not exist: check the name, that its file is in `jsx/` and ends in `.jsx`, and that it is not in another app's folder (`jsx/aeft/`, `jsx/ppro/`). |
|
|
113
|
+
| `{ error: "The host returned a non-JSON result.", raw }` | Your function returned a plain string. Return `JSON.stringify(...)`. |
|
|
114
|
+
| `{ error: "The host script failed to run." }` | ExtendScript syntax error or an ES5+ feature in `jsx/`. |
|
|
115
|
+
| `{ error: "Could not load host script: ..." }` | The embedded JSX failed to load. Read the message; usually a syntax error. "This extension has no host script for X" means the build has no code for the running app (afterpresets.json `hosts`). |
|
|
116
|
+
|
|
117
|
+
The JSX loads once per page. During `ap dev` every save rebuilds and reloads
|
|
118
|
+
the open panels, which loads the new JSX too; after an update,
|
|
119
|
+
`AP.updates.reload()` does the same. The new functions replace the old ones.
|
|
120
|
+
Functions removed from the new code stay defined in the app until it
|
|
121
|
+
restarts, so never rely on a function being absent.
|
|
122
|
+
|
|
123
|
+
## Testing
|
|
124
|
+
|
|
125
|
+
Call the function from the live panel and check the result and the project
|
|
126
|
+
state. Use a disposable project (the MCP `host_scratch_project` tool) for
|
|
127
|
+
anything that changes the project. With the MCP tools, `host_eval` runs in the
|
|
128
|
+
app that runs the connected panel.
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: AfterPresets runtime reference
|
|
3
|
+
description: What the AfterPresets runtime does, and which reference file to read before you use any AP.* API.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# AfterPresets runtime reference
|
|
7
|
+
|
|
8
|
+
These files are for the AI coding agent that builds an After Effects or Premiere
|
|
9
|
+
Pro extension with AfterPresets. They describe the `AP.*` API that every panel gets.
|
|
10
|
+
|
|
11
|
+
## What the runtime does
|
|
12
|
+
|
|
13
|
+
The runtime is a small script that the AfterPresets CLI puts in front of each
|
|
14
|
+
panel's JavaScript. It is logic only. It draws nothing: your project owns every
|
|
15
|
+
screen, style, and word the user sees.
|
|
16
|
+
|
|
17
|
+
It gives you:
|
|
18
|
+
|
|
19
|
+
- `AP.boot` to start the panel.
|
|
20
|
+
- Licensing, off by default. Paid extensions must turn it on.
|
|
21
|
+
- Signed updates with changelogs.
|
|
22
|
+
- `AP.host.eval` to call ExtendScript functions in the app (After Effects or Premiere Pro).
|
|
23
|
+
- `AP.panels` and `AP.events` for extensions with more than one panel.
|
|
24
|
+
- `AP.paths` to find the images, videos and other files you ship.
|
|
25
|
+
- `AP.storage` to save settings and other small data on this computer.
|
|
26
|
+
|
|
27
|
+
Do not edit the runtime and do not copy it into your source files. The CLI
|
|
28
|
+
adds it for you. `ap docs` refreshes this folder from the installed runtime.
|
|
29
|
+
|
|
30
|
+
## The rule
|
|
31
|
+
|
|
32
|
+
**Read the relevant file below before you write or change code that uses
|
|
33
|
+
`AP.*`.** Do not guess option names, statuses, or callback shapes. If a file
|
|
34
|
+
and your memory disagree, the file wins.
|
|
35
|
+
|
|
36
|
+
## Files
|
|
37
|
+
|
|
38
|
+
| File | Read it before you |
|
|
39
|
+
|---|---|
|
|
40
|
+
| [boot.md](boot.md) | call `AP.boot`, use `ctx`, or change when the app starts |
|
|
41
|
+
| [licensing.md](licensing.md) | turn licensing on, write `renderLicense`, or change the license screen |
|
|
42
|
+
| [updates.md](updates.md) | change update options or the update screen, or show a changelog |
|
|
43
|
+
| [host.md](host.md) | call the app from the panel or write `jsx/` code |
|
|
44
|
+
| [host-after-effects.md](host-after-effects.md) | write ExtendScript for After Effects (`jsx/aeft/`) |
|
|
45
|
+
| [host-premiere.md](host-premiere.md) | write ExtendScript for Premiere Pro (`jsx/ppro/`) |
|
|
46
|
+
| [panels.md](panels.md) | add a panel or modal, open/close panels, or send data between panels |
|
|
47
|
+
| [assets.md](assets.md) | add images, fonts, videos or other files, or import a file into the app |
|
|
48
|
+
| [storage.md](storage.md) | save settings, recent items or any other data between launches |
|
|
49
|
+
|
|
50
|
+
## Commands you will use
|
|
51
|
+
|
|
52
|
+
```sh
|
|
53
|
+
ap dev # build, link into the app, rebuild on change
|
|
54
|
+
ap check # static checks; also run by ap dev and ap push
|
|
55
|
+
ap add panel settings --type modal
|
|
56
|
+
ap push # publish a release (asks for version bump and changelog)
|
|
57
|
+
ap docs # refresh docs/afterpresets/ from the runtime
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
## Compatibility
|
|
61
|
+
|
|
62
|
+
Panels run in Adobe CEP 10 or later (After Effects 2020+, Premiere Pro 2020+). Its browser is old
|
|
63
|
+
(Chromium 74 in CEP 10). Write plain ES5 in panel code: `var`, `function`, no
|
|
64
|
+
arrow functions, no `let`/`const`, no `class`, no template strings, no
|
|
65
|
+
`fetch`-only features. ExtendScript in `jsx/` is ES3 (see [host.md](host.md)).
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Media and other files
|
|
3
|
+
description: Where to put images, fonts, videos, presets and other files your extension ships, and how to use them from HTML, CSS, JavaScript and ExtendScript.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Media and other files
|
|
7
|
+
|
|
8
|
+
Put files your extension ships in these folders at the **project root**
|
|
9
|
+
(next to `afterpresets.json`):
|
|
10
|
+
|
|
11
|
+
```
|
|
12
|
+
assets/ fonts/ icons/ images/ media/
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
They are copied into the build unchanged, at the same place: `media/intro.mp4`
|
|
16
|
+
in the project is `media/intro.mp4` inside the installed extension. Other
|
|
17
|
+
folders are not shipped. To choose your own list, set it in
|
|
18
|
+
`afterpresets.json` (this replaces the defaults):
|
|
19
|
+
|
|
20
|
+
```json
|
|
21
|
+
"assets": ["media", "presets", "fonts"]
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
These files are **not** obfuscated or hidden. Anything the buyer installs, they
|
|
25
|
+
can open. Keep secrets out of them. The whole release must stay under 200 MB.
|
|
26
|
+
|
|
27
|
+
## From HTML and CSS
|
|
28
|
+
|
|
29
|
+
Write paths relative to the file you are in, as usual. They must point into
|
|
30
|
+
an asset folder; the build rewrites them for the installed extension and fails
|
|
31
|
+
on a missing file.
|
|
32
|
+
|
|
33
|
+
```html
|
|
34
|
+
<!-- src/panels/main/index.html -->
|
|
35
|
+
<img src="../../../images/logo.png" alt="">
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
```css
|
|
39
|
+
/* src/features/home/home.css */
|
|
40
|
+
.hero { background-image: url(../../../images/hero.jpg); }
|
|
41
|
+
@font-face { font-family: "Brand"; src: url(../../../fonts/Brand.woff2); }
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## From JavaScript
|
|
45
|
+
|
|
46
|
+
Use `AP.paths`; never build paths by hand.
|
|
47
|
+
|
|
48
|
+
| Call | Returns |
|
|
49
|
+
|---|---|
|
|
50
|
+
| `AP.paths.asset("media/intro.mp4")` | Absolute path of a shipped file. Relative path with `/`; `..` and absolute paths throw. |
|
|
51
|
+
| `AP.paths.extension()` | Absolute path of the installed extension folder. |
|
|
52
|
+
| `AP.paths.data()` | A writable folder for your own files. It survives updates. Never write into the extension folder: updates replace it. For settings use `AP.storage`; see [storage.md](storage.md). |
|
|
53
|
+
|
|
54
|
+
## From ExtendScript (importing into the app)
|
|
55
|
+
|
|
56
|
+
ExtendScript cannot see the panel's folders by itself. Pass the absolute path
|
|
57
|
+
from the panel:
|
|
58
|
+
|
|
59
|
+
```js
|
|
60
|
+
// panel
|
|
61
|
+
ctx.host.eval("importClip", [AP.paths.asset("media/intro.mp4")], function (result) {
|
|
62
|
+
if (result && result.error) { /* show result.error */ }
|
|
63
|
+
});
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
```js
|
|
67
|
+
// After Effects: jsx/aeft/media.jsx (loaded automatically, like every .jsx file in jsx/)
|
|
68
|
+
function importClip(path) {
|
|
69
|
+
var file = new File(path);
|
|
70
|
+
if (!file.exists) return JSON.stringify({ error: "Missing file: " + path });
|
|
71
|
+
var item = app.project.importFile(new ImportOptions(file));
|
|
72
|
+
return JSON.stringify({ ok: true, name: item.name });
|
|
73
|
+
}
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
```js
|
|
77
|
+
// Premiere Pro: jsx/ppro/media.jsx
|
|
78
|
+
function importClip(path) {
|
|
79
|
+
var file = new File(path);
|
|
80
|
+
if (!file.exists) return JSON.stringify({ error: "Missing file: " + path });
|
|
81
|
+
// importFiles(paths, suppressUI, targetBin, importAsNumberedStills)
|
|
82
|
+
var ok = app.project.importFiles([file.fsName], true, app.project.getInsertionBin(), false);
|
|
83
|
+
return JSON.stringify({ ok: ok === true, name: file.name });
|
|
84
|
+
}
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
Both files define the same function name: an extension for both apps calls
|
|
88
|
+
`importClip` and each app loads its own version.
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: AP.boot
|
|
3
|
+
description: Start a panel with AP.boot. Options, the ctx object passed to start, and the boot lifecycle.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# AP.boot
|
|
7
|
+
|
|
8
|
+
Every panel calls `AP.boot` exactly once, from its `src/panels/<id>/main.js`
|
|
9
|
+
code. `ap check` fails when a panel never calls it.
|
|
10
|
+
|
|
11
|
+
```js
|
|
12
|
+
AP.boot({
|
|
13
|
+
start: function (ctx) {
|
|
14
|
+
// Build your UI here.
|
|
15
|
+
},
|
|
16
|
+
license: false, // default. true, or { offlineGraceDays, checkInBackground }
|
|
17
|
+
renderLicense: function (api, root) {}, // required when license is on
|
|
18
|
+
updates: { check: "auto", mode: "background" } // defaults
|
|
19
|
+
});
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## Options
|
|
23
|
+
|
|
24
|
+
| Option | Type | Default | Meaning |
|
|
25
|
+
|---|---|---|---|
|
|
26
|
+
| `start` | `function (ctx)` | required | Your app. Called once, when the panel may run. |
|
|
27
|
+
| `license` | `false`, `true`, or `{ offlineGraceDays, checkInBackground }` | `false` | Turns licensing on. See [licensing.md](licensing.md). |
|
|
28
|
+
| `renderLicense` | `function (api, root)` | none | Draws the license screen. Required when `license` is on. |
|
|
29
|
+
| `updates.check` | `"auto"` or `"manual"` | `"auto"` | `"auto"` checks at start and every 6 hours. See [updates.md](updates.md). |
|
|
30
|
+
| `updates.mode` | `"background"`, `"prompt"` or `"silent"` | `"background"` | What happens when an update is found. `"background"` installs it without asking, then your update screen offers **Reload now** (`AP.updates.reload()`). `"prompt"` waits for your Install button. `"silent"` installs and shows nothing. See [updates.md](updates.md). |
|
|
31
|
+
|
|
32
|
+
Unknown values are replaced by the default with a console warning. If
|
|
33
|
+
`license` is on and `renderLicense` is missing, `AP.boot` logs an error and
|
|
34
|
+
throws; the panel stays empty.
|
|
35
|
+
|
|
36
|
+
## ctx
|
|
37
|
+
|
|
38
|
+
`start(ctx)` receives:
|
|
39
|
+
|
|
40
|
+
```js
|
|
41
|
+
ctx = {
|
|
42
|
+
product: { bundleId: "com.afterpresets.seller.tool", version: "1.2.0" },
|
|
43
|
+
panel: { id: "main" }, // this panel's id from afterpresets.json
|
|
44
|
+
license: AP.license, // license api; status is "disabled" when licensing is off
|
|
45
|
+
updates: AP.updates, // see updates.md
|
|
46
|
+
host: AP.host // see host.md
|
|
47
|
+
};
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
The same objects are also available as globals (`AP.license`, `AP.updates`,
|
|
51
|
+
`AP.host`, `AP.panels`, `AP.events`) for code that runs outside `start`.
|
|
52
|
+
|
|
53
|
+
## Lifecycle
|
|
54
|
+
|
|
55
|
+
1. The page loads. The runtime is already defined; nothing has run yet.
|
|
56
|
+
2. Your entry code calls `AP.boot(options)`.
|
|
57
|
+
3. When the DOM is ready:
|
|
58
|
+
- **License off:** `AP.license.state.status` is `"disabled"` and `start(ctx)`
|
|
59
|
+
runs immediately.
|
|
60
|
+
- **License on:** the runtime adds an empty `<div id="ap-license-root">` to
|
|
61
|
+
`<body>`, calls `renderLicense(api, root)`, and validates the license.
|
|
62
|
+
`start(ctx)` runs once the status becomes `active` or `offline_grace`.
|
|
63
|
+
It never runs for any other status.
|
|
64
|
+
4. After `start`, if `updates.check` is `"auto"`, the runtime checks for updates
|
|
65
|
+
now and every 6 hours. In the default `"background"` mode a found update is
|
|
66
|
+
installed right away and `AP.updates.onInstalled` fires; the panel keeps
|
|
67
|
+
running the old version until `AP.updates.reload()` or the next launch.
|
|
68
|
+
|
|
69
|
+
`start` runs at most once per panel load. If the license later becomes invalid
|
|
70
|
+
(for example the buyer signs out), the license root is shown again over your
|
|
71
|
+
app; `start` is not called a second time.
|
|
72
|
+
|
|
73
|
+
## Example: a free extension
|
|
74
|
+
|
|
75
|
+
```js
|
|
76
|
+
AP.boot({
|
|
77
|
+
start: function (ctx) {
|
|
78
|
+
var app = document.getElementById("app");
|
|
79
|
+
app.textContent = "Hello from " + ctx.product.bundleId + " (" + ctx.panel.id + ")";
|
|
80
|
+
}
|
|
81
|
+
});
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
## Example: a paid extension
|
|
85
|
+
|
|
86
|
+
```js
|
|
87
|
+
AP.boot({
|
|
88
|
+
start: function (ctx) {
|
|
89
|
+
renderHome(document.getElementById("app"), ctx); // imported from src/features/home/home.js
|
|
90
|
+
},
|
|
91
|
+
license: true,
|
|
92
|
+
renderLicense: renderLicense, // imported; see licensing.md
|
|
93
|
+
updates: { check: "auto", mode: "background" }
|
|
94
|
+
});
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
## Mistakes to avoid
|
|
98
|
+
|
|
99
|
+
- Do not build app UI before `start` runs. Put it inside `start`.
|
|
100
|
+
- Do not call `start` yourself, and do not call `AP.boot` twice (the second call
|
|
101
|
+
is ignored with a warning).
|
|
102
|
+
- Do not wrap `AP.boot` in `try/catch` to hide the missing-`renderLicense`
|
|
103
|
+
error. Fix the options instead.
|