afterpresets 0.1.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-after-effects.md +57 -0
- package/runtime/docs/cep/host-premiere.md +84 -0
- package/runtime/docs/{host.md → cep/host.md} +42 -16
- package/runtime/docs/{README.md → common/README.md} +10 -8
- package/runtime/docs/{assets.md → common/assets.md} +16 -2
- package/runtime/docs/{licensing.md → common/licensing.md} +1 -1
- package/runtime/docs/{panels.md → common/panels.md} +5 -5
- package/runtime/docs/{storage.md → common/storage.md} +5 -5
- package/runtime/docs/{updates.md → common/updates.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/runtime/src/updates.js +1 -1
- package/src/api/error-messages.js +1 -1
- package/src/build/build.js +7 -7
- package/src/build/html.js +1 -1
- package/src/build/jsx.js +2 -2
- package/src/build/runtime.js +3 -3
- package/src/check/check.js +3 -3
- package/src/check/native.js +14 -0
- package/src/check/pricing.js +1 -1
- package/src/check/types.js +2 -2
- package/src/cli.js +5 -5
- package/src/commands/add.js +8 -3
- package/src/commands/build.js +8 -2
- package/src/commands/check.js +11 -3
- package/src/commands/dev.js +9 -2
- package/src/commands/docs.js +5 -1
- package/src/commands/init.js +15 -3
- 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/config.js +1 -1
- package/src/dev/bridge.js +8 -0
- package/src/dev/cep-link.js +1 -1
- package/src/dev/debug-file.js +5 -5
- package/src/dev/native.js +3 -0
- package/src/dev/session.js +4 -3
- package/src/mcp/extendscript.js +10 -7
- 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/panel.js +4 -4
- package/src/mcp/tools/project.js +47 -31
- 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/add-panel.js +1 -1
- package/src/project/docs.js +3 -1
- package/src/project/manifest.js +3 -2
- package/src/project/project.js +2 -2
- package/src/project/template.js +5 -1
- package/src/prompt.js +1 -1
- package/src/release/installers.js +4 -4
- package/src/release/native.js +3 -0
- package/src/release/package.js +1 -1
- package/src/release/publish.js +1 -1
- package/src/system/run-command.js +1 -1
- package/src/targets.js +1 -0
- package/src/user-config.js +2 -2
- package/template/cep/AGENTS.md +104 -0
- package/template/{README.md → cep/README.md} +16 -11
- package/template/cep/docs/code_guide.md +67 -0
- package/template/cep/docs/initial_setup.md +115 -0
- package/template/cep/docs/release_checklist.md +24 -0
- package/template/{src → cep/src}/features/home/home.html +4 -4
- package/template/{src → cep/src}/features/home/home.js +10 -11
- package/template/{src → cep/src}/shared/lib/host-theme.js +3 -3
- package/template/{src → cep/src}/shared/lib/view.js +1 -1
- package/template/{src → cep/src}/shared/ui/tokens.css +1 -1
- package/template/hosts/AGENTS.two-apps.md +12 -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/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
- package/vendor/afterpresets-additions/AfterEffects.d.ts +291 -0
- package/vendor/afterpresets-additions/Premiere.d.ts +179 -0
- package/vendor/types-for-adobe/Premiere/24.0/index.d.ts +2567 -0
- package/vendor/types-for-adobe/README.md +8 -4
- package/template/AGENTS.md +0 -168
- package/template/docs/initial_setup.md +0 -69
- package/template/jsx/home.jsx +0 -17
- /package/runtime/docs/{boot.md → common/boot.md} +0 -0
- /package/template/{.mcp.json → cep/.mcp.json} +0 -0
- /package/template/{gitignore → cep/gitignore} +0 -0
- /package/template/{package.json → cep/package.json} +0 -0
- /package/template/{src → cep/src}/features/home/home.css +0 -0
- /package/template/{src → cep/src}/features/license-screen/license-screen.css +0 -0
- /package/template/{src → cep/src}/features/license-screen/license-screen.html +0 -0
- /package/template/{src → cep/src}/features/license-screen/license-screen.js +0 -0
- /package/template/{src → cep/src}/features/update-screen/update-screen.css +0 -0
- /package/template/{src → cep/src}/features/update-screen/update-screen.html +0 -0
- /package/template/{src → cep/src}/features/update-screen/update-screen.js +0 -0
- /package/template/{src → cep/src}/panels/main/index.html +0 -0
- /package/template/{src → cep/src}/panels/main/main.js +0 -0
- /package/template/{src → cep/src}/shared/lib/dom.js +0 -0
- /package/template/{src → cep/src}/shared/lib/markdown.js +0 -0
- /package/template/{src → cep/src}/shared/ui/base.css +0 -0
- /package/template/{src → cep/src}/shared/ui/button.css +0 -0
- /package/template/{src → cep/src}/shared/ui/card.css +0 -0
- /package/template/{src → cep/src}/shared/ui/field.css +0 -0
- /package/template/{src → cep/src}/shared/ui/index.css +0 -0
|
@@ -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 |
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Testing a native effect
|
|
3
|
+
description: How the agent tests every change itself in After Effects - build, apply the effect with host_eval, render frames with comp_capture and look at them - plus the checks to run before saying done.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Testing a native effect
|
|
7
|
+
|
|
8
|
+
You test your own work. A change is done only when you have built it, applied
|
|
9
|
+
the effect in After Effects, rendered frames, **looked at them**, and shown
|
|
10
|
+
them to the user. "It compiles" is not done.
|
|
11
|
+
|
|
12
|
+
The tools are on the AfterPresets MCP server:
|
|
13
|
+
|
|
14
|
+
| Tool | Use |
|
|
15
|
+
|---|---|
|
|
16
|
+
| `host_bridge` | Status, install or removal of the dev bridge that lets the tools reach After Effects when the project has no panel |
|
|
17
|
+
| `host_scratch_project` | Switch After Effects to a scratch project before changing anything |
|
|
18
|
+
| `host_eval` | Run ExtendScript in After Effects: build a test comp, apply the effect, set parameters, read values |
|
|
19
|
+
| `comp_capture` | Render frames of a comp at full quality and return them as images (up to 12 per call) |
|
|
20
|
+
|
|
21
|
+
## One-time setup
|
|
22
|
+
|
|
23
|
+
1. The first `ap dev` installs the dev bridge. Call `host_bridge` with no
|
|
24
|
+
action; if the bridge is not installed, call it with `action: "install"`.
|
|
25
|
+
Then ask the user to save their work and restart After Effects once. Afterwards `host_bridge` must report the bridge as
|
|
26
|
+
loaded in After Effects.
|
|
27
|
+
2. Never quit or restart After Effects yourself while the user may have
|
|
28
|
+
unsaved work. Ask them.
|
|
29
|
+
|
|
30
|
+
## Every change
|
|
31
|
+
|
|
32
|
+
1. **Build and install.** Save; `ap dev` (or `dev_start`) rebuilds, signs
|
|
33
|
+
the plugin for local use and installs it into
|
|
34
|
+
`/Library/Application Support/Adobe/Common/Plug-ins/7.0/MediaCore/AfterPresets Dev/<bundleId>/`.
|
|
35
|
+
Call `dev_status` until the build is ok; fix compiler errors from its
|
|
36
|
+
`file:line` list. After Effects loads plugins only when it starts, so when
|
|
37
|
+
`dev_status` says **RESTART NEEDED**: `ap dev` restarts After Effects by
|
|
38
|
+
itself only when that is safe (a saved or scratch project, no dialog
|
|
39
|
+
open); otherwise ask the user to save their work and restart it. Never
|
|
40
|
+
quit, kill or restart After Effects yourself.
|
|
41
|
+
2. **Scratch project.** Call `host_scratch_project` before you add, change or
|
|
42
|
+
delete anything in After Effects. Never test in the user's project.
|
|
43
|
+
3. **Apply the effect by match name** in a test comp with `host_eval`:
|
|
44
|
+
|
|
45
|
+
```js
|
|
46
|
+
var c = app.project.items.addComp("AP Test", 1920, 1080, 1, 4, 30);
|
|
47
|
+
var bg = c.layers.addSolid([0.15, 0.3, 0.6], "Base", 1920, 1080, 1, 4);
|
|
48
|
+
var t = c.layers.addText("Hello"); // something with edges and alpha
|
|
49
|
+
t.property("ADBE Transform Group").property("ADBE Scale").setValue([400, 400]);
|
|
50
|
+
var fx = t.property("ADBE Effect Parade").addProperty("ACME Soft Glow"); // your match name
|
|
51
|
+
if (!fx) return "not applied";
|
|
52
|
+
fx.property(1).setValue(40); // first parameter after the layer
|
|
53
|
+
c.openInViewer();
|
|
54
|
+
return fx.name + " | " + fx.numProperties + " properties";
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
If `addProperty` throws or returns null, the match name is wrong or After
|
|
58
|
+
Effects did not load the plugin: see [debugging.md](debugging.md).
|
|
59
|
+
4. **Render and look.** Call `comp_capture` (for example `frames: [0, 60, 119]`,
|
|
60
|
+
or `seconds: [1.5]`). It clears After Effects' caches first by default, so
|
|
61
|
+
every frame comes from the build that is loaded now (undo history is kept).
|
|
62
|
+
Open each image and check what the change
|
|
63
|
+
was meant to do, plus edges, transparency and colour.
|
|
64
|
+
5. **Show the user** the frames and say what you checked and what you did not.
|
|
65
|
+
|
|
66
|
+
## Testing the locked (signed-out) state
|
|
67
|
+
|
|
68
|
+
Dev builds from `ap dev` render **without** the licence watermark, so you
|
|
69
|
+
can judge the look. To test what a signed-out buyer sees, create the file
|
|
70
|
+
`~/.afterpresets/native-dev-enforce-license` (or start After Effects with
|
|
71
|
+
`AP_DEV_ENFORCE_LICENSE=1`), restart After Effects (ask the user), and
|
|
72
|
+
capture frames. Delete the file afterwards. Release builds always enforce
|
|
73
|
+
the licence. The status button (`params[AP_PARAM_LICENSE]`, caption
|
|
74
|
+
"License...") shows the state in its name, e.g. "License: sign in"; read it
|
|
75
|
+
with `host_eval` if needed.
|
|
76
|
+
|
|
77
|
+
## Before saying done
|
|
78
|
+
|
|
79
|
+
Run what applies to the change. Each line names the classic bug it catches
|
|
80
|
+
(the rules are in [rules.md](rules.md)).
|
|
81
|
+
|
|
82
|
+
| Check | How | Catches |
|
|
83
|
+
|---|---|---|
|
|
84
|
+
| Every parameter | Set each to its minimum, default and maximum; capture | Wrong union member, ranges, division by zero |
|
|
85
|
+
| Animation | Keyframe a parameter (`setValueAtTime`), capture several frames | Values read at the wrong time, cached state |
|
|
86
|
+
| 16 and 32 bpc | `app.project.bitsPerChannel = 16` then `32`, capture the same frames; compare with 8 | Missing depth paths, 32767/65535 white, clamped overbrights |
|
|
87
|
+
| Half resolution | `c.resolutionFactor = [2, 2]`, capture; the result must look like a smaller copy of full resolution | Ignored downsample factors |
|
|
88
|
+
| Small or moved layer | Layer smaller than the comp, partly outside it | Hard-coded sizes, `rowbytes`, origin |
|
|
89
|
+
| Upstream expansion | Put a Gaussian Blur before your effect, capture with the blur on and off | Buffer origin, point parameters |
|
|
90
|
+
| Two instances | Apply the effect to two layers with different settings, capture | Globals and statics shared between instances |
|
|
91
|
+
| Save and reopen | Save the scratch project, `app.open()` it again, capture the same frame | Parameter disk IDs, sequence data flattening |
|
|
92
|
+
| Render speed | Read the render times `comp_capture` reports (caches are cleared first) | Slow paths, blocking work in render |
|
|
93
|
+
|
|
94
|
+
Not covered yet (say so to the user when it matters): the Windows `.aex` is
|
|
95
|
+
built on the Mac but tested by the user on a Windows PC; Premiere Pro;
|
|
96
|
+
multi-frame rendering under load. For the last one, when the effect declares
|
|
97
|
+
multi-frame rendering, ask the user to render the test comp from the Render
|
|
98
|
+
Queue with Multi-Frame Rendering on and compare it with your captures.
|
|
99
|
+
|
|
100
|
+
## Scripting pitfalls
|
|
101
|
+
|
|
102
|
+
Some After Effects scripting errors abort the whole `host_eval` script, and
|
|
103
|
+
`try/catch` cannot catch them. Avoid them:
|
|
104
|
+
|
|
105
|
+
- **Re-fetch an effect after `moveTo()`.** `fx.moveTo(1)` invalidates `fx`;
|
|
106
|
+
the next access to the old reference aborts the script. Get it again by
|
|
107
|
+
index or name:
|
|
108
|
+
|
|
109
|
+
```js
|
|
110
|
+
fx.moveTo(1);
|
|
111
|
+
fx = layer.property("ADBE Effect Parade").property(1);
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
- **Never turn an array into a string implicitly** (`"" + value`, `alert(arr)`,
|
|
115
|
+
string concatenation with a colour or point value). Use `value.join(",")`
|
|
116
|
+
or `JSON.stringify(value)`.
|
|
117
|
+
- **Never open a modal dialog** from a script: no `alert`, `confirm`,
|
|
118
|
+
`prompt`, `File.openDialog`, and no `app.project.save()` without a file
|
|
119
|
+
(it shows the Save dialog). While a dialog is open After Effects answers
|
|
120
|
+
no tool calls.
|
|
121
|
+
- **Save and reopen** (the "Save and reopen" check) without dialogs: save the
|
|
122
|
+
scratch project to an explicit file, open it again, then look everything
|
|
123
|
+
up again by name, because every comp, layer and effect reference from
|
|
124
|
+
before is invalid:
|
|
125
|
+
|
|
126
|
+
```js
|
|
127
|
+
var f = new File(Folder.temp.fsName + "/ap-test-reopen.aep");
|
|
128
|
+
app.project.save(f);
|
|
129
|
+
app.open(f);
|
|
130
|
+
var c = null;
|
|
131
|
+
for (var i = 1; i <= app.project.numItems; i++) {
|
|
132
|
+
if (app.project.item(i).name === "AP Test") c = app.project.item(i);
|
|
133
|
+
}
|
|
134
|
+
var fx = c.layer("Hello").property("ADBE Effect Parade").property(1);
|
|
135
|
+
return fx.matchName;
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
Then `comp_capture` the same frames as before saving and compare them.
|
|
139
|
+
- **The effect's Options dialog is modal.** Never open or click it from a
|
|
140
|
+
script or tool. When it needs checking (sign-in, licence status, update
|
|
141
|
+
text), ask the user to click the effect's **Options** link or its
|
|
142
|
+
**License...** button, and to tell you or screenshot what it shows.
|
|
143
|
+
|
|
144
|
+
## If something goes wrong
|
|
145
|
+
|
|
146
|
+
- `comp_capture` times out or After Effects stops answering: a modal dialog
|
|
147
|
+
(error, crash report, licence) may be open. Ask the user what After Effects
|
|
148
|
+
shows; do not retry in a loop.
|
|
149
|
+
- The frame did not change after a rebuild: the old binary is still loaded.
|
|
150
|
+
`dev_status` says whether a restart is needed; After Effects must restart
|
|
151
|
+
to load a new build.
|
|
152
|
+
- `host_eval` or `comp_capture` returns nothing or says the script engine
|
|
153
|
+
is busy: After Effects is probably showing a dialog. Ask the user.
|
|
154
|
+
- Crashes and load failures: [debugging.md](debugging.md).
|
package/runtime/package.json
CHANGED
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
// What the generator reads and how the result is organised.
|
|
4
|
+
//
|
|
5
|
+
// Bumping the pin: clone the repository, check out the new commit, run
|
|
6
|
+
// node scripts/ae-sdk-docs.js --source <checkout> --out <tmp> --allow-unpinned
|
|
7
|
+
// read the output, then copy the printed commit and digest here. The run fails
|
|
8
|
+
// if a page or anchor named in TASKS no longer exists; fix TASKS first.
|
|
9
|
+
|
|
10
|
+
const PIN = {
|
|
11
|
+
repo: "docsforadobe/after-effects-plugin-guide",
|
|
12
|
+
commit: "c3fc3fc4132bbd0088b0b32461a5f21b2a88eb7b",
|
|
13
|
+
date: "2026-11-03",
|
|
14
|
+
sdk: "After Effects 27.0 SDK",
|
|
15
|
+
digest: "sha256:246909fbbd4d9e275ef4355649e4f68039e15eeec63ae3f121fc0c4a69fa2d02",
|
|
16
|
+
site: "https://ae-plugins.docsforadobe.dev",
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
/** Source pages left out: not about effect plug-ins (3D renderers, file importers) or no use to an agent. */
|
|
20
|
+
const EXCLUDE = [/^index\.md$/, /^history\.md$/, /^artisans\//, /^aeios\//];
|
|
21
|
+
|
|
22
|
+
const RENAME = {
|
|
23
|
+
"effect-details/tips-tricks.md": "effect-tips",
|
|
24
|
+
"effect-ui-events/tips-and-tricks.md": "ui-tips",
|
|
25
|
+
"intro/next-steps.md": "intro-next-steps",
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
// Sections whose page names are too generic on their own ("overview",
|
|
29
|
+
// "multithreading", "global-outflags").
|
|
30
|
+
const PREFIX = { "ppro/": "ppro", "audio/": "audio", "aegps/": "aegp" };
|
|
31
|
+
|
|
32
|
+
/** Output file name (without .md) for a source page path like "effect-basics/PF_InData.md". */
|
|
33
|
+
function outputName(sourcePath) {
|
|
34
|
+
if (RENAME[sourcePath]) return RENAME[sourcePath];
|
|
35
|
+
const base = sourcePath
|
|
36
|
+
.split("/")
|
|
37
|
+
.pop()
|
|
38
|
+
.replace(/\.md$/, "")
|
|
39
|
+
.toLowerCase()
|
|
40
|
+
.replace(/_/g, "-");
|
|
41
|
+
const dir = Object.keys(PREFIX).find((d) => sourcePath.indexOf(d) === 0);
|
|
42
|
+
if (!dir) return base;
|
|
43
|
+
const stem = PREFIX[dir];
|
|
44
|
+
if (base === stem || base === stem + "s" || base.indexOf(stem + "-") === 0) return base;
|
|
45
|
+
return stem + "-" + base;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// Split thresholds in characters (about 4 characters per token).
|
|
49
|
+
const LIMITS = { maxChars: 14000, singleMax: 18000, minChars: 4000, mergeMax: 9000 };
|
|
50
|
+
|
|
51
|
+
/** Reading order for a first effect. */
|
|
52
|
+
const START_HERE = [
|
|
53
|
+
"intro/what-can-i-do.md",
|
|
54
|
+
"effect-basics/entry-point.md",
|
|
55
|
+
"effect-basics/command-selectors.md#calling-sequence",
|
|
56
|
+
"effect-basics/parameters.md",
|
|
57
|
+
"smartfx/smartfx.md",
|
|
58
|
+
"effect-details/multi-frame-rendering-in-ae.md",
|
|
59
|
+
];
|
|
60
|
+
|
|
61
|
+
/** Task -> source references ("page.md" or "page.md#anchor"). Every reference must resolve. */
|
|
62
|
+
const TASKS = [
|
|
63
|
+
["Start a new effect: how plug-ins work, the entry point", ["intro/what-can-i-do.md", "effect-basics/effect-basics.md", "effect-basics/entry-point.md"]],
|
|
64
|
+
["Copy from an Adobe sample project", ["intro/sample-projects.md#sample-project-descriptions"]],
|
|
65
|
+
["Handle a command (PF_Cmd_*), know which command comes when", ["effect-basics/command-selectors.md#calling-sequence", "effect-basics/command-selectors.md#command-selectors-table"]],
|
|
66
|
+
["Read what After Effects passes in (in_data: time, downsampling, extent_hint)", ["effect-basics/PF_InData.md#pf_indata-members", "effect-basics/PF_InData.md#extent_hint-usage"]],
|
|
67
|
+
["Set capabilities: out_flags / out_flags2", ["effect-basics/PF_OutData.md#pf_outflags", "effect-basics/PF_OutData.md#pf_outflags2"]],
|
|
68
|
+
["Write or change the PiPL (match name, category, version, flags)", ["intro/pipl-resources.md", "intro/pipl-resources.md#multiple-pipls"]],
|
|
69
|
+
["Add a parameter (slider, color, point, popup, checkbox, layer...)", ["effect-basics/parameters.md#parameter-types", "effect-basics/PF_ParamDef.md#pf_paramdef-members", "effect-basics/PF_ParamDef.md#parameter-flags"]],
|
|
70
|
+
["Add, remove or reorder parameters in an effect that has shipped", ["effect-details/changing-parameter-orders.md"]],
|
|
71
|
+
["Show, hide, enable or change parameters from code", ["effect-details/parameter-supervision.md#updating-parameter-ui", "effect-details/parameter-supervision.md#updating-parameter-values"]],
|
|
72
|
+
["Read a parameter at another time, or a layer parameter's pixels", ["effect-details/interaction-callback-functions.md#interaction-callbacks", "effect-details/interaction-callback-functions.md#parameter-checkout-behavior"]],
|
|
73
|
+
["Float values for color, point and angle parameters", ["effect-details/parameters-floating-point-values.md"]],
|
|
74
|
+
["Store custom data in a parameter (arbitrary data)", ["effect-details/arbitrary-data-parameters.md"]],
|
|
75
|
+
["Loop over pixels (iterate 8/16/32 bpc)", ["effect-details/iteration-suites.md", "effect-basics/PF_EffectWorld.md#pf_effectworld-structure", "effect-basics/PF_EffectWorld.md#rowbytes-in-pf_effectworlds"]],
|
|
76
|
+
["Smart Render (PreRender / SmartRender, checking out layers)", ["smartfx/smartfx.md#how-to-smartify", "smartfx/smartfx.md#pf_cmd_smart_pre_render", "smartfx/smartfx.md#pf_cmd_smart_render"]],
|
|
77
|
+
["Support 16 bpc and 32 bpc (float) color", ["smartfx/smartfx.md#the-way-things-are-now", "effect-ui-events/tips-and-tricks.md#how-deep-are-my-pixels", "effect-basics/PF_EffectWorld.md#pf_pixelptr-accessor-macros"]],
|
|
78
|
+
["Draw outside the layer bounds (glows, shadows: expand the output)", ["effect-basics/PF_InData.md#point-controls-and-buffer-expansion", "smartfx/smartfx.md#rectangles", "smartfx/smartfx.md#the-size-of-a-layer"]],
|
|
79
|
+
["Multi-frame rendering and thread safety", ["effect-details/multi-frame-rendering-in-ae.md", "effect-details/multi-frame-rendering-in-ae.md#what-does-it-mean-for-an-effect-to-be-thread-safe", "effect-details/accessing-function-suites.md#threading"]],
|
|
80
|
+
["Cache expensive results across frames and threads (Compute Cache)", ["effect-details/compute-cache-api.md"]],
|
|
81
|
+
["Global, sequence and frame data (and flattening)", ["effect-details/global-sequence-frame-data.md", "effect-details/multi-frame-rendering-in-ae.md#sequence-data-in-multi-frame-rendering"]],
|
|
82
|
+
["Allocate memory and image buffers", ["effect-details/memory-allocation.md", "effect-details/image-buffer-management-functions.md"]],
|
|
83
|
+
["Use a function suite (AcquireSuite, versions)", ["effect-details/accessing-function-suites.md", "intro/compatibility-across-multiple-versions.md#api-versions"]],
|
|
84
|
+
["Sample, transform, blend, fill and convert color (utility callbacks)", ["effect-details/graphics-utility-suites.md", "effect-details/color-space-conversion.md", "effect-details/useful-utility-functions.md"]],
|
|
85
|
+
["Non-square pixels and downsampled previews", ["effect-details/pixel-aspect-ratio.md"]],
|
|
86
|
+
["Masks and paths, cameras and lights, motion blur", ["effect-details/working-with-paths.md", "effect-details/accessing-camera-light-information.md", "effect-details/motion-blur.md"]],
|
|
87
|
+
["Custom UI in the comp or Effect Controls (events, Drawbot)", ["effect-ui-events/effect-ui-events.md", "effect-ui-events/custom-ui-and-drawbot.md", "effect-ui-events/PF_EventExtra.md", "effect-ui-events/ui-callbacks.md"]],
|
|
88
|
+
["GPU rendering (Metal, CUDA, OpenCL, DirectX)", ["intro/gpu-build-instructions.md"]],
|
|
89
|
+
["Call AEGP suites from an effect (project, layers, streams)", ["aegps/cheating-effect-usage-of-aegp-suites.md", "aegps/aegp-suites.md", "aegps/aegp-details.md#accessing-pixels-from-effect-layer-parameters"]],
|
|
90
|
+
["Report errors, handle exceptions, out-of-memory", ["effect-basics/errors.md", "intro/exceptions.md"]],
|
|
91
|
+
["Debug a plug-in (attach a debugger, reset preferences)", ["intro/debugging-plug-ins.md", "intro/debugging-ae-macos.md"]],
|
|
92
|
+
["Build for Apple silicon (universal) and Windows on Arm, export only the entry point", ["intro/apple-silicon-support.md", "intro/windows-on-arm-support.md", "intro/symbol-export.md"]],
|
|
93
|
+
["Where the plug-in is installed", ["intro/where-installers-should-put-plug-ins.md", "ppro/plug-in-installation.md"]],
|
|
94
|
+
["Support older After Effects versions, see what changed in each SDK", ["intro/compatibility-across-multiple-versions.md", "intro/whats-new.md"]],
|
|
95
|
+
["Effects panel: search keywords, description and preview media", ["intro/pipl-resources.md#search-keywords-and-description", "effect-details/effect-preview-media.md"]],
|
|
96
|
+
["Localized names and UTF-8 strings", ["intro/localization.md"]],
|
|
97
|
+
["Make the effect work in Premiere Pro", ["ppro/ppro.md", "ppro/basic-host-differences.md", "ppro/bigger-differences.md", "ppro/multithreading.md", "ppro/unsupported-features.md"]],
|
|
98
|
+
["Audio effects", ["audio/audio.md", "audio/accessing-audio-data.md"]],
|
|
99
|
+
["Performance, caching and testing tips from Adobe", ["effect-details/tips-tricks.md", "effect-details/tips-tricks.md#testing", "effect-ui-events/tips-and-tricks.md#ui-performance"]],
|
|
100
|
+
];
|
|
101
|
+
|
|
102
|
+
module.exports = { PIN, EXCLUDE, RENAME, PREFIX, LIMITS, START_HERE, TASKS, outputName };
|