Skip to content

Repository files navigation

StageWizard

Native macOS show control for live performance: a cue-based audio, video, and camera playback engine built for running real stages — theaters, magic shows, talks, and touring rigs. Apple Silicon, macOS 26.1+, Swift 6 (strict concurrency), SwiftUI + AppKit, AVFoundation. No third-party dependencies.

StageWizard

What it does

  • Audio cues — per-cue output-device routing (Core Audio, hot-plug aware), sample-accurate in/out trim, per-cue volume in dB, fade in/out, gapless looping with play counts or infinite loop, exit-loop.

  • Video cues — playback on virtual output groups ("Internal", "External", "Prompter"…): named sets of displays managed in one settings panel, so a whole cue list re-routes in seconds when the rig changes. A group can span several displays and mirrors one decode onto all of them. Fit/fill/stretch, hold-last-frame or unload at end, embedded-audio routing to any output device, trim, loops, fades.

  • Geometry — per-cue Fill Stage or Custom placement: position (X/Y) and scale the image on its stage, with a draggable mini-canvas and live updates while the cue plays. Stage-relative units, so one layout means the same thing on every display of a group.

  • Camera cues — live camera input (built-in, USB/UVC, Continuity) on any output group; runs until stopped; fade in/out.

  • Image cues — still images (PNG/JPEG/HEIC…) on any output group, with geometry and fades; holds until stopped.

  • Text cues — rich text on stage (titles, lower thirds): a 16:9 WYSIWYG editor with a formatting toolbar (bold/italic, alignment, size, line height, color) plus the macOS Fonts panel; pasted formatting survives, backgrounds are transparent or colored, and edits render live while the cue plays.

  • Render layers — every visual cue picks a layer 1–10 (1 = background, 10 = front) so video, camera, text, and stills stack predictably.

  • Live camera effects — per-cue, toggled live: person segmentation (the background turns transparent, revealing lower layers behind the performer), chroma key (green-screen keying with color, tolerance, and softness controls — composes with segmentation), and magic dust — particle emitters that follow the performer's hands (Vision hand tracking), with six bundled emitter presets, any Particle Designer .pex file, and a 0.5–10× particle-size dial. All on-device (Vision + CoreImage), nothing external at showtime. Experimental gesture GO: hold a pose to a running camera cue for one second and GO fires — open palm, closed fist, thumbs up, or both hands together, your pick per cue. A performer mid-routine needs no keyboard, and the stage display can show the hold-progress bar so you know the trigger is arming.

  • Slide decks — drop a PowerPoint (.pptx/.ppt) or PDF and it becomes a navigable deck: one group named after the file, one cue per slide, GO to advance, crossfade between slides, trailing clear cue. Decks are flattened to per-slide images at import by the best converter installed (ONLYOFFICE's OOXML-native engine, PowerPoint, Keynote, or LibreOffice — plain PDFs need nothing at all), so nothing external ever runs during a show.

  • Sequencing — pre-wait, auto-continue (anchored to cue start + post-wait), auto-follow (fires on completion), auto-continue at a marker (drop named markers on the waveform/filmstrip timeline and anchor the next cue to a beat inside the media), and a playhead that skips past auto chains the way operators expect.

  • Playback rate — audio and video cues run at 0.25×–4× (tape-style varispeed for audio); durations, fades, and marker follows all track the rate in wall-clock time.

  • Wall-clock triggers — any cue can fire itself at a time of day (once per day, in Show or Rehearsal mode): preshow music at 19:30, doors at 19:55, no operator needed.

  • Groups — fire-all-at-once, timeline mode with a drag-to-arrange editor (each child is a bar on a ruler; audio bars show waveforms), or enter-and-play-first: GO steps the playhead through the group's children one by one — how slide decks navigate.

  • Fade & stop cues — target any running cue (or everything); resolved against live playback at fire time; fade to level or to silence with stop-when-done.

  • Action cues — StageWizard conducts the rest of the rig from the same cue list: OSC cues send one OSC message to any host:port (typed int/float/string arguments — fire a lighting console, a media server, a drone rig in the same beat as your video); MIDI cues send a note, CC, or program change to any MIDI destination (a note-off always follows, even through panic — no hanging synths); HTTP cues fire a GET/POST at any URL (PTZ presets, relay boxes, stream decks); GoTo cues jump the playhead to any cue — optionally firing it — for repeatable sections, encores, and preshow loops. All fire-and-forget: the show never waits on the network.

  • Panic — Esc fades everything out over the show's panic duration; Esc twice hard-stops instantly. Hardwired, not reassignable.

  • Workspace modes — Edit / Show (locks every editing surface while transport stays live) / Rehearsal (stays fully editable, and video and camera output goes to floating, resizable preview windows — one per output group — so you can adjust the show with no rig attached). The mode is saved with the show file.

  • Virtual webcam — activate the bundled StageWizard Camera system extension and any output group can mirror into it: Zoom, Teams, or OBS pick "StageWizard Camera" and receive your show feed at 1080p30, driven by the same cue list as the stage outputs. The feed state is saved with the show, and a floating monitor panel shows exactly what the camera transmits. In Show mode the whole transport turns red — one glance says the workspace is live.

  • Remote control — every trigger source funnels through one bus: MIDI (any note or CC, assigned by MIDI-Learn, hot-plug aware; a CC fires only on the press, so a held pedal can't machine-gun GO), OSC over UDP (/stagewizard/go, /stopall, /next, /prev, /toggle, /panic, /cue/{number}/fire, /cue/{number}/select) — which also advertises itself over Bonjour (_stagewizard._udp) and pushes live status feedback (standing-by cue, running count, panic, window, notes, elapsed, full cue list, a liveness heartbeat) to any sender it's heard from recently, so a hardware controller never has to poll (with a Bluetooth LE fallback tunnel carrying the same OSC contract when show Wi-Fi dies — the app auto-reconnects to advertising controllers as a standing central) — and a web remote — the app serves a dark phone page (huge GO, prev/next, double-tap STOP ALL, standing-by cue + notes) at a QR code you scan from the settings panel. All zero-config, zero-dependency, off by default, LAN-only.

    The web remote phone page: standing-by cue, giant GO, prev/next, STOP ALL

  • Stage display — a performer-facing confidence monitor styled like a broadcast multiview: labeled tiles, tally borders (red = a mirror is live, green = standing by), ON-AIR-style clock and show-timer tiles. Fullscreen on any spare display in Show mode (never over the operator's own screen — it floats there instead, and ⌘⎋ always exits Show mode), a floating resizable window in Rehearsal. Fully editable pane layout (drag, resize, snap on a 16:9 canvas, one-press multiview grid reset): clock, show timer, the standing-by cue huge, its notes, running cues with meters, the gesture hold-progress bar — and live program panes that mirror any number of video outputs (16:9-locked, one decode, an extra layer, attach and detach mid-playback like a video patchbay). Never a cue target. Any output group can also become its own floating resizable window in every mode — a prompter feed on the operator screen during a real show.

    Stage display multiview: clock, standing-by, live program mirror with tally, notes, running cues

  • Preflight — one click (and automatically on entering Show mode) checks the whole cue list against the rig: missing media, unassigned or display-less output groups, missing camera permission, disconnected audio devices, un-fed webcam groups, broken cues.

  • Operator UX — assignable keyboard shortcuts (stored in the show file) plus per-cue hotkeys, all suppressed while typing; undo/redo for every edit (snapshot-based, coalesced, playback-safe); Active Cues panel with live progress and per-instance transport; a show timer counting up from the moment Show mode starts; editable notes next to the GO button; drag media files (or whole decks) straight into the cue list; copy/paste/duplicate cues with reference-safe identity remapping; one-click renumber (10/20/30…); Open Recent; full-row color tags; collapsible groups; waveform/filmstrip trim editors with a marker lane; media relink/replace on any cue (file dialog or drop onto the inspector); rotating backups and playback-aware autosave. Dark show-control look with MagicLab styling.

  • Show files — versioned, diff-friendly JSON (.stagewizard); media referenced relative to the show file so shows survive folder moves; old format versions migrate automatically on open.

Building

Requires Xcode 26+. The Xcode project is generated, and builds land in ./build (ignored by git and Dropbox):

Tools/build.sh        # generate project, run all tests, build Release
Tools/package.sh      # everything above + dependency check + sign,
                      # notarize & staple (when credentials are present) + zip

Virtual webcam builds: the camera system extension needs the restricted com.apple.developer.system-extension.install entitlement, which macOS only honors with an embedded Developer ID provisioning profile (System Extension capability, from the Apple developer portal). Drop it at Support/StageWizard.provisionprofile and the build scripts embed and sign automatically; without it the app builds and runs fine, minus webcam activation.

The packaged app is self-contained (system frameworks only). Release zips on the releases page are Developer ID signed and notarized — download, unzip, double-click. Without signing credentials, package.sh falls back to an ad-hoc build (right-click → Open the first time).

Test media and the demo shows (Demo.stagewizard covers the core engine; FeatureTour.stagewizard walks through the v1.6 additions cue by cue — rates, marker follows, chroma key + gesture GO, wall-clock triggers, with the notes column narrating each one):

swift Tools/make-test-media.swift TestMedia
open Demo.stagewizard
open FeatureTour.stagewizard

Architecture

ShowModel/       pure Codable value types (the .stagewizard format)
ShowRuntime/     @MainActor cue engine: instance state machine, transport,
                 follows, ActiveCuesRegistry, MediaPlayback protocol
AudioEngineKit/  one AVAudioEngine per output device, pooled player nodes,
                 sample-accurate segment scheduling, HAL hot-plug
VideoEngineKit/  AVQueuePlayer arm pipeline (load→layer→ready→seek→preroll),
                 output windows keyed by target (display or preview),
                 camera capture, still/slide rendering, display fingerprint
                 matching, geometry
FadeKit/         one 100 Hz fade clock (≤1 dB steps, lands on exactly 0.0
                 before any stop); video opacity via render-server animations
ShortcutKit/     local event-monitor dispatcher + shortcut recorder
StageWizardApp/  SwiftUI UI, document controller, engine bridge

Cue definitions (Codable, in the show file) are strictly separated from playback instances (runtime state). All orchestration is MainActor; every AVFoundation, CoreMIDI, and Network.framework callback hops isolation immediately; the only off-main mutations are documented-thread-safe volume setters driven by the fade clock. Remote triggers (MIDI, OSC, web remote, gesture) all route through a single trigger bus into the same transport the keyboard uses. 686 unit and integration tests cover the model, sequencing semantics, the engines, the OSC/HTTP parsers, deck conversion, and full-stack playback.

Prior art & thanks

StageWizard's cue model and engine design draw on lessons from the open-source show-control community:

  • Linux Show Player — the reference for separating stored properties, operator actions, and runtime states, and for its generic fader design.
  • QPlayer — clean flat-list-plus-parent cue trees and a minimal, load-bearing follow model.
  • LivePlay — instance-vs-definition separation and the "one fade-out path for every stop" contract.
  • ShowQ and Cuems — cue-engine state machines and armed/loaded staging.
  • CasparCG — group scheduling via per-child offsets.

License

MIT — see LICENSE.

About

Native macOS show control for live performance — cue-based audio, video, and camera playback

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages