VS

Theme, features and events

The editor is the VidstudioEditor component from @vidstudio/editor. Three props shape it: theme, features and shortcuts. One prop, onEvent, reports what happens inside it. mountEditor takes the same props.

The theme

A theme is an object of type EditorTheme. Each key sets one custom property on the editor root element. The package exports two full themes: darkTheme (the default) and lightTheme.

Pass a partial theme to change some keys only. The other keys keep their default.

import { VidstudioEditor, lightTheme } from "@vidstudio/editor";
import type { VidstudioEditorProps } from "@vidstudio/editor";

export function BrandedEditor(props: Pick<VidstudioEditorProps, "store" | "projectId">) {
  return (
    <div style={{ height: "100vh" }}>
      <VidstudioEditor {...props} theme={{ ...lightTheme, accentPrimary: "#0f766e", fontFamily: "Inter, sans-serif" }} />
    </div>
  );
}

The host page is not changed. The variables live on the editor root, not on :root.

Four keys need an explanation. textOnAccent colours text and icons on an accent button. accentWarning also colours keyframes. mediaBg, mediaText and mediaTextMuted sit behind the video and over it. They stay dark and light in both themes.

Key darkTheme lightTheme
bgPrimary #0a0a0b #ffffff
bgSecondary #111113 #f6f6f7
bgTertiary #18181b #eeeef0
bgCard #141416 #fbfbfc
bgCardHover #1c1c1f #f1f1f3
bgElevated #202024 #ffffff
textPrimary #ffffff #18181b
textSecondary #a1a1aa #52525b
textTertiary #71717a #71717a
textMuted #52525b #a1a1aa
textOnAccent #ffffff #ffffff
accentPrimary #ff6363 #e5484d
accentPrimaryHover #ff7a7a #d63c41
accentSecondary #3b82f6 #2563eb
accentSuccess #22c55e #16a34a
accentWarning #f59e0b #d97706
accentWarningHover #fbbf24 #b45309
accentError #ef4444 #dc2626
borderPrimary #27272a #e4e4e7
borderSecondary #3f3f46 #d4d4d8
borderHover #52525b #a1a1aa
errorSurface #3a1a1a #fef2f2
errorBorder #662222 #fecaca
errorText #ff8888 #b91c1c
warningSurface #3a2e1a #fffbeb
warningBorder #665522 #fde68a
warningText #f0b45a #b45309
mediaBg #000000 #000000
mediaText #ffffff #ffffff
mediaTextMuted #cccccc #cccccc
timelineBg #111111 #fafafa
timelineTrackBorder #2a2a2a #e4e4e7
timelineRulerText #888888 #71717a
timelinePlayhead #e8524a #e5484d
timelineWaveform #f4845f #ea580c
timelineSnap #4fc3f7 #0284c7
radiusSm 6px 6px
radiusMd 8px 8px
fontFamily -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Inter', 'Helvetica Neue', Arial, sans-serif same as dark

Feature flags

The features prop is a partial object of type EditorFeatures. Every flag defaults to true. The full set is exported as allFeatures.

This mounts an editor with captions and the tour off.

import { VidstudioEditor } from "@vidstudio/editor";
import type { VidstudioEditorProps } from "@vidstudio/editor";

export function PlainEditor(props: Pick<VidstudioEditorProps, "store" | "projectId">) {
  return (
    <div style={{ height: "100vh" }}>
      <VidstudioEditor {...props} features={{ captions: false, tour: false }} />
    </div>
  );
}
Flag What disappears when it is off
sourceMonitor The Source and Program tabs over the preview, and the Source Monitor panel.
tour The tour button and the tour that opens on the first visit.
safeZones The guides picker over the preview, and the guide lines it draws.
captions The Transcribe control in the effect panel. No speech model is ever downloaded.
transitions The transition handles where two clips meet on a video or audio track.
keyframes The keyframe markers on timeline clips, and the keyframe controls in the effect panel.
export The Export button and the export dialog.
projectSettings The canvas size picker and the frame rate picker.
textTracks The "Add text track" button in the timeline toolbar.
imageImport The image import button in the timeline toolbar.
audioImport The audio import button in the timeline toolbar.
shortcutsHelp The shortcuts button, and the key that opens the shortcut list.
projectFiles The "Save project" and "Open project" entries of the project menu.

Shortcuts

The shortcuts prop has two values.

Value Where keys are heard
"scoped" (default) On the editor root only. A key reaches the editor only while focus is inside it. Inputs on the host page are never affected.
"global" On the window. Every key on the page reaches the editor. Use it for a page that holds nothing but the editor.

Events

onEvent receives two kinds of event. An engine event comes from the backend; its type is EditorEvent from @vidstudio/engine. A user interface event comes from the editor's own components; its type is EditorUiEvent from @vidstudio/editor. Every event has a kind field. The other fields are the payload.

Kind Source Payload When it fires
timeline-changed engine none A track, clip or transition changed.
effects-changed engine clipId: string | null An effect, keyframe or geometry changed on one clip. null means re-read every clip.
project-changed engine none The name, canvas size, frame rate, work area or loop setting changed.
player-state engine state: "idle" | "loading" | "ready" | "playing" | "paused" | "seeking" The player changed state.
time engine seconds: number The playhead moved.
duration engine seconds: number The timeline length changed.
load-progress engine fraction: number The project is loading into the player, 0 to 1.
proxy-progress engine assetId: string, fraction: number | null A preview proxy is being made, 0 to 1. null means it finished, failed or stopped.
audio-loading engine count: number How many audio tracks are still decoding their sound.
export-progress engine progress: { phase, currentFrame, totalFrames, percent } The export advanced. phase is "preparing", "video", "audio" or "finalizing".
warning engine message: string The engine has something to show the user.
error engine message: string, error: Error An import or playback failure.
preview-played engine none play() started the preview. Sent on every play.
media-imported engine mediaType: "video" | "audio" | "both", clipDurationSec: number, addedTo: "new_track" | "existing_track" An asset was placed on the timeline with addTrackFromAsset or addClipFromAsset. A picture with its linked sound is one event, "both".
export-started engine settings: ExportSettings An export began.
export-finished engine settings: ExportSettings, result: ExportResult, durationMs: number An export produced a file.
export-failed engine settings: ExportSettings, error: Error, phase: string | null, durationMs: number An export failed for any reason but a cancel. phase is the last progress phase reached.
storage-full engine operation: "import" | "export" | "delete_track", error: Error Browser storage refused a write because it is full.
export-downloaded user interface settings: ExportSettings The user pressed Download in the export dialog, or onExport received the file.
export-released user interface reason: "dialog_closed" | "page_left", outputBytes: number The finished export file was deleted from browser storage.

ExportSettings and ExportResult are described in Driving the engine.

This component counts exports.

import { useState } from "react";
import { VidstudioEditor } from "@vidstudio/editor";
import type { VidstudioEditorProps } from "@vidstudio/editor";

export function CountingEditor(props: Pick<VidstudioEditorProps, "store" | "projectId">) {
  const [finished, setFinished] = useState(0);
  const [downloaded, setDownloaded] = useState(0);
  return (
    <div style={{ height: "100vh" }}>
      <p>
        {finished} exports finished, {downloaded} downloaded
      </p>
      <VidstudioEditor
        {...props}
        onEvent={(event) => {
          if (event.kind === "export-finished") setFinished((n) => n + 1);
          if (event.kind === "export-downloaded") setDownloaded((n) => n + 1);
        }}
      />
    </div>
  );
}

A new onEvent function does not rebuild the editor. A new options object does, so keep options stable.