@fcannizzaro/streamdeck-react

createPlugin

Configure and initialize the @fcannizzaro/streamdeck-react plugin.

createPlugin is the entry point for your plugin. It configures fonts, registers actions, and returns a plugin instance with a connect() method.

Basic Usage

import { createPlugin, googleFont } from "@fcannizzaro/streamdeck-react";
import { counterAction } from "./actions/counter";

const inter = await googleFont("Inter");

const plugin = createPlugin({
  fonts: [inter],
  actions: [counterAction],
});

await plugin.connect();

Configuration

interface PluginConfig {
  adapter?: StreamDeckAdapter;
  fonts: FontConfig[];
  actions: ActionDefinition[];
  wrapper?: WrapperComponent;
  info?: PluginManifestInfo;
  takumi?: TakumiBackend;
  imageFormat?: "png" | "webp";
  caching?: boolean;
  devicePixelRatio?: number;
  onActionError?: (uuid: string, actionId: string, error: Error) => void;
  devtools?: boolean;
  debug?: boolean;
  imageCacheMaxBytes?: number;
  touchStripCacheMaxBytes?: number;
  useWorker?: boolean;
  coordinator?: boolean;
  theme?: ThemeDefinition;
  stylesheets?: string[];
}

adapter

The Stream Deck adapter to use. Defaults to physicalDevice() which wraps the @elgato/streamdeck SDK. Pass a custom adapter to use an alternative backend (web simulator, test harness):

import { createPlugin, physicalDevice } from "@fcannizzaro/streamdeck-react";

const plugin = createPlugin({
  adapter: physicalDevice(), // explicit, or omit for same default
  fonts: [...],
  actions: [...],
});

See Adapter for details on the StreamDeckAdapter interface and writing custom adapters.

fonts (required)

Array of font configurations used by the Takumi renderer. At least one font is required. See Font Management.

actions (required)

Array of action definitions created with defineAction.

wrapper

An optional React component that wraps all action roots. Use this to inject global providers (state management, themes, etc.):

const plugin = createPlugin({
  fonts: [...],
  actions: [...],
  wrapper: ({ children }) => <MyGlobalProvider>{children}</MyGlobalProvider>,
});

info

Optional plugin manifest metadata. This is used for runtime documentation. For manifest generation, provide plugin-level info via the bundler plugin's manifest option in streamDeckReact().

takumi

Selects the Takumi renderer backend. Default: 'native-binding'.

  • 'native-binding' — Uses the native Rust NAPI addon (@takumi-rs/core). Native binaries are lazy-loaded from npm by default — no platform-specific packages need to be installed. This is the fastest and most capable mode, supporting all font formats including WOFF/WOFF2.
  • 'wasm' — Uses the WebAssembly build (@takumi-rs/wasm). Useful for WebContainer and browser-based environments where native addons cannot load. WOFF/WOFF2 fonts are not supported in this mode — use TTF or OTF only. Worker threads are automatically disabled.
const plugin = createPlugin({
  takumi: "wasm", // use WASM renderer instead of native binding
  fonts: [...],
  actions: [...],
});

When using the bundler plugin (streamDeckReact()), pass the matching takumi option to skip native binary copying:

streamDeckReact({
  takumi: "wasm", // skips .node file copying
});

imageFormat

Output image format. Default: 'png'. Set to 'webp' if you prefer WebP output.

caching

Enable output hash caching to skip duplicate setImage() calls. Default: true.

devicePixelRatio

Device pixel ratio used by the Takumi renderer. Default: 1.

onActionError

Called when a component error is caught by the root error boundary:

const plugin = createPlugin({
  // ...
  onActionError: (uuid, actionId, error) => {
    myErrorTracker.report(error);
  },
});

devtools

Enable the devtools server. The browser devtools UI discovers it via port scanning. The port is derived deterministically from the plugin UUID (range 39400-39499). Default: false. See DevTools.

debug

Enable performance diagnostics including render counters, duplicate detection, and depth warnings. Default: process.env.NODE_ENV !== 'production' (enabled in development, disabled in production).

imageCacheMaxBytes

Maximum byte budget for the key/dial image cache (LRU, byte-bounded). Cached renders are skipped entirely on cache hit. Set to 0 to disable. Default: 16777216 (16 MB).

touchStripCacheMaxBytes

Maximum byte budget for the TouchStrip raw buffer cache. This cache stores RGBA buffers for rendered TouchStrip frames. Set to 0 to disable. Default: 8388608 (8 MB).

useWorker

Offload Takumi rendering to a worker thread. This prevents the native rasterization (5-30ms per frame) from blocking the main thread during animations. When not set, auto-detected: enabled only if any action defines a touchStrip component. Set explicitly to true or false to override. Automatically disabled when takumi is "wasm". Default: auto-detect.

coordinator

Enable the Action Coordinator for cross-action communication. When enabled, actions can use useChannel() for shared state and useActionPresence() to observe which actions are visible on the device. Default: false.

const plugin = createPlugin({
  coordinator: true,
  fonts: [...],
  actions: [...],
});

See Action Coordinator for a full guide.

theme

A CSS theme definition created with defineTheme(). Tokens are injected as CSS custom properties on every root's container element, making them available via Tailwind arbitrary values like bg-[var(--color-primary)].

import { createPlugin, defineTheme, googleFont } from "@fcannizzaro/streamdeck-react";

const theme = defineTheme({
  colors: { primary: "#4CAF50", surface: "#1a1a2e" },
  spacing: { sm: "4px", md: "8px", lg: "16px" },
});

const plugin = createPlugin({
  theme,
  fonts: [await googleFont("Inter")],
  actions: [...],
});

See CSS Theme System for a full guide.

stylesheets

CSS stylesheets to pass to the Takumi renderer. Enables full Tailwind v4 support including @theme blocks, custom utilities, and any standard CSS.

Use @tailwindcss/vite in your Vite config and import your CSS file with the ?inline query to get the compiled stylesheet as a string at build time:

// theme.css — @import "tailwindcss"; @theme { --color-primary: #4CAF50; }
import stylesheet from "./theme.css?inline";

const plugin = createPlugin({
  stylesheets: [stylesheet],
  fonts: [await googleFont("Inter")],
  actions: [...],
});

In components, you can use Tailwind v4 theme tokens directly:

<div className="bg-primary text-white">Themed</div>

See Tailwind CSS for a full guide.

connect()

connect() must be the last call in your entry file. It calls adapter.connect() to establish the connection with the Stream Deck backend (or custom adapter).

The action registration, font initialization, and renderer setup all happen during the connect() call — createPlugin() prepares the configuration, connect() performs the actual initialization and opens the connection.

On this page