Skip to content
AI systems & agentsPrototype2026

Evolve Prism

A self-hosted live production platform replacing a roughly $1,000/year subscription service, with browser-based guest ingest, branded live compositing, and multistream RTMP…

43
unit tests passing, app layer for phases 1-3
2
consecutive zero-intervention rehearsal shows required before the existing subscription tool can be cancelled
ArchitectureGated system — no screenshot
Interface
  • Next.js (App Router)
  • React 19
  • TypeScript
  • Google Workspace SSO (arctic/PKCE)
Data
  • SQLite (better-sqlite3)
  • Redis
Operations
  • Docker
Supporting
  • LiveKit SFU
  • LiveKit Egress

Evolve Prism holds live data, so this shows the verified technology stack by layer rather than a screenshot. Hosts, ports and topology are deliberately absent.

Problem

Live-streaming a branded show typically means paying for a hosted service (roughly $1,000/year) to get browser-based guest ingest, on-air compositing with lower thirds and banners, and multistream output to platforms like YouTube. Self-hosting that stack is nontrivial: it needs a real-time media server, a host control surface that can change the on-air look instantly without dropping guests, and a recording/export path, all running within a 16 GB home machine's resource budget rather than cloud infrastructure. The owner runs more than one branded show, so a second, quieter requirement sat underneath the obvious one: whatever replaced the subscription tool had to support different on-air looks per property without becoming a second product to maintain per brand.

What was built

Prism is a self-hosted replacement for that class of tool. Guests join a show from a browser link with no account required, using short-lived, revocable invite tokens. A host console lets the operator switch scenes, banners, lower-thirds, and tickers live, with the on-air layout updating instantly for viewers. Layout templates render the branded composite that gets recorded or pushed out as RTMP for platforms like YouTube. The first layout template set shipped neutral (grid, spotlight, side-by-side, and screen-share-focus scenes), with per-brand skins for other properties in the owner's portfolio layered on as the same templates restyled, not separate builds. The system is explicitly scoped to production only: it does not do scheduling or publishing, clip generation, chat aggregation, virtual backgrounds, or cloud storage — those are deliberately left to other tools in the owner's stack. It is single-tenant, built for one operator's internal use, not a multi-tenant product.

Technical approach

The real-time media path runs on a self-hosted LiveKit SFU with room state in Redis; both are lightweight always-on containers under 100 MiB combined. LiveKit Egress, the component that actually renders a layout URL in headless Chrome and encodes/writes the output, is the heavy container and is deliberately started only for the duration of a show window and torn down afterward, to protect the memory budget on a 16 GB host machine that also runs everything else. The Next.js app hosts four distinct surfaces on one process: the guest green room/live room, the host console, show CRUD admin, and the layout template pages that egress itself loads headlessly. State lives in SQLite via better-sqlite3 rather than Postgres, a deliberate choice to minimize memory footprint on a single-tenant system with no row-level security needed. The host console pushes on-air state two ways simultaneously: persisted to SQLite so a restarted egress process picks up the current look on load, and broadcast live over a LiveKit data channel so connected viewers update instantly without a page reload. Authentication splits by role: hosts go through Google Workspace SSO with PKCE and an allowlist that denies by default, while guests exchange short-TTL LiveKit JWTs from hashed, revocable invite tokens, with route middleware gating everything except the guest-join flow, webhooks, health checks, and unauthenticated read-only layout state. Because WebRTC media cannot ride the tunnel used for the app itself, the network architecture deliberately splits app/signaling traffic (routed one way) from media traffic (routed via direct router port forwards) rather than trying to force everything through a single tunnel.

Creative approach

Craft

The architecture treats the on-air composite as a normal web page rendered by a headless browser (egress renders a Prism layout URL directly), which means branding, scene layout, and visual skins are implemented once as ordinary React templates rather than as a separate compositing engine's proprietary scene format. Scene state changes propagate over both a persisted store and a live data-channel broadcast simultaneously, so the visible result updates instantly for viewers even though the underlying egress renderer is only reading state on a slower cycle. The first template set was deliberately built neutral before any brand skin was applied — grid, spotlight, side-by-side, and screen-share-focus scenes exist as the shared layout vocabulary every show draws from, so adding a new branded look for another property in the owner's portfolio is a skin applied to an existing template rather than a new layout built from nothing. The integration test that proves this layer works checks the thing that actually matters for a live show: two video tiles rendering correctly and a recording-start signal logging, against a real two-participant room, not just that the component tree mounts.

Reframe

The project's non-goals list is as important as its feature list: no multi-tenancy, no scheduling, no clip generation, no chat aggregation, no virtual backgrounds, no cloud storage of recordings. Each of those is explicitly owned by a different tool in the operator's existing stack. Scoping Prism to only live production, and refusing to let it grow into an all-in-one platform, is what made a single-operator, resource-constrained build of a normally cloud-scale product tractable. The memory budget is itself a design constraint the project treats as load-bearing rather than incidental: the SFU and Redis stay small and always-on, while the one genuinely heavy container — egress, the piece that actually renders and encodes video — exists only for the duration of a show window, which means the always-on cost of running Prism at all is close to zero and the expensive part only exists when a show is actually happening.

Process and what failed

The app layer across three build phases (43 unit tests, a proven two-browser room integration test, live console control) reached a locally working state, but a real environmental blocker surfaced during the egress/recording phase: LiveKit Egress dispatches successfully and its headless Chrome runs cleanly inside the container, yet gstreamer never writes an output file. The investigation methodically ruled out reachability, Chrome availability, out-of-memory kills, and an RTMP port mismatch that was found and fixed along the way, then bisected the failure to egress's own built-in template (not Prism's custom layout code) to confirm the bug isn't in this project's code. The blocker was left open and documented with full repro steps and leading hypotheses rather than worked around by weakening the test that catches it, and a separate network-layer exit test remains blocked on physical router port-forward configuration.

Outcome

The application layer is built and locally proven through phase 3 — control plane, layout templates, host console, and auth all working against a live two-participant room — but two hard gates remain open before the existing paid tool can be retired: a network validation test blocked on router configuration, and an environmental egress/recording bug that prevents composite video capture from writing a file. The project's own launch gate requires two consecutive full-length rehearsal shows with zero manual intervention before cancellation of the incumbent service, and that gate has not been reached.