Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/gratitude5dee/wzrd-studio-desktopfinal/llms.txt

Use this file to discover all available pages before exploring further.

WZRD Studio ships as a native macOS application built on Electron 42, with a Vite 5 + React 19 + TypeScript 5.5 single-page app running in the renderer process. The shell handles deep-link routing, custom protocol registration, FFmpeg media processing, PTY session management, and a secure IPC bridge — all while keeping Node.js APIs completely out of reach of renderer JavaScript. Every privileged operation flows through a narrow, explicitly-typed IPC surface.

Process Model

WZRD Studio uses the standard Electron three-layer model: a Node.js main process, an isolated renderer process (the React SPA), and a preload script that bridges the two. Node integration is deliberately disabled in the renderer; nothing from node:* can be accessed directly by React components.
┌─────────────────────────────────────────────────────────────────┐
│  Main Process  (electron/main.js — Node.js / Electron APIs)     │
│                                                                  │
│  • Protocol handlers (wzrd://app/, wzrd://media/)               │
│  • IPC handlers  (ipcMain.handle)                               │
│  • FFmpeg/ffprobe child processes                               │
│  • PTY sessions (node-pty)                                      │
│  • Deep-link routing                                            │
└───────────────────────────┬─────────────────────────────────────┘
                            │  contextBridge (preload.cjs)
                            │  window.wzrdDesktop
                            │  window.wzrdQcut
┌───────────────────────────▼─────────────────────────────────────┐
│  Renderer Process  (src/ — Vite + React 19 + TypeScript)        │
│                                                                  │
│  • getDesktopBridge()  → WzrdDesktopBridge | null               │
│  • All media / clip-studio / QCut calls go through IPC          │
└─────────────────────────────────────────────────────────────────┘

Main Process — electron/main.js

The entry point for the Electron shell. On startup it:
  1. Registers the wzrd:// scheme as privileged before app.ready fires.
  2. Applies a custom userData path if WZRD_DESKTOP_USER_DATA_DIR is set.
  3. Creates a MediaFileAccess instance that gates which local paths the renderer may read via the wzrd://media/ protocol.
  4. Calls app.whenReady() to install the application menu, protocol handler, all IPC handlers, and a permission handler (camera/microphone requests are blocked outside trusted app navigation).
  5. Enforces single-instance via app.requestSingleInstanceLock() — a second launch routes any deep-link argument to the existing window.
electron/main.js is an ES module (.js with "type": "module" in package.json). The preload script is CommonJS (preload.cjs) because Electron requires synchronous require() in preload context.

Key helpers in main.js

FunctionPurpose
createMainWindow()Creates the BrowserWindow, wires navigation guards, loads the start URL
installIpcHandlers()Registers all ipcMain.handle listeners for media, clip-studio, and media file access
installProtocolHandler()Attaches the wzrd:// protocol handler via protocol.handle
installPermissionHandler()Blocks all browser permission requests except media from trusted app URLs
routeDeepLink(rawUrl)Translates a wzrd:// deep-link to an app URL and loads it (or queues it as pendingDeepLink)
sendMediaProgress(operationId, progress)Pushes wzrd:media:progress events to the renderer during long FFmpeg operations
sendFfmpegProgress(operationId, progress)Pushes wzrd:clip-studio:ffmpeg-progress events
sendYoutubeDownloadProgress(operationId, progress)Pushes wzrd:clip-studio:youtube-download-progress events

Preload Bridge — electron/preload.cjs

The preload script uses Electron’s contextBridge to expose two globals to the renderer — no Node.js APIs are leaked. All calls are wrapped in ipcRenderer.invoke (request/response) or ipcRenderer.on (push events).
Exposes the core media and Clip Studio operations used by the React app. All methods return Promise (or, for event subscriptions, a cleanup function).
// Declared in src/lib/desktop.ts
interface WzrdDesktopBridge {
  isDesktop: true;
  platform: string;
  openExternal: (url: string) => Promise<boolean>;
  getDeepLink: (path: string) => string;
  // Media (all optional — check before calling)
  probeMedia?: (params: { filePath: string; ffmpegPath?: string }) => Promise<DesktopVideoMetadata>;
  extractThumbnail?: (params: { operationId: string; sourcePath: string; outputPath: string; atMs: number }) => Promise<{ outputPath: string }>;
  extractWaveformPeaks?: (params: { operationId: string; sourcePath: string; resolution?: number; sampleRate?: number }) => Promise<{ peaks: number[] }>;
  renderPreviewProxy?: (params: { operationId: string; sourcePath: string; outputPath: string }) => Promise<{ outputPath: string }>;
  renderTimeline?: (params: { operationId: string; timeline: LocalTimelineRenderPlan; outputPath: string }) => Promise<{ outputPath: string }>;
  runStudioMediaAction?: (params: { operationId: string; actionId: string; outputFolder: string }) => Promise<{ outputPath?: string; outputs?: Array<{ type: string; path?: string }> }>;
  cacheRemoteMedia?: (params: { operationId: string; url: string; name?: string }) => Promise<{ path: string; mediaUrl: string }>;
  // Clip Studio (all optional)
  cutClip?: (params: { operationId: string; sourcePath: string; outputPath: string; startSeconds: number; durationSeconds: number }) => Promise<{ outputPath: string }>;
  exportVerticalClip?: (params: { operationId: string; sourcePath: string; outputPath: string }) => Promise<{ outputPath: string }>;
  downloadYoutubeVideo?: (params: { operationId: string; url: string }) => Promise<DesktopYoutubeDownloadResult>;
  // Progress subscriptions (return unsubscribe fn; all optional)
  onFfmpegProgress?: (cb: (p: DesktopFfmpegProgress) => void) => () => void;
  onMediaProgress?: (cb: (p: DesktopFfmpegProgress) => void) => () => void;
  onYoutubeDownloadProgress?: (cb: (p: DesktopYoutubeDownloadProgress) => void) => () => void;
}

Renderer — src/

The React SPA is a Vite 5 project compiled to dist/ and served via the wzrd://app/ protocol. In development mode (ELECTRON_RENDERER_URL env set) Electron loads the Vite dev server URL directly.

Desktop Bridge Detection

Renderer code detects the desktop context using getDesktopBridge() from src/lib/desktop.ts. In a web browser the function returns null, allowing WZRD Studio to run as a progressive web app as well.
import { getDesktopBridge, isDesktopRuntime } from '@/lib/desktop';

// Returns WzrdDesktopBridge | null
const bridge = getDesktopBridge();

if (bridge) {
  // Running inside Electron — full media processing available
  const metadata = await bridge.probeMedia({ filePath: '/path/to/video.mp4' });
} else {
  // Running in browser — fall back to cloud processing
}
// Full type signature from src/lib/desktop.ts
export function getDesktopBridge(): WzrdDesktopBridge | null {
  if (typeof window === 'undefined') return null;
  const bridge = window.wzrdDesktop;
  return bridge?.isDesktop ? bridge : null;
}

export function isDesktopRuntime(): boolean {
  return getDesktopBridge() !== null;
}
Always check getDesktopBridge() before calling any window.wzrdDesktop method. The same React components render in both desktop and web mode.

Security Model

WZRD Studio enforces a strict security posture in the renderer:
SettingValueEffect
contextIsolationtrueRenderer JS cannot access the preload script’s Node scope
nodeIntegrationfalseNo require() or Node APIs in renderer
sandboxtrueRenderer runs in Chromium sandbox
webSecuritytrueSame-origin policy enforced
allowRunningInsecureContentfalseBlocks mixed content
External navigation is intercepted on will-navigate and setWindowOpenHandler. Only https://, http://, and mailto: URLs are allowed to open in the system browser. All other navigations are blocked.
// electron/window-options.js
export function createMainWindowOptions({ preloadPath, iconPath } = {}) {
  return {
    width: 1440,
    height: 960,
    minWidth: 1100,
    minHeight: 720,
    title: "WZRD Studio",
    backgroundColor: "#050506",
    show: false,
    webPreferences: {
      preload: preloadPath,
      contextIsolation: true,
      nodeIntegration: false,
      sandbox: true,
      webSecurity: true,
      allowRunningInsecureContent: false,
      devTools: true,
    },
  };
}

Protocol Registration

Two custom URL schemes are registered before app.ready.
Registered with protocol.registerSchemesAsPrivileged as standard, secure, supportFetchAPI, corsEnabled, and stream.Two sub-hosts are served under this scheme:
HostExample URLServes
appwzrd://app/editorCompiled React SPA from dist/ (falls back to index.html for SPA routing)
mediawzrd://media/?file=%2Fpath%2Fto%2Fvideo.mp4Local media files from the allow-list
The protocol handler in main.js routes requests via resolveAppProtocolRequest (app assets) and resolveClipperMediaProtocolRequest (local media). Path traversal is rejected at both layers.
// electron/protocol.js
export const WZRD_PROTOCOL = "wzrd";
export const WZRD_APP_HOST  = "app";
export const WZRD_MEDIA_HOST = "media";

// Build a playback URL for a local file:
buildClipperMediaUrl('/Users/alice/clips/intro.mp4')
// → "wzrd://media/?file=%2FUsers%2Falice%2Fclips%2Fintro.mp4"

FFmpeg Toolchain

All media processing delegates to an FFmpeg binary on the host system. The shell provides three toolchain helpers:
Searches common macOS installation paths for ffmpeg and a co-located ffprobe:
/opt/homebrew/bin/ffmpeg     (Homebrew Apple Silicon)
/usr/local/bin/ffmpeg        (Homebrew Intel)
$HOME/.local/bin/ffmpeg
ffmpeg                       (PATH fallback)
Returns a FfmpegToolchain object:
interface FfmpegToolchain {
  available: boolean;
  version?: string;
  ffmpegPath: string;
  ffprobePath: string;
  ffprobeAvailable: boolean;
  diagnostics: string[];
  error?: string;
}
Called before every export job. Verifies:
  • Source file is readable.
  • Output directory is writable (writes a probe file).
  • libx264 encoder is present.
  • aac encoder is present.
Throws a user-readable error if any check fails.
Maps raw FFmpeg exit codes, signals, and stderr tails to user-friendly error messages, including specific messages for:
  • ENOENT / binary not found
  • Missing libx264 or aac encoders
  • Permission-denied output paths
  • Filter-graph failures

Media File Access Control

Only explicitly allow-listed paths can be served via wzrd://media/. The allow-list is managed by createMediaFileAccess in electron/media-file-access.js.
// electron/media-file-access.js
export function createMediaFileAccess({ roots = [] } = {}) {
  const allowedMediaPaths = new Set();
  return {
    allowMediaPath(filePath) { /* adds resolved path to set */ },
    isAllowedMediaPath(filePath) { /* checks set + roots */ },
  };
}
Paths are added to the set when:
  • The user selects a file via showOpenDialog.
  • A YouTube video finishes downloading to userData/clipper/imports/.
  • A remote media URL is cached to userData/media-cache/.
  • An FFmpeg export writes its output file.
Two helper utilities are also exported:
  • isPathInside(rootDir, filePath) — strict path containment check (no symlink tricks).
  • safeFileStem(value) — strips unsafe characters from a filename stem for use in cache paths.
  • extensionForRemoteMedia(url, contentType) — infers a file extension from a remote URL and its Content-Type header.

QCut Bridge — electron/qcut-bridge.js

setupQcutBridge() registers the wzrd:qcut:* IPC namespace used by WZRD’s AI editor engine. It provides:
  • FFmpeg export sessions — frame-by-frame canvas rendering → ffmpeg CLI composition.
  • PTY sessions — full xterm-compatible pseudo-terminal via node-pty (unpacked from asar to allow native bindings).
  • Project folder management — per-project userData/qcut-projects/<id>/ hierarchy with media/, skills/, and exports/ sub-directories.
  • Skills — markdown-based instruction files bundled with the app and synced to ~/.claude/skills/ for the Claude CLI.
  • MCP server — a local Model Context Protocol server started alongside the bridge.
  • Agent command channel — bidirectional command/response channel for the agent API, protected by a permission gate.
node-pty contains native binaries and must be excluded from the asar archive. The electron-builder config sets asarUnpack: ['node_modules/node-pty/**'] to handle this automatically.

Agent Relay — packages/wzrd-agent-relay/

A Cloudflare Worker at packages/wzrd-agent-relay/src/index.ts acts as a WebSocket relay for agent PTY sessions. It uses Cloudflare Durable Objects (WzrdAgentPtySession) to maintain session state, connects to sandboxes via @daytona/sdk, and authenticates requests via a JWT verified against DAYTONA_RELAY_JWT_SECRET.
// packages/wzrd-agent-relay/src/index.ts
export default {
  async fetch(req: Request, env: Env): Promise<Response> {
    const url = new URL(req.url);
    if (url.pathname !== '/pty') return new Response('not_found', { status: 404 });
    const token = url.searchParams.get('token');
    if (!token) return new Response('missing_token', { status: 400 });
    const sessionId = peekSessionId(token);
    if (!sessionId) return new Response('bad_token', { status: 400 });
    const id = env.WZRD_AGENT_PTY.idFromName(sessionId);
    return env.WZRD_AGENT_PTY.get(id).fetch(req);
  },
};
The relay requires these Worker environment bindings:
BindingTypePurpose
WZRD_AGENT_PTYDurable Object namespaceStores per-session PTY state
SUPABASE_URLSecretValidates user sessions
SUPABASE_SERVICE_ROLE_KEYSecretService-level Supabase access
DAYTONA_API_KEYSecretDaytona SDK authentication
DAYTONA_RELAY_JWT_SECRETSecretSigns and verifies relay JWTs

Build & Packaging

WZRD Studio targets macOS Apple Silicon (arm64). The build pipeline uses electron-builder invoked via bun run desktop:dist:mac.
# Build the macOS DMG
bun run desktop:dist:mac

# Outputs:
# release/wzrdstudiofinal555.dmg
# release/mac-arm64/WZRD Studio.app
Key build settings:
SettingValue
App IDcom.wzrd.studio
DMG artifactwzrdstudiofinal555.dmg
Target archarm64
asartrue
asarUnpacknode_modules/node-pty/**
afterPackCustom post-packaging script
The DMG is currently unsigned and un-notarized. On first launch, macOS Gatekeeper will block it. Users must right-click → Open, or approve it in System Settings → Privacy & Security → Open Anyway.

Development Mode

# Start the Vite renderer dev server
bun run dev

# Start Electron pointing at the dev server
bun run desktop:dev

# Run targeted unit tests
bun x vitest run src/lib/desktop.test.ts electron/deep-links.test.js

# Lint
bun run lint
In dev mode, ELECTRON_RENDERER_URL is set to the Vite dev server URL. The main process loads that URL instead of the compiled dist/ bundle, and Electron DevTools are enabled.

Build docs developers (and LLMs) love