Video Studio SDKv0.0.3
Plugin authoringExtension points

Register icons

Add icons to the global map so your plugin's UI can use them — and so other plugins can too.

ctx.registerIcons(map) adds arbitrary icon components to the global icon map. They become available everywhere useIconMap() is read — including in your own panels and inspector sections. Use this when:

  • Your plugin needs a glyph the SDK doesn't ship (a brand icon, a domain-specific symbol).
  • You want to override one of the built-in defaults from a plugin (you usually shouldn't — host-app icons overrides are the right place).

Registering

import { createPlugin } from '@studio-dev/vsdk/plugins'
import { SparkleIcon, FlameIcon } from './icons'

export const myPlugin = () =>
  createPlugin({
    id:      'mycompany:my-plugin',
    name:    'My Plugin',
    version: '0.1.0',
    onRegister(ctx) {
      ctx.registerIcons({
        sparkle: SparkleIcon,
        flame:   FlameIcon,
      })

      ctx.registerPanel({
        id:        'my-panel',
        label:     'My Panel',
        icon:      ctx.icons.sparkle,    // refer back to the icon you just registered
        component: lazy(() => import('./panel')),
        order:     50,
      })
    },
  })

Each value must satisfy StudioIconComponent = ComponentType<{ className?: string }> — the SDK applies sizing through className.

Precedence

The resolved icon map is built in this order:

defaults  ←  plugin-registered icons  ←  consumer icons prop

So:

  • Plugin-registered icons override defaults (use sparingly).
  • Consumer (host app) icons prop on VideoStudioProvider always wins.

This layering lets the host app rebrand the editor regardless of which plugins are loaded — a plugin can register sparkle, but if the host also passes icons={{ sparkle: MyBrand }}, the brand wins.

When to register vs. override

Use caseMechanism
Your plugin needs a glyph the SDK doesn't shipctx.registerIcons
You want to globally rebrand all play/pause/save iconsHost app's icons prop
You want a custom icon visible only in your plugin's UIJust import and use it directly — don't pollute the global map

The last row is worth emphasizing: not every plugin icon needs to be registered. If only your panel renders it, importing the React component and using it directly is fine — the registry exists for cross-plugin sharing and theming, not as a generic icon catalog.

Reading icons from other plugins

If plugin A registers sparkle, plugin B's components can read it through useIconMap():

import { useIconMap } from '@studio-dev/vsdk'

function PluginBPanel() {
  const icons = useIconMap()
  const Sparkle = icons.sparkle    // present if plugin A registered it
  if (!Sparkle) return null
  return <Sparkle className="size-4" />
}

Useful for ecosystem icons — e.g. a "brand kit" plugin registers brand glyphs that other plugins opt-in to using.

TypeScript

StudioIconMap is an intersection of Record<StudioIconName, StudioIconComponent> with Record<string, StudioIconComponent>, so reading an unknown key returns a possibly-undefined component without a type error:

const icons = useIconMap()
const Sparkle = icons.sparkle  // type: StudioIconComponent (may be undefined at runtime)

For a stricter typing on your own plugin keys, extend the map type:

declare module '@studio-dev/vsdk' {
  interface StudioIconMap {
    sparkle: StudioIconComponent
    flame:   StudioIconComponent
  }
}

Use module augmentation sparingly — once it's in a d.ts shared with consumers, every host app sees your keys.

On this page