---
name: create-plugin
description: Scaffold a new Adobe Premiere Pro / After Effects video effect plugin (C++ AE SDK). Creates all source files, build scripts, and project structure for a fully buildable .plugin bundle. Use when the user wants to create a new Premiere Pro plugin, After Effects effect, video filter, color effect, or motion graphics plugin.
---


# Create AE SDK Plugin

You are a Premiere Pro / After Effects plugin development expert. Your job is to scaffold a complete, buildable C++ plugin project from a name and description.

## Parse Arguments

`$ARGUMENTS` format: `PluginName Description of what the effect does`

- **First word** = PascalCase plugin name (e.g., `ChromaBlur`, `FilmGrain`, `ColorShift`)
- **Remaining words** = effect description

Derive these values:
- `PLUGIN_NAME` = first word (PascalCase, e.g., `ChromaBlur`)
- `PLUGIN_NAME_UPPER` = SCREAMING_SNAKE (e.g., `CHROMABLUR`)
- `PLUGIN_MATCH_NAME` = `GUALO_PluginName` (e.g., `GUALO_ChromaBlur`)
- `PLUGIN_CATEGORY` = same as PLUGIN_NAME (shows as menu category)
- `BUNDLE_IDENTIFIER` = `com.gualo.pluginnamelowercase`

## Project Structure to Generate

```
<PluginName>/
  src/
    <PluginName>.h           # Plugin header
    <PluginName>.cpp          # Main SDK implementation
    <PluginName>_PiPL.r       # PiPL resource
    <PluginName>Engine.h      # Processing algorithms
  build.sh                    # Shell build script (primary)
  Info.plist                  # macOS bundle metadata
  CMakeLists.txt              # CMake build (alternative)
```

## Step-by-Step Generation Procedure

1. **Read all template files** from `~/.claude/skills/create-plugin/templates/`:
   - `PluginName.h.template`
   - `PluginName.cpp.template`
   - `PluginName_PiPL.r.template`
   - `PluginNameEngine.h.template`
   - `build.sh.template`
   - `Info.plist.template`
   - `CMakeLists.txt.template`

2. **Design the effect parameters** based on the description. Choose from:
   - `PF_ADD_FLOAT_SLIDERX(name, min, max, slider_min, slider_max, default, precision, display_flags, flags, disk_id)` — for continuous values
   - `PF_ADD_POPUP(name, num_choices, default, "Choice1|Choice2|Choice3", disk_id)` — for mode selection
   - `PF_ADD_CHECKBOX(name, comment, default, flags, disk_id)` — for toggles
   - `PF_ADD_COLOR(name, r_default, g_default, b_default, disk_id)` — for color pickers
   - `PF_ADD_ANGLE(name, default_angle, disk_id)` — for rotation
   - `PF_ADD_POINT(name, x_default, y_default, restrict_bounds, disk_id)` — for XY position
   - `PF_ADD_SLIDER(name, min, max, slider_min, slider_max, default, disk_id)` — for integer values

3. **Design the processing algorithm** in the Engine.h file. The engine receives three separate float arrays (R, G, B) in [0,1] range and modifies them in place.

4. **Determine the correct OutFlags:**
   - If the effect is a pure per-pixel color operation (no spatial/neighbor reads): include `PF_OutFlag_PIX_INDEPENDENT`
   - If the effect uses blur, convolution, or reads neighboring pixels: do NOT include `PF_OutFlag_PIX_INDEPENDENT`
   - Always include: `PF_OutFlag_DEEP_COLOR_AWARE | PF_OutFlag_NON_PARAM_VARY | PF_OutFlag_WIDE_TIME_INPUT`

5. **Calculate PiPL OutFlags hex:**
   - PIX_INDEPENDENT = 0x2000000, DEEP_COLOR_AWARE = 0x400, NON_PARAM_VARY = 0x4
   - With PIX_INDEPENDENT: `0x2000404`
   - Without PIX_INDEPENDENT: `0x404`
   - OutFlags2 is always: `0x8001400`

6. **Write all files** to the project directory using the templates as a base, replacing all `{{PLACEHOLDER}}` values.

7. **Make build.sh executable:** `chmod +x build.sh`

8. **Set up AE SDK symlink:** Check if `ae_sdk/` exists. If not, look for the SDK at common locations:
   - `~/Downloads/AfterEffectsSDK_*/`
   - Prompt the user if not found and create the symlink.

9. **Offer to build:** Run `./build.sh` to verify compilation.

10. **Offer to install:** Copy to `~/Library/Application Support/Adobe/Common/Plug-ins/7.0/MediaCore/`

---

## CRITICAL RULES — Violations Cause Crashes or Broken Plugins

These rules were learned the hard way building working plugins. NEVER violate them.

### Render Region (CRASH PREVENTION)
- ALWAYS use `extent_hint` for the render region, NEVER `output->width` or `output->height`
- Pattern:
  ```cpp
  int top = output->extent_hint.top;
  int bottom = output->extent_hint.bottom;
  int left = output->extent_hint.left;
  int right = output->extent_hint.right;
  if (bottom <= top || right <= left) { // fallback
      top = 0; left = 0; bottom = output->height; right = output->width;
  }
  int width = right - left;
  int height = bottom - top;
  ```
- Using width/height directly causes out-of-bounds access and crashes Premiere.

### Premiere Pixel Formats (BGRA ONLY)
- Only register BGRA formats (VUYA/YCbCr causes pink hue on render):
  - `PrPixelFormat_BGRA_4444_8u` — struct: `{ blue, green, red, alpha }` as `A_u_char`
  - `PrPixelFormat_BGRA_4444_32f` — struct: `{ blue, green, red, alpha }` as `PF_FpShort`
  - AE native: `PF_Pixel8` with `{ alpha, red, green, blue }` as `A_u_char`
- Do NOT register VUYA formats — they cause a pink/magenta overlay during render/export
- Unknown pixel formats: fallback to `safeCopyFrame(input, output)` passthrough
- The .cpp template already has correct format handling — use it verbatim.

### Memory Safety
- ALWAYS use `calloc`, NEVER `malloc` for pixel buffers (prevents garbage pixels)
- ALWAYS null-check: `if (!params || !output || !in_data || !out_data) return PF_Err_BAD_CALLBACK_PARAM;`
- ALWAYS free ALL allocated buffers, even on error paths
- ALWAYS cast row offsets to long: `(char*)data + (long)y * rowbytes`
- ALWAYS check alloc results: `if (!ptr) { free(other); return PF_Err_OUT_OF_MEMORY; }`

### Parameter System
- Popup params are **1-based** in AE SDK. Subtract 1 when reading: `params[X]->u.pd.value - 1`
- Float slider values: `params[X]->u.fs_d.value`
- ALWAYS call `AEFX_CLR_STRUCT(def)` before EVERY `PF_ADD_*` macro
- Each param needs a unique, stable Disk ID starting at 1. NEVER renumber after release.

### Build System (macOS)
- Use **build.sh** as primary build (Make breaks on spaces in paths)
- Use `eval` with quoted paths in build.sh for safety
- Rez uses lowercase `-d` (NOT `-D`): `-d AE_OS_MAC`
- Required SDK util sources: `AEGP_SuiteHandler.cpp`, `MissingSuiteError.cpp`, `AEFX_SuiteHelper.c`
- Do **NOT** compile `String_Utils.c` (causes unresolved symbol errors)
- Universal binary: `-arch arm64 -arch x86_64`
- C++17: `-std=c++17`
- Optimization: `-O2`
- Frameworks: `-framework CoreFoundation -framework CoreServices -framework Accelerate`
- Ad-hoc code sign: `codesign --force --sign -` (REQUIRED macOS 15+)

### PiPL Resource
- MUST have both `CodeMacIntel64` and `CodeMacARM64` entry points set to `"EffectMain"`
- OutFlags hex MUST match what GlobalSetup sets
- AE_Effect_Version `524288` = version 1.0

### Plugin Flags
- out_flags2 always: `PF_OutFlag2_FLOAT_COLOR_AWARE | PF_OutFlag2_SUPPORTS_SMART_RENDER | PF_OutFlag2_SUPPORTS_THREADED_RENDERING`
- For per-pixel effects: `PF_OutFlag_PIX_INDEPENDENT | PF_OutFlag_DEEP_COLOR_AWARE | PF_OutFlag_NON_PARAM_VARY | PF_OutFlag_WIDE_TIME_INPUT`
- For spatial effects (blur, etc.): Same but WITHOUT `PF_OutFlag_PIX_INDEPENDENT`

### Entry Point
- Always use `PluginDataEntryFunction2` (new style) with `PF_REGISTER_EFFECT_EXT2`
- EffectMain MUST have try/catch wrapping all commands
- Handle: `PF_Cmd_ABOUT`, `PF_Cmd_GLOBAL_SETUP`, `PF_Cmd_PARAMS_SETUP`, `PF_Cmd_RENDER`

### Pass-through Optimization
- Check if all effect params are at zero/default. If so, `safeCopyFrame(input, output)` and return.
- This prevents unnecessary processing and keeps Premiere responsive.

### Performance (learned from real 4K testing)
- Gaussian blur: use 3-pass box blur approximation (O(n) not O(n*k))
- Large blur radii (>15 sigma): use half-resolution blur (downsample → blur → upsample)
- Never allocate per-pixel temporary buffers inside a loop — allocate once outside
- Cap all blur radii to prevent memory explosions (max 200 pixels)

### Random/Animated Effects
- Per-frame grain seed: `(uint32_t)(in_data->current_time) ^ 0xDEADBEEF`
- Set `PF_OutFlag_NON_PARAM_VARY` so Premiere knows the output can vary even without param changes

### Installation Path
- User-level (no sudo): `~/Library/Application Support/Adobe/Common/Plug-ins/7.0/MediaCore/`
- System-level (sudo): `/Library/Application Support/Adobe/Common/Plug-ins/7.0/MediaCore/`

---

## Common Effect Patterns

### Pure Color Effect (brightness, contrast, hue shift, LUT)
- Set PIX_INDEPENDENT
- PiPL OutFlags: `0x2000404`
- No blur utilities needed in Engine.h
- Simple per-pixel loop in processFrame

### Blur/Convolution Effect (gaussian blur, sharpen, edge detect)
- Do NOT set PIX_INDEPENDENT
- PiPL OutFlags: `0x404`
- Include box blur utilities in Engine.h
- Use fastBlurHalfRes for large radii

### Film Emulation Effect (grain, halation, bloom, vignette)
- Do NOT set PIX_INDEPENDENT (halation/bloom use spatial reads)
- PiPL OutFlags: `0x404`
- Include all DSP utilities
- Use multi-resolution mip-chain for bloom
- Per-channel blur for halation

### Composite/Blend Effect
- May need PIX_INDEPENDENT depending on approach
- Consider alpha channel handling
