fxplug-sys 0.1.1

Raw C ABI types for Rust-authored FxPlug effects
Documentation
# FxPlug Rust Bindings

Rust authoring surface for FxPlug 4 `FxTileableEffect` plug-ins on macOS 12+.

The v0.1 public scope is intentionally narrow: one Rust tileable image effect
per PlugInKit service. This crate is not a complete FxPlug SDK binding layer.
The longer-term plan for fuller bindings is tracked in the
[roadmap](https://github.com/Dragoy/fxplug-rust/blob/master/ROADMAP.md).

The MVP uses Objective-C as the Apple runtime shim and Rust for plugin logic:

- `fxplug-sys`: C-compatible ABI structs, constants, and the shared C header.
- `fxplug`: safe Rust trait/macro API for single tileable effects.
- `examples/brightness-plugin`: first plugin and acceptance fixture.
- `examples/glitch-wgpu-plugin`: glitch effect example with a `wgpu` WGSL
  shader description and Rust CPU fallback for the current FxPlug bridge.
- `Plugin` plus `src/rust_bridge.*`: Objective-C FxPlug/Metal/IOSurface shim.
- `FxPlugRust.xcodeproj`: committed Xcode build wrapper that emits a variant
  app bundle with an embedded FxPlug 4 PlugInKit service.

## Rust API

Plugins implement `TileableEffect` and are exported declaratively:

```rust
use fxplug::{register_plugin, TileableEffect};

struct MyEffect;

impl TileableEffect for MyEffect {
    /* metadata, parameters, state, rects, render */
}

register_plugin!(MyEffect);
```

The v0.1 surface covers properties, float/int/toggle parameters, typed
parameter values, plugin state, destination/source tile rects, CPU RGBA32F
rendering, raw Metal/IOSurface callback pointers, and a small Metal render plan
used by the Objective-C helper.

`register_plugins!` remains as a single-plugin compatibility alias. Passing
multiple effect types is a compile error because the committed Objective-C
PlugInKit shim registers one `FxTileableEffect` class and dispatches plugin
index `0`.

## Build

Rust-only checks work on Linux and macOS:

```sh
cargo fmt --check
cargo clippy --workspace --all-targets
cargo test --workspace
cargo publish -p fxplug-sys --dry-run --allow-dirty
cargo publish -p fxplug --dry-run --allow-dirty
```

On macOS, build the plugin bundle:

```sh
xcodebuild -project FxPlugRust.xcodeproj \
  -scheme FxPlugRust \
  -configuration Release \
  -destination 'platform=macOS' \
  MACOSX_DEPLOYMENT_TARGET=12.0 \
  PRODUCT_NAME=FxPlugRustBrightness \
  CODE_SIGNING_ALLOWED=NO \
  build
```

The default wrapper app is written to
`build/Release/FxPlugRustBrightness.app`. For local testing, remove any old
standalone copy from `~/Library/Plug-Ins/FxPlug`, then register the FxPlug 4
service through PlugInKit:

```sh
rm -rf ~/Library/Plug-Ins/FxPlug/FxPlugRust.fxplug
pluginkit -a build/Release/FxPlugRustBrightness.app/Contents/PlugIns/FxPlugRust.pluginkit
pluginkit -m -p FxPlug | grep FxPlugRust
```

You can also place the wrapper app in `/Applications` and launch it once so
Launch Services discovers the embedded service.

The default macOS build is universal (`arm64` and `x86_64`) with
`MACOSX_DEPLOYMENT_TARGET=12.0`, so it can be tested on both Apple Silicon and
Intel Macs running macOS 12 or newer.

By default the wrapper links `examples/brightness-plugin`. To build the glitch
example instead, pass the Rust package and staticlib names through the build:

```sh
FXPLUG_RUST_PACKAGE=glitch-wgpu-plugin \
FXPLUG_RUST_LIB=fxplug_glitch_wgpu \
xcodebuild -project FxPlugRust.xcodeproj \
  -scheme FxPlugRust \
  -configuration Release \
  -destination 'platform=macOS' \
  MACOSX_DEPLOYMENT_TARGET=12.0 \
  PRODUCT_NAME=FxPlugRustGlitch \
  CODE_SIGNING_ALLOWED=NO \
  build
```

The glitch build writes a distinct app bundle,
`build/Release/FxPlugRustGlitch.app`, and a distinct PlugInKit service
identifier, `com.bigblage.fxplugrust.glitch.service`. If `pluginkit -m -p
FxPlug` still shows `com.bigblage.fxplugrust.brightness.service`, you are
registering an older app bundle or a brightness build. Re-register the freshly
built
`build/Release/FxPlugRustGlitch.app/Contents/PlugIns/FxPlugRust.pluginkit`, or
replace `/Applications/FxPlugRustGlitch.app` with the new build before running
`pluginkit -a`. The `(1.1)` printed by `pluginkit` is the FxPlug service
protocol version from PlugInKit metadata, not the Rust effect version.

The dynamic FxPlug registration reads display name, description, and UUID from
the linked Rust plugin descriptor, so the same Objective-C shim can host either
example.

The plug-in service links FxPlug and PluginManager with runtime search paths for
Final Cut Pro, Motion, Compressor, and `/Library/Frameworks`. This lets the
service load the host-provided FxPlug runtime instead of requiring a separate
framework install in `/Library/Frameworks`.

## SDK Artifacts

CI expects these FxPlug fixtures under `vendor/fxplug-sdk/`:

- `FxPlug.sdk_4.3.3-3d7c879c31ba.zip`, containing `FxPlug.framework` and
  `PluginManager.framework` headers plus `.tbd` link stubs with macOS 11+
  deployment metadata. The project builds with `MACOSX_DEPLOYMENT_TARGET=12.0`.
- `FxPlug.framework-c0a7a1c76ef2.zip` and
  `PluginManager.framework-a39aecfa287b.zip`, runtime framework archives from a
  Mac. CI validates that they are present but does not link against them.
- `FxPlugSDK_headers.tar.gz`, a legacy headers-only fallback used only when the
  primary SDK zip is unavailable.

If your licensed SDK is stored elsewhere, set `FXPLUG_SDK_DIR` to a directory
whose `Library/Frameworks` contains both frameworks, or set `FXPLUG_SDK_ZIP`
to an equivalent SDK archive. To use a legacy headers tarball, set
`FXPLUG_SDK_HEADERS_TARBALL`.