afterpresets 0.2.0 → 0.3.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/README.md +6 -4
- package/native-runtime/CMakeLists.txt +82 -0
- package/native-runtime/README.md +40 -0
- package/native-runtime/THIRD_PARTY_NOTICES.md +14 -0
- package/native-runtime/include/ap_native.h +223 -0
- package/native-runtime/src/apply.cpp +199 -0
- package/native-runtime/src/crypto.cpp +225 -0
- package/native-runtime/src/crypto.hpp +51 -0
- package/native-runtime/src/dialog.cpp +62 -0
- package/native-runtime/src/dialog.hpp +35 -0
- package/native-runtime/src/engine.cpp +909 -0
- package/native-runtime/src/engine.hpp +232 -0
- package/native-runtime/src/fsutil.cpp +291 -0
- package/native-runtime/src/fsutil.hpp +57 -0
- package/native-runtime/src/json.cpp +326 -0
- package/native-runtime/src/json.hpp +70 -0
- package/native-runtime/src/platform.hpp +83 -0
- package/native-runtime/src/platform_common.cpp +60 -0
- package/native-runtime/src/platform_mac.mm +314 -0
- package/native-runtime/src/platform_win.cpp +277 -0
- package/native-runtime/src/runtime.cpp +473 -0
- package/native-runtime/src/util.cpp +169 -0
- package/native-runtime/src/util.hpp +32 -0
- package/native-runtime/src/zip.cpp +243 -0
- package/native-runtime/src/zip.hpp +58 -0
- package/native-runtime/third_party/monocypher/LICENCE.md +167 -0
- package/native-runtime/third_party/monocypher/monocypher-ed25519.c +500 -0
- package/native-runtime/third_party/monocypher/monocypher-ed25519.h +140 -0
- package/native-runtime/third_party/monocypher/monocypher.c +2956 -0
- package/native-runtime/third_party/monocypher/monocypher.h +321 -0
- package/native-runtime/third_party/tinf/LICENSE +22 -0
- package/native-runtime/third_party/tinf/crc32.c +57 -0
- package/native-runtime/third_party/tinf/tinf.h +140 -0
- package/native-runtime/third_party/tinf/tinflate.c +636 -0
- package/native-runtime/vendor-files.json +39 -0
- package/package.json +6 -3
- package/runtime/docs/cep/host.md +8 -0
- package/runtime/docs/common/README.md +1 -1
- package/runtime/docs/native/README.md +44 -0
- package/runtime/docs/native/debugging.md +140 -0
- package/runtime/docs/native/rules.md +402 -0
- package/runtime/docs/native/testing.md +154 -0
- package/runtime/package.json +1 -1
- package/runtime/scripts/ae-sdk-docs/config.js +102 -0
- package/runtime/scripts/ae-sdk-docs/convert.js +430 -0
- package/runtime/scripts/ae-sdk-docs/index.js +314 -0
- package/runtime/scripts/ae-sdk-docs/source.js +205 -0
- package/runtime/scripts/ae-sdk-docs/split.js +170 -0
- package/runtime/scripts/ae-sdk-docs.js +72 -0
- package/runtime/src/host.js +1 -1
- package/src/api/error-messages.js +1 -1
- package/src/check/check.js +3 -3
- package/src/check/native.js +14 -0
- package/src/check/pricing.js +1 -1
- package/src/cli.js +2 -2
- package/src/commands/build.js +8 -2
- package/src/commands/check.js +10 -2
- package/src/commands/dev.js +9 -2
- package/src/commands/docs.js +5 -1
- package/src/commands/init.js +10 -7
- package/src/commands/push.js +5 -2
- package/src/commands/sdk.js +14 -0
- package/src/commands/testers.js +1 -1
- package/src/commands/upgrade.js +2 -2
- package/src/commands/whoami.js +1 -1
- package/src/dev/bridge.js +8 -0
- package/src/dev/native.js +3 -0
- package/src/dev/session.js +4 -3
- package/src/mcp/extendscript.js +9 -8
- package/src/mcp/host-target.js +1 -0
- package/src/mcp/panels.js +1 -1
- package/src/mcp/png.js +1 -0
- package/src/mcp/server.js +2 -2
- package/src/mcp/tools/capture.js +3 -0
- package/src/mcp/tools/host.js +1 -1
- package/src/mcp/tools/native.js +6 -0
- package/src/mcp/tools/project.js +48 -32
- package/src/mcp/tools/releases.js +23 -20
- package/src/native/build.js +27 -0
- package/src/native/cmake/CMakeLists.txt +88 -0
- package/src/native/cmake/zig-windows.cmake +19 -0
- package/src/native/effect.js +3 -0
- package/src/native/install.js +8 -0
- package/src/native/installers.js +4 -0
- package/src/native/pipl.js +20 -0
- package/src/native/restart.js +2 -0
- package/src/native/sdk.js +8 -0
- package/src/project/docs.js +3 -3
- package/src/project/project.js +2 -2
- package/src/project/template.js +5 -4
- package/src/prompt.js +1 -1
- package/src/release/native.js +3 -0
- package/src/release/publish.js +1 -1
- package/src/system/run-command.js +1 -1
- package/src/targets.js +1 -1
- package/template/cep/AGENTS.md +99 -164
- package/template/cep/README.md +7 -2
- package/template/cep/docs/code_guide.md +67 -0
- package/template/cep/docs/initial_setup.md +58 -12
- package/template/cep/docs/release_checklist.md +24 -0
- package/template/hosts/AGENTS.two-apps.md +12 -0
- package/template/native/.mcp.json +8 -0
- package/template/native/AGENTS.md +105 -0
- package/template/native/README.md +71 -0
- package/template/native/docs/code_guide.md +72 -0
- package/template/native/docs/initial_setup.md +179 -0
- package/template/native/docs/release_checklist.md +24 -0
- package/template/native/effect.json +16 -0
- package/template/native/gitignore +8 -0
- package/template/native/package.json +14 -0
- package/template/native/src/Effect.cpp +224 -0
- package/template/native/src/License.cpp +95 -0
- package/template/native/src/License.h +29 -0
- package/template/native/src/Render.h +68 -0
|
@@ -17,7 +17,7 @@ screen, style, and word the user sees.
|
|
|
17
17
|
It gives you:
|
|
18
18
|
|
|
19
19
|
- `AP.boot` to start the panel.
|
|
20
|
-
- Licensing, off by default. Paid extensions must
|
|
20
|
+
- Licensing, off in `AP.boot` by default (the starter project turns it on). Paid extensions must keep it on.
|
|
21
21
|
- Signed updates with changelogs.
|
|
22
22
|
- `AP.host.eval` to call ExtendScript functions in the app (After Effects or Premiere Pro).
|
|
23
23
|
- `AP.panels` and `AP.events` for extensions with more than one panel.
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: AfterPresets native effect reference
|
|
3
|
+
description: Which file to read before writing or changing a C++ After Effects effect plugin built with AfterPresets.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# AfterPresets native effect reference
|
|
7
|
+
|
|
8
|
+
These files are for the AI coding agent that builds an After Effects effect
|
|
9
|
+
plugin (C++, Adobe's effect SDK) with AfterPresets. An effect is a new entry
|
|
10
|
+
in the Effect menu that renders pixels, like a glow or a blur.
|
|
11
|
+
|
|
12
|
+
## The rule
|
|
13
|
+
|
|
14
|
+
**Read [rules.md](rules.md) before you write or change any effect code, and
|
|
15
|
+
follow [testing.md](testing.md) before you say a change is done.** Then read
|
|
16
|
+
the SDK topic files for your task (index: [sdk/README.md](sdk/README.md)). Do
|
|
17
|
+
not guess struct fields, flag names, selectors or call order. If a file and
|
|
18
|
+
your memory disagree, the file wins. If the SDK guide and the SDK headers in
|
|
19
|
+
the project disagree, the headers win.
|
|
20
|
+
|
|
21
|
+
## Files
|
|
22
|
+
|
|
23
|
+
| File | Read it before you |
|
|
24
|
+
|---|---|
|
|
25
|
+
| [rules.md](rules.md) | write or change any effect code: the hard rules, each with why and an example |
|
|
26
|
+
| [testing.md](testing.md) | say "done": build, apply the effect in After Effects, render frames and look at them |
|
|
27
|
+
| [debugging.md](debugging.md) | chase a crash, an effect that does not load, wrong pixels, or a slow render |
|
|
28
|
+
| [sdk/README.md](sdk/README.md) | use any part of the After Effects SDK: tasks mapped to small topic files |
|
|
29
|
+
|
|
30
|
+
## About sdk/
|
|
31
|
+
|
|
32
|
+
`sdk/` is Adobe's After Effects C++ SDK guide, cut into small topic files. It
|
|
33
|
+
is generated on this computer from a pinned version of the community copy at
|
|
34
|
+
https://github.com/docsforadobe/after-effects-plugin-guide. AfterPresets does
|
|
35
|
+
not ship it: the guide is copyright Adobe. Never copy its text into the
|
|
36
|
+
product, its listing or its source files. Search it with:
|
|
37
|
+
|
|
38
|
+
```sh
|
|
39
|
+
grep -rn "PF_OutFlag2_SUPPORTS_THREADED_RENDERING" docs/afterpresets/sdk/
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
Adobe's SDK itself (headers, samples, `Util/` helpers) is not redistributed
|
|
43
|
+
either. The project gets it from Adobe; never commit it to a public
|
|
44
|
+
repository.
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Debugging a native effect
|
|
3
|
+
description: Find out why an effect does not load, crashes, renders wrong pixels or is slow, without an IDE - scripting checks, binary checks, crash reports, logs and debugger limits.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Debugging a native effect
|
|
7
|
+
|
|
8
|
+
You have no IDE and usually no debugger attached. Work from evidence you can
|
|
9
|
+
collect yourself: scripting queries through `host_eval`, frames from
|
|
10
|
+
`comp_capture`, the built binary, crash reports and logs. Change one thing at
|
|
11
|
+
a time and test again ([testing.md](testing.md)).
|
|
12
|
+
|
|
13
|
+
## The effect does not appear or does not apply
|
|
14
|
+
|
|
15
|
+
1. **Is it loaded?** Ask After Effects for its effect list:
|
|
16
|
+
|
|
17
|
+
```js
|
|
18
|
+
var out = [];
|
|
19
|
+
for (var i = 0; i < app.effects.length; i++) {
|
|
20
|
+
var e = app.effects[i];
|
|
21
|
+
if (/ACME/.test(e.matchName)) out.push(e.matchName + " | " + e.displayName + " | " + e.category);
|
|
22
|
+
}
|
|
23
|
+
return out.join("\n") || "not loaded";
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
Listed, but `addProperty` fails: you are using a different match name.
|
|
27
|
+
Not listed: After Effects did not load the binary; go on.
|
|
28
|
+
2. **Was After Effects restarted** after the binary was installed? Plugins
|
|
29
|
+
load at launch only.
|
|
30
|
+
3. **Is it where After Effects looks?** See
|
|
31
|
+
[sdk/where-installers-should-put-plug-ins.md](sdk/where-installers-should-put-plug-ins.md).
|
|
32
|
+
Folders whose names end in parentheses, or start with `¬` (macOS) or `~`
|
|
33
|
+
(Windows), are not scanned. `ap dev` installs into
|
|
34
|
+
`/Library/Application Support/Adobe/Common/Plug-ins/7.0/MediaCore/AfterPresets Dev/<bundleId>/`,
|
|
35
|
+
a folder made once with administrator rights and then owned by the user;
|
|
36
|
+
buyers' copies go to `MediaCore/AfterPresets/<bundleId>/`. Any other
|
|
37
|
+
write to the shared MediaCore folder or the After Effects `Plug-ins`
|
|
38
|
+
folder needs administrator rights: ask the user, never use `sudo`
|
|
39
|
+
yourself.
|
|
40
|
+
4. **Check the binary** (macOS):
|
|
41
|
+
|
|
42
|
+
```sh
|
|
43
|
+
lipo -info Effect.plugin/Contents/MacOS/Effect # arm64 and x86_64 for a universal build
|
|
44
|
+
nm -gU Effect.plugin/Contents/MacOS/Effect # the entry point must be exported
|
|
45
|
+
codesign -dv Effect.plugin # must be signed (ad-hoc is enough to develop)
|
|
46
|
+
xattr -l Effect.plugin # com.apple.quarantine set by downloads
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
macOS 15 and later refuse unsigned plugins; sign development builds
|
|
50
|
+
ad-hoc with `codesign --force --deep --sign - Effect.plugin`, and do not
|
|
51
|
+
touch the bundle after signing. The PiPL needs an entry point for every
|
|
52
|
+
architecture you build (`CodeMacARM64`, `CodeMacIntel64`, `CodeWin64X86`).
|
|
53
|
+
5. **Check the PiPL against GlobalSetup**: flags (rule 2 in
|
|
54
|
+
[rules.md](rules.md)), match name, version. A mismatch warning appears when
|
|
55
|
+
the effect is applied; ask the user to read you any dialog.
|
|
56
|
+
6. **Read After Effects' plugin loading log.** It is rewritten at every
|
|
57
|
+
launch: `~/Library/Preferences/Adobe/After Effects/<version>/Plugin Loading.log`
|
|
58
|
+
(for example `26.2`). Search it for your bundle name:
|
|
59
|
+
|
|
60
|
+
```sh
|
|
61
|
+
grep -n -i "MyEffect" ~/Library/Preferences/Adobe/After\ Effects/*/Plugin\ Loading.log
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
The line "No loaders recognized this plugin … Ignore" is normal for After
|
|
65
|
+
Effects effects (it comes from the shared MediaCore loader). A missing
|
|
66
|
+
line means After Effects never saw the file (wrong folder, not
|
|
67
|
+
restarted); a load error points at the binary (step 4) or the PiPL
|
|
68
|
+
(step 5).
|
|
69
|
+
|
|
70
|
+
Whether a plugin loads also depends on how After Effects itself is signed
|
|
71
|
+
(hardened runtime, library validation). A result on one computer, for
|
|
72
|
+
example one with a re-signed or developer copy of After Effects, may not
|
|
73
|
+
match a customer's computer.
|
|
74
|
+
|
|
75
|
+
## After Effects crashes
|
|
76
|
+
|
|
77
|
+
- macOS writes a crash report to `~/Library/Logs/DiagnosticReports/`
|
|
78
|
+
(`Adobe After Effects*.ips`). Find the crashed thread and look for frames in
|
|
79
|
+
your binary. Build development versions with debug symbols (`-g`) and keep
|
|
80
|
+
the `.dSYM`, so addresses map to functions and lines (`atos -o
|
|
81
|
+
Effect.plugin.dSYM/Contents/Resources/DWARF/Effect -arch arm64 -l <load
|
|
82
|
+
address> <address>`).
|
|
83
|
+
- Usual causes: reading past a row (`rowbytes`, wrong pixel type for the
|
|
84
|
+
depth), an exception leaving the entry point (rule 15), a world used after
|
|
85
|
+
`PF_DisposeWorld`, writing shared state from several render threads
|
|
86
|
+
(rule 11), unbalanced parameter checkouts (rule 10).
|
|
87
|
+
- After a crash, After Effects may show a recovery dialog at the next launch.
|
|
88
|
+
Ask the user to answer it; do not script around it.
|
|
89
|
+
|
|
90
|
+
## Wrong pixels
|
|
91
|
+
|
|
92
|
+
- Capture the same frame at 8, 16 and 32 bpc. Wrong in one depth only: that
|
|
93
|
+
depth's code path or its maximum channel value (32768 for 16 bpc).
|
|
94
|
+
- Bright random colours, rainbows, black blotches: integer overflow; clamp
|
|
95
|
+
before converting.
|
|
96
|
+
- Wrong only at half resolution or with an effect before yours: downsample
|
|
97
|
+
factors or buffer origin ([rules.md](rules.md), rule 9).
|
|
98
|
+
- To see an internal value, temporarily write it into the output (for example
|
|
99
|
+
a red channel proportional to the value) and capture the frame. Remove it
|
|
100
|
+
afterwards.
|
|
101
|
+
- Unchanged after a rebuild: After Effects still runs the old binary
|
|
102
|
+
(restart), or you looked at a cached frame (`comp_capture` clears caches by
|
|
103
|
+
default; keep it that way).
|
|
104
|
+
|
|
105
|
+
## Slow renders
|
|
106
|
+
|
|
107
|
+
`comp_capture` reports a render time per frame, measured after clearing the
|
|
108
|
+
caches. Compare before and after a change on the same frames. Typical fixes:
|
|
109
|
+
precompute tables once (GlobalSetup or SequenceSetup), avoid `pow`/`sqrt`/
|
|
110
|
+
division per pixel, fuse passes, process only the requested area, and enable
|
|
111
|
+
multi-frame rendering when the effect is thread-safe (rule 11).
|
|
112
|
+
|
|
113
|
+
## Logs
|
|
114
|
+
|
|
115
|
+
The AfterPresets native runtime (`ap_native`) writes a small log for each
|
|
116
|
+
plugin: `~/Library/Logs/AfterPresets/<bundleId>.log` on macOS (rotated at
|
|
117
|
+
1 MB; `ap_log_path()` returns the exact path). Each After Effects start adds
|
|
118
|
+
a `start <bundleId> <version> build=...` line, then licence and update
|
|
119
|
+
events. Read it with `tail -n 50`. It is safe to read: tokens and URL query
|
|
120
|
+
strings are scrubbed.
|
|
121
|
+
|
|
122
|
+
To log from effect code, call `ap_log(rt, level, "message")`: it never
|
|
123
|
+
blocks and does no file I/O on the calling thread, so it is allowed in
|
|
124
|
+
render code, but never log from inside the per-pixel loop. Never log licence
|
|
125
|
+
tokens, account data or user paths, and remove temporary logging before
|
|
126
|
+
release.
|
|
127
|
+
|
|
128
|
+
## Debuggers
|
|
129
|
+
|
|
130
|
+
Attaching `lldb` to a release build of After Effects 26.5 or later on macOS is
|
|
131
|
+
refused because of how the application is signed. Adobe's workaround (a
|
|
132
|
+
re-signed copy, or developer mode for beta builds) needs the user and
|
|
133
|
+
administrator rights: see [sdk/debugging-ae-macos.md](sdk/debugging-ae-macos.md).
|
|
134
|
+
Prefer the evidence above; propose a debugger session to the user only when
|
|
135
|
+
it is the only way forward.
|
|
136
|
+
|
|
137
|
+
Holding Cmd+Opt+Shift (macOS) or Ctrl+Alt+Shift (Windows) while After Effects
|
|
138
|
+
starts resets its preferences, which clears settings a plugin may have
|
|
139
|
+
stored. Only the user should do this, after being told it resets all their
|
|
140
|
+
preferences.
|
|
@@ -0,0 +1,402 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Rules for native effects
|
|
3
|
+
description: The hard rules and classic mistakes of After Effects effect plugins (PiPL, flags, match names, parameters, bit depths, Smart Render, multi-frame rendering, sequence data, memory, errors), each with why and an example.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Rules for native effects
|
|
7
|
+
|
|
8
|
+
Read this before writing or changing effect code. Each rule says why it
|
|
9
|
+
exists and shows the right shape. Details are in the SDK topic files
|
|
10
|
+
([sdk/README.md](sdk/README.md)); `grep` them for any name used here.
|
|
11
|
+
|
|
12
|
+
## Identity and registration
|
|
13
|
+
|
|
14
|
+
### 1. The match name is permanent, unique and prefixed
|
|
15
|
+
|
|
16
|
+
The match name (`AE_Effect_Match_Name` in the PiPL, and the `matchName` given
|
|
17
|
+
to `PF_REGISTER_EFFECT*` if the project registers in code) is the effect's
|
|
18
|
+
identity. After Effects stores it in every project, preset and template that
|
|
19
|
+
uses the effect. Give it a vendor prefix, keep it ASCII, and never change it
|
|
20
|
+
after the first release. The display name and category may change; the match
|
|
21
|
+
name may not.
|
|
22
|
+
|
|
23
|
+
Why: rename it and every saved project shows "missing effect". Two vendors
|
|
24
|
+
with the same match name collide, and one of the effects does not load.
|
|
25
|
+
|
|
26
|
+
```c
|
|
27
|
+
AE_Effect_Match_Name { "ACME Soft Glow" }, // never changes
|
|
28
|
+
Name { "Soft Glow" }, // display name, up to 47 characters
|
|
29
|
+
Category { "ACME" }, // spelled the same in every effect
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
A category spelled two ways ("ACME" and "ACME ") makes two folders in the
|
|
33
|
+
Effect menu.
|
|
34
|
+
|
|
35
|
+
### 2. The PiPL flags equal the GlobalSetup flags
|
|
36
|
+
|
|
37
|
+
`AE_Effect_Global_OutFlags` and `AE_Effect_Global_OutFlags_2` in the PiPL must
|
|
38
|
+
be exactly the values `PF_Cmd_GLOBAL_SETUP` puts in `out_data->out_flags` and
|
|
39
|
+
`out_data->out_flags2`. Every time you add or remove a flag (Smart Render,
|
|
40
|
+
float, multi-frame rendering, `I_DO_DIALOG`, GPU...), change both.
|
|
41
|
+
|
|
42
|
+
Why: After Effects reads the PiPL without running the plugin and reads the
|
|
43
|
+
flags again at GlobalSetup. When they differ it warns the user when the effect
|
|
44
|
+
is applied, and features silently follow the wrong set. This is the most
|
|
45
|
+
common native-plugin mistake.
|
|
46
|
+
|
|
47
|
+
```cpp
|
|
48
|
+
// GlobalSetup
|
|
49
|
+
out_data->out_flags = PF_OutFlag_DEEP_COLOR_AWARE | PF_OutFlag_PIX_INDEPENDENT;
|
|
50
|
+
out_data->out_flags2 = PF_OutFlag2_SUPPORTS_SMART_RENDER
|
|
51
|
+
| PF_OutFlag2_FLOAT_COLOR_AWARE
|
|
52
|
+
| PF_OutFlag2_SUPPORTS_THREADED_RENDERING;
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
The PiPL holds the same two numbers in hex. Keep both in one place: in an
|
|
56
|
+
AfterPresets project the flags live only in `effect.json`, and the build
|
|
57
|
+
generates both the PiPL and `ap_effect_config.h`, whose macros GlobalSetup
|
|
58
|
+
uses; `ap check` compares the built PiPL with `effect.json`. Never type flag
|
|
59
|
+
values by hand, and never edit a generated file.
|
|
60
|
+
|
|
61
|
+
### 3. Versions agree and only go up
|
|
62
|
+
|
|
63
|
+
`out_data->my_version` (set with `PF_VERSION(...)` in GlobalSetup) and
|
|
64
|
+
`AE_Effect_Version` in the PiPL describe the same version: generate both from
|
|
65
|
+
one header. Raise it for every release. `AE_Effect_Spec_Version` is the SDK
|
|
66
|
+
version the effect was built with: use the SDK's `PF_AE_PLUG_IN_VERSION` /
|
|
67
|
+
`PF_AE_PLUG_IN_SUBVERS` constants, never hand-typed numbers.
|
|
68
|
+
|
|
69
|
+
Why: users and support read the version in the Effects panel and in "About".
|
|
70
|
+
Multi-frame rendering needs an effect built against SDK 13.25 or later
|
|
71
|
+
(March 2021 SDK or newer).
|
|
72
|
+
|
|
73
|
+
```cpp
|
|
74
|
+
out_data->my_version = PF_VERSION(MAJOR_VERSION, MINOR_VERSION, BUG_VERSION,
|
|
75
|
+
STAGE_VERSION, BUILD_VERSION);
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
### 4. One effect per binary, one entry point
|
|
79
|
+
|
|
80
|
+
Ship one PiPL and one effect per `.plugin` / `.aex`. Export only the entry
|
|
81
|
+
point (`EffectMain`, plus the SDK's `PluginDataEntryFunction*` when the effect
|
|
82
|
+
also registers in code with `PF_REGISTER_EFFECT*`); hide every other symbol.
|
|
83
|
+
|
|
84
|
+
Why: Premiere Pro and other hosts do not support several effects in one
|
|
85
|
+
binary, and an update then has to replace all of them. Exported symbols from
|
|
86
|
+
two plugins that share a library clash at load time (see
|
|
87
|
+
[sdk/symbol-export.md](sdk/symbol-export.md)).
|
|
88
|
+
|
|
89
|
+
## Parameters
|
|
90
|
+
|
|
91
|
+
### 5. Parameter disk IDs never change, never get reused
|
|
92
|
+
|
|
93
|
+
Each parameter has two numbers: its index (its position in the Effect
|
|
94
|
+
Controls, the order you call `PF_ADD_*`) and its disk ID (`def.uu.id`, saved
|
|
95
|
+
in projects). Keep two enums. Disk IDs start at 1. Add new IDs only at the
|
|
96
|
+
end. Never delete, reorder or reuse an ID, even when you remove the
|
|
97
|
+
parameter.
|
|
98
|
+
|
|
99
|
+
Why: projects store values by disk ID. Reorder the IDs and a saved project
|
|
100
|
+
loads "Radius" into "Intensity". Without IDs, After Effects numbers
|
|
101
|
+
parameters by position, so inserting one shifts every later value.
|
|
102
|
+
|
|
103
|
+
```cpp
|
|
104
|
+
enum { GLOW_INPUT = 0, GLOW_RADIUS, GLOW_INTENSITY, GLOW_COLOR, GLOW_NUM_PARAMS };
|
|
105
|
+
enum { RADIUS_DISK_ID = 1, INTENSITY_DISK_ID, COLOR_DISK_ID /* add new IDs here only */ };
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
Changing a parameter's default also needs care: give it a new disk ID, or set
|
|
109
|
+
`PF_ParamFlag_USE_VALUE_FOR_OLD_PROJECTS`, so old projects keep the value they
|
|
110
|
+
were made with. See [sdk/changing-parameter-orders.md](sdk/changing-parameter-orders.md).
|
|
111
|
+
|
|
112
|
+
### 6. Clear every definition, count every parameter
|
|
113
|
+
|
|
114
|
+
Call `AEFX_CLR_STRUCT(def)` before every `PF_ADD_*`, and set
|
|
115
|
+
`out_data->num_params` to the number of parameters including the input layer
|
|
116
|
+
(index 0).
|
|
117
|
+
|
|
118
|
+
Why: a definition left over from the previous parameter carries flags and
|
|
119
|
+
ranges into the next one. A wrong `num_params` makes the effect fail to apply
|
|
120
|
+
or read garbage.
|
|
121
|
+
|
|
122
|
+
```cpp
|
|
123
|
+
PF_ParamDef def;
|
|
124
|
+
AEFX_CLR_STRUCT(def);
|
|
125
|
+
PF_ADD_FLOAT_SLIDERX("Radius", 0, 1000, 0, 200, 25, PF_Precision_TENTHS, 0, 0, RADIUS_DISK_ID);
|
|
126
|
+
AEFX_CLR_STRUCT(def);
|
|
127
|
+
PF_ADD_FLOAT_SLIDERX("Intensity", 0, 400, 0, 200, 100, PF_Precision_TENTHS, 0, 0, INTENSITY_DISK_ID);
|
|
128
|
+
out_data->num_params = GLOW_NUM_PARAMS;
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
### 7. Read each parameter through its own union member
|
|
132
|
+
|
|
133
|
+
| Parameter | Read |
|
|
134
|
+
|---|---|
|
|
135
|
+
| Float slider (`PF_ADD_FLOAT_SLIDERX`) | `u.fs_d.value` (double) |
|
|
136
|
+
| Slider (int) | `u.sd.value` |
|
|
137
|
+
| Fixed slider, percent | `u.fd.value` (`PF_Fixed`, 16.16: use `FIX2FLT`) |
|
|
138
|
+
| Angle | `u.ad.value` (`PF_Fixed` degrees) |
|
|
139
|
+
| Checkbox | `u.bd.value` |
|
|
140
|
+
| Popup | `u.pd.value` (1-based) |
|
|
141
|
+
| Color | `u.cd.value` (`PF_Pixel`, 8 bpc; use `PF_ColorParamSuite1` for float) |
|
|
142
|
+
| Point | `u.td.x_value`, `u.td.y_value` (`PF_Fixed` pixels; use `PF_PointParamSuite1` for float) |
|
|
143
|
+
| Layer | `u.ld` (checked out, see rule 10) |
|
|
144
|
+
|
|
145
|
+
Why: the union does not complain. Reading a percent parameter through `sd`
|
|
146
|
+
gives silently wrong numbers. Check the type in
|
|
147
|
+
[sdk/parameters.md](sdk/parameters.md) before reading.
|
|
148
|
+
|
|
149
|
+
`PF_ADD_POINT` defaults are a percentage of the layer (50, 50 is the
|
|
150
|
+
centre), not pixels; the value you read back is in pixels of the layer. The
|
|
151
|
+
values you get are already scaled for downsampling and origin offsets; see
|
|
152
|
+
[sdk/parameters.md](sdk/parameters.md#point-parameter-origin).
|
|
153
|
+
|
|
154
|
+
## Pixels and bit depths
|
|
155
|
+
|
|
156
|
+
### 8. Handle every bit depth you declare, and declare what you handle
|
|
157
|
+
|
|
158
|
+
- 8 bpc: `PF_Pixel`, channels 0-255. Always supported.
|
|
159
|
+
- 16 bpc: `PF_Pixel16`, channels **0-32768** (`PF_MAX_CHAN16`), not 65535 and
|
|
160
|
+
not 32767. Declare with `PF_OutFlag_DEEP_COLOR_AWARE`.
|
|
161
|
+
- 32 bpc: `PF_PixelFloat`, nominally 0.0-1.0, but values below 0 and above 1
|
|
162
|
+
are valid (overbright) and must not be clamped. Declare with
|
|
163
|
+
`PF_OutFlag2_FLOAT_COLOR_AWARE`, which requires Smart Render
|
|
164
|
+
(`PF_OutFlag2_SUPPORTS_SMART_RENDER`).
|
|
165
|
+
|
|
166
|
+
Why: without the flags, After Effects converts to a lower depth and shows a
|
|
167
|
+
warning badge on the effect. With the flags but a missing code path, 16/32 bpc
|
|
168
|
+
projects render garbage. Using 32767 or 65535 for white makes 16-bit output
|
|
169
|
+
slightly too dark or wrap around.
|
|
170
|
+
|
|
171
|
+
Write one kernel and instantiate it per depth; clamp before converting to an
|
|
172
|
+
integer type:
|
|
173
|
+
|
|
174
|
+
```cpp
|
|
175
|
+
template <typename P, int MaxChan> struct Px; // P = PF_Pixel8, PF_Pixel16 or PF_PixelFloat
|
|
176
|
+
// 8: MaxChan 255 16: MaxChan PF_MAX_CHAN16 (32768) 32: float, no clamp
|
|
177
|
+
static inline A_u_short to16(float v) {
|
|
178
|
+
v = v < 0.f ? 0.f : (v > 1.f ? 1.f : v);
|
|
179
|
+
return (A_u_short)(v * PF_MAX_CHAN16 + 0.5f);
|
|
180
|
+
}
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
In Smart Render, pick the path from the world's pixel format
|
|
184
|
+
(`PF_WorldSuite2::PF_GetPixelFormat`: `ARGB32`, `ARGB64`, `ARGB128`) and use
|
|
185
|
+
the matching iterate suite (`Iterate8Suite`, `Iterate16Suite`,
|
|
186
|
+
`IterateFloatSuite`). Pixel order is ARGB in After Effects.
|
|
187
|
+
|
|
188
|
+
### 9. Never assume the size, origin or stride of a buffer
|
|
189
|
+
|
|
190
|
+
- Use `rowbytes` to step between rows; it is not `width * sizeof(pixel)`.
|
|
191
|
+
- Scale distances that come from the user in pixels by
|
|
192
|
+
`in_data->downsample_x` / `downsample_y` (a half-resolution preview has half
|
|
193
|
+
the pixels).
|
|
194
|
+
- Process only the area you are asked for (`extent_hint`, or the Smart
|
|
195
|
+
Render request rects) and use the buffer's own width, height and origin.
|
|
196
|
+
- Pixel aspect ratio may not be 1 ([sdk/pixel-aspect-ratio.md](sdk/pixel-aspect-ratio.md)).
|
|
197
|
+
|
|
198
|
+
Why: hard-coded coordinates or `width * 4` work at full resolution in one test
|
|
199
|
+
comp and break at half resolution, on cropped layers and with other effects
|
|
200
|
+
upstream.
|
|
201
|
+
|
|
202
|
+
```cpp
|
|
203
|
+
float radius_px = (float)(radius * in_data->downsample_x.num / in_data->downsample_x.den);
|
|
204
|
+
PF_Pixel8 *row = (PF_Pixel8 *)((char *)world->data + y * world->rowbytes);
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
To draw outside the layer (glows, shadows), expand the output properly: in
|
|
208
|
+
Smart Render return a larger `result_rect` / `max_result_rect` from PreRender;
|
|
209
|
+
without Smart Render set `PF_OutFlag_I_EXPAND_BUFFER` and give the new output
|
|
210
|
+
width, height and origin in `PF_Cmd_FRAME_SETUP`. Point parameters then
|
|
211
|
+
arrive shifted by the origin; see
|
|
212
|
+
[sdk/pf-indata.md](sdk/pf-indata.md#point-controls-and-buffer-expansion).
|
|
213
|
+
|
|
214
|
+
## Smart Render
|
|
215
|
+
|
|
216
|
+
### 10. Smart Render is all or nothing
|
|
217
|
+
|
|
218
|
+
With `PF_OutFlag2_SUPPORTS_SMART_RENDER`, handle both `PF_Cmd_SMART_PRE_RENDER`
|
|
219
|
+
and `PF_Cmd_SMART_RENDER`:
|
|
220
|
+
|
|
221
|
+
- PreRender: check out the input layer with a render request
|
|
222
|
+
(`checkout_layer`), and return the union of the result rects.
|
|
223
|
+
- SmartRender: use the checked-out input world
|
|
224
|
+
(`checkout_layer_pixels`) and output (`checkout_output`), never
|
|
225
|
+
`params[0]->u.ld`. Check out every parameter you read with
|
|
226
|
+
`PF_CHECKOUT_PARAM` and check every one back in with `PF_CHECKIN_PARAM`,
|
|
227
|
+
also on error paths.
|
|
228
|
+
- Keep `PF_Cmd_RENDER` working too: Premiere Pro never sends the Smart Render
|
|
229
|
+
selectors.
|
|
230
|
+
|
|
231
|
+
Why: setting the flag without both selectors gives errors when the effect is
|
|
232
|
+
applied. Reading `params[0]` in SmartRender, or unbalanced checkouts, gives
|
|
233
|
+
"bad parameter passed to effect callback" errors.
|
|
234
|
+
|
|
235
|
+
```cpp
|
|
236
|
+
PF_ParamDef radius;
|
|
237
|
+
AEFX_CLR_STRUCT(radius);
|
|
238
|
+
ERR(PF_CHECKOUT_PARAM(in_data, GLOW_RADIUS, in_data->current_time,
|
|
239
|
+
in_data->time_step, in_data->time_scale, &radius));
|
|
240
|
+
/* ... render ... */
|
|
241
|
+
ERR2(PF_CHECKIN_PARAM(in_data, &radius)); // always, even if err is set
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
## Multi-frame rendering and threads
|
|
245
|
+
|
|
246
|
+
### 11. Only claim thread safety you have
|
|
247
|
+
|
|
248
|
+
Set `PF_OutFlag2_SUPPORTS_THREADED_RENDERING` (After Effects 2022+) only when
|
|
249
|
+
all of these hold:
|
|
250
|
+
|
|
251
|
+
- No global or static variable is written after GlobalSetup (constant tables
|
|
252
|
+
built once in GlobalSetup are fine).
|
|
253
|
+
- `in_data->global_data` is written only in `PF_Cmd_GLOBAL_SETUP` and
|
|
254
|
+
`PF_Cmd_GLOBAL_SETDOWN`.
|
|
255
|
+
- `sequence_data` is never written at render time or in
|
|
256
|
+
`PF_Cmd_UPDATE_PARAMS_UI`; it is read at render time through
|
|
257
|
+
`PF_EffectSequenceDataSuite1` (`PF_GetConstSequenceData`).
|
|
258
|
+
- No lock (mutex, gate) is held while calling back into After Effects (any
|
|
259
|
+
suite call, any checkout).
|
|
260
|
+
- Rendering is deterministic: no `rand()`, no time-of-day, no state carried
|
|
261
|
+
from the previous frame. Seed noise from parameters, time and position.
|
|
262
|
+
|
|
263
|
+
`PF_Cmd_SEQUENCE_SETUP`, `SEQUENCE_RESETUP`, `SEQUENCE_SETDOWN`,
|
|
264
|
+
`SMART_PRE_RENDER`, `RENDER` and `SMART_RENDER` can run on several threads at
|
|
265
|
+
once, at the same time as UI selectors.
|
|
266
|
+
|
|
267
|
+
Why: without the flag, After Effects renders the effect one frame at a time
|
|
268
|
+
and shows a "not optimised for multi-frame rendering" warning. With the flag
|
|
269
|
+
but shared state, frames render differently, flicker, or crash, only on busy
|
|
270
|
+
machines. Non-deterministic renders also break the frame cache.
|
|
271
|
+
|
|
272
|
+
```cpp
|
|
273
|
+
// wrong: one instance's value leaks into another instance's render
|
|
274
|
+
static float g_radius;
|
|
275
|
+
// right: read parameters in the render call (or pass them via pre_render_data)
|
|
276
|
+
```
|
|
277
|
+
|
|
278
|
+
If an effect must cache expensive work across frames, use the Compute Cache
|
|
279
|
+
([sdk/compute-cache-api.md](sdk/compute-cache-api.md)), not sequence data.
|
|
280
|
+
|
|
281
|
+
### 12. Never block a render or UI thread
|
|
282
|
+
|
|
283
|
+
No network, file I/O, dialogs, sleeps or long waits inside render selectors
|
|
284
|
+
or `PF_Cmd_UPDATE_PARAMS_UI`. Load files and tables once (GlobalSetup or
|
|
285
|
+
SequenceSetup). Licence and update work runs in the AfterPresets native
|
|
286
|
+
runtime off the render thread; render code only reads its cached state
|
|
287
|
+
with `ap_is_unlocked(rt)` (lock-free, safe on any thread, never waits).
|
|
288
|
+
|
|
289
|
+
Why: a render that waits on the network freezes previews for every user who
|
|
290
|
+
is offline or slow, and can deadlock with multi-frame rendering.
|
|
291
|
+
|
|
292
|
+
## Sequence data
|
|
293
|
+
|
|
294
|
+
### 13. Flatten sequence data, and say so
|
|
295
|
+
|
|
296
|
+
Sequence data is saved in the project. If it contains pointers or handles,
|
|
297
|
+
flatten it: set `PF_OutFlag_SEQUENCE_DATA_NEEDS_FLATTENING` and
|
|
298
|
+
`PF_OutFlag2_SUPPORTS_GET_FLATTENED_SEQUENCE_DATA`, handle
|
|
299
|
+
`PF_Cmd_SEQUENCE_FLATTEN`, `PF_Cmd_SEQUENCE_RESETUP` and
|
|
300
|
+
`PF_Cmd_GET_FLATTENED_SEQUENCE_DATA`. Put a version number and a
|
|
301
|
+
flat/unflat marker at the same offset in both layouts, and write numbers in
|
|
302
|
+
one fixed byte order. Resize the handle only in the selectors listed in
|
|
303
|
+
[sdk/global-sequence-frame-data.md](sdk/global-sequence-frame-data.md#resizing-sequence-data).
|
|
304
|
+
|
|
305
|
+
Why: pointers saved in a project are garbage when it reopens, on the other
|
|
306
|
+
OS, or in the other app. Without the version field, an update cannot read
|
|
307
|
+
projects saved by the previous version.
|
|
308
|
+
|
|
309
|
+
```cpp
|
|
310
|
+
typedef struct { A_u_long version; A_Boolean flat; char message[256]; PF_FpLong amount; } SeqFlat;
|
|
311
|
+
```
|
|
312
|
+
|
|
313
|
+
Prefer parameters (including hidden ones) over sequence data: they are saved,
|
|
314
|
+
keyframable and thread-safe without extra work.
|
|
315
|
+
|
|
316
|
+
## Memory and errors
|
|
317
|
+
|
|
318
|
+
### 14. Allocate through After Effects and free what you allocate
|
|
319
|
+
|
|
320
|
+
Large buffers come from After Effects: `PF_HandleSuite1` for memory,
|
|
321
|
+
`PF_WorldSuite2` (`PF_NewWorld` / `PF_DisposeWorld`) for image buffers. Free
|
|
322
|
+
every world you create with `PF_DisposeWorld` (or `PF_DISPOSE_WORLD`).
|
|
323
|
+
`AEFX_CLR_STRUCT` only zeroes a struct; it frees nothing.
|
|
324
|
+
|
|
325
|
+
Why: After Effects frees its caches when your allocations need memory; plain
|
|
326
|
+
`malloc` competes with it and causes swapping or crashes during RAM preview.
|
|
327
|
+
A world disposed with `AEFX_CLR_STRUCT` leaks a full frame every render.
|
|
328
|
+
|
|
329
|
+
### 15. Return every error, never throw out of the entry point
|
|
330
|
+
|
|
331
|
+
Return a `PF_Err` from every call and pass on any error a callback returns,
|
|
332
|
+
including `PF_Interrupt_CANCEL` (stop the frame) and `PF_Err_OUT_OF_MEMORY`.
|
|
333
|
+
Use the SDK's `ERR()` / `ERR2()` macros. Catch every C++ exception inside the
|
|
334
|
+
entry point and turn it into an error. To show a message, set
|
|
335
|
+
`PF_OutFlag_DISPLAY_ERROR_MESSAGE` and `out_data->return_msg`.
|
|
336
|
+
|
|
337
|
+
Why: a swallowed cancel caches a half-rendered frame; an exception that
|
|
338
|
+
crosses into After Effects crashes it (and behaves differently on Apple
|
|
339
|
+
silicon, see [sdk/apple-silicon-support.md](sdk/apple-silicon-support.md)).
|
|
340
|
+
|
|
341
|
+
```cpp
|
|
342
|
+
extern "C" DllExport PF_Err EffectMain(PF_Cmd cmd, PF_InData *in_data, PF_OutData *out_data,
|
|
343
|
+
PF_ParamDef *params[], PF_LayerDef *output, void *extra) {
|
|
344
|
+
PF_Err err = PF_Err_NONE;
|
|
345
|
+
try {
|
|
346
|
+
switch (cmd) { /* ... */ }
|
|
347
|
+
} catch (const std::bad_alloc &) {
|
|
348
|
+
err = PF_Err_OUT_OF_MEMORY;
|
|
349
|
+
} catch (...) {
|
|
350
|
+
err = PF_Err_INTERNAL_STRUCT_DAMAGED;
|
|
351
|
+
}
|
|
352
|
+
return err;
|
|
353
|
+
}
|
|
354
|
+
```
|
|
355
|
+
|
|
356
|
+
## Hosts and builds
|
|
357
|
+
|
|
358
|
+
### 16. Premiere Pro is a different host
|
|
359
|
+
|
|
360
|
+
The same binary loads in Premiere Pro from the shared MediaCore folder.
|
|
361
|
+
Check `in_data->appl_id` (`'PrMr'` is Premiere Pro). Premiere never sends
|
|
362
|
+
Smart Render selectors, uses other pixel formats (BGRA/VUYA, declared through
|
|
363
|
+
`PF_PixelFormatSuite1`) and lacks some suites. Until Premiere support is in
|
|
364
|
+
scope, test only in After Effects and say so. See
|
|
365
|
+
[sdk/ppro.md](sdk/ppro.md).
|
|
366
|
+
|
|
367
|
+
### 17. Build clean
|
|
368
|
+
|
|
369
|
+
Compile without warnings and keep warnings on. Fix narrowing casts (they are
|
|
370
|
+
the source of wrap-around colours) instead of hiding them. Debug and release
|
|
371
|
+
builds use the same include paths, defines and struct alignment.
|
|
372
|
+
|
|
373
|
+
## AfterPresets rules
|
|
374
|
+
|
|
375
|
+
### 18. Licensing, logs and secrets
|
|
376
|
+
|
|
377
|
+
- Licensing and updates come only from the AfterPresets native runtime. Do
|
|
378
|
+
not write your own licence checks, serials or network calls.
|
|
379
|
+
- Never log or print licence tokens, proofs, account data or file paths that
|
|
380
|
+
contain the user's name.
|
|
381
|
+
- Do not put Adobe SDK files or SDK guide text in the product, its listing or
|
|
382
|
+
a public repository.
|
|
383
|
+
|
|
384
|
+
## Things tutorials get wrong
|
|
385
|
+
|
|
386
|
+
Common in video tutorials and old samples. Do not copy:
|
|
387
|
+
|
|
388
|
+
| Tutorial habit | Do instead |
|
|
389
|
+
|---|---|
|
|
390
|
+
| White in 16 bpc is 32767 (or 65535) | `PF_MAX_CHAN16` = 32768 |
|
|
391
|
+
| "Free" a world with `AEFX_CLEAR_STRUCT` | `PF_DisposeWorld` (rule 14) |
|
|
392
|
+
| Pass values between calls in global variables | Read parameters per render, `pre_render_data`, sequence data (rule 11) |
|
|
393
|
+
| `rand()` per frame | Seed from parameters, time and position (rule 11) |
|
|
394
|
+
| Read a file (LUT) inside render | Load once in GlobalSetup / SequenceSetup (rule 12) |
|
|
395
|
+
| Hard-coded pixel coordinates | Downsample factors and buffer extents (rule 9) |
|
|
396
|
+
| `PF_ADD_POINT` default in pixels (1920, 1080) | Percent of the layer (50, 50 = centre) (rule 7) |
|
|
397
|
+
| "Treat warnings as errors: No" | Fix the casts (rule 17) |
|
|
398
|
+
| Read a param through the wrong union member | Rule 7 table |
|
|
399
|
+
| `xcrun altool` to notarise | Retired by Apple; `xcrun notarytool` |
|
|
400
|
+
| Paste out_flags hex from the debugger into the PiPL by hand | One source for both (rule 2) |
|
|
401
|
+
| "Nothing changed" after a rebuild | Stale frame cache: purge caches before judging a render ([testing.md](testing.md)) |
|
|
402
|
+
| Build into Program Files with an admin IDE | Build into the project; install with a separate step |
|