OBS Plugin Dock
Summary
The OBS plugin dock is the primary user-facing interface for GoLiveBro (formerly Telemy), providing real-time stream telemetry inside an OBS Studio dock panel. The dock is built in React JSX with inline styles, bundled via esbuild, and rendered inside OBS’s embedded Chromium (CEF). It uses CSS custom properties for theming, with palettes extracted from the active OBS Qt theme at runtime via C++ code. The same dock components power the landing page interactive demo by falling back to useSimulatedState() when no CEF bridge is present.
Three significant dock UX improvements were designed and implemented in March 2026: sparkline output bars replacing solid bitrate fills, density/font-scale separation allowing independent control of text zoom and layout spacing, and a comprehensive UX/theme fixes pass covering 12 tasks across theme palettes, font size minimums, jargon labels, tooltips, section collapse defaults, sign-out confirmation, secret field auto-relock, and upgrade banner styling. A future video stabilization feature was explored and documented on 2026-03-18 but deferred to Phase 3+.
The dock source lives in the obs-plugin/dock/ directory with key files including aegis-dock.jsx (main component), ui-components.jsx, encoder-components.jsx, and connection-components.jsx. The C++ side handles theme extraction (dock_theme.h/cpp), metrics collection (metrics_collector.cpp), and bridge communication (obs_plugin_entry.cpp). Two separate esbuild bundles are produced: one for OBS (aegis-dock-app.js, ~278KB) and one for the webpage demo (telemy-dock.js/dock-demo-bundle.js).
Timeline
- 2026-03-18: Video stabilization feature documented as future exploration. Deferred to Phase 3+.
- 2026-03-20: Density/font-scale separation plan created. 7 tasks: C++ changes to emit densityLevel field, JS changes to compute densityScale multiplier, density-aware spacing via —dp CSS variable across all components.
- 2026-03-23: Sparkline output bars design approved. Replaces solid fill bitrate bars with smooth bezier canvas sparklines, color-coded relative to each output’s target bitrate (green >=85%, yellow 70-85%, red <70%).
- 2026-03-23: Dock UX/theme fixes plan created. 12 tasks covering theme palette corrections, font size floor of 10px, jargon replacement (BYOR/MGD to Self-hosted/Managed), tooltips, section collapse defaults, sign-out confirmation, secret auto-relock, and banner styling.
Current State
The dock renders real-time stream health data across several collapsible sections: Encoders & Uploads (with sparkline bitrate charts), Connections (relay status cards), Failover Engine, Output Config, and Event Log. The last three sections default to collapsed. The dock supports 7 OBS themes: Yami, Acri, Grey, Rachni, Classic, Light, and a default fallback.
Theme integration works via a C++ pipeline: dock_theme.cpp reads OBS Qt palette slots and user.ini settings (FontScale, Density), converts them to JSON fields (bg, surface, panel, text, textMuted, accent, border, scrollbar, fontFamily, fontSizePx, densityLevel), and passes them to the JS dock via the CEF bridge. The JS side computes a fontScale (zoom multiplier) and densityScale (spacing multiplier, 0.5-1.5 range, mapped as 1.0 + densityLevel * 0.1), exposes densityScale as —dp CSS variable, and all structural spacing uses calc(var(—dp, 1) * Xpx).
All text in the dock renders at minimum 10px font size. The StatPill, SecretField, ConnectionTypeBadge, EngineStateChips, footer, SIM badge, and provision progress text were all raised from 6-9px to 10px minimum. Jargon labels “BYOR” and “MGD” were replaced with “Self-hosted” and “Managed”.
Sparkline output bars use canvas rendering with quadraticCurveTo for smooth bezier curves, semi-transparent fill below the line, and a faint reference line at target bitrate. Target bitrate is sourced from obs_encoder_get_settings() (target_bitrate_kbps field added to C++ metrics), with a rolling average fallback. Circular buffer stores up to 60 minutes of history sampled every 500ms (live) or 3s (simulated), downsampled to 150-200 points for rendering. Time range selector in the section header offers 5m/15m/30m/60m windows, default 15m, persisted to localStorage.
The UpgradeBanner uses subdued OBS-palette colors (theme surface background, accent left border) instead of the original purple gradient. The GraceWarningBanner uses amber warning styling (#d29922) instead of solid red. Sign-out has a two-step confirmation (shows “Sign out? Yes/No” inline prompt). SecretField auto-relocks after 30 seconds on reveal, or 5 seconds after blur.
Tooltips were added to: SIM badge (“Simulation mode, no OBS bridge connected”), IPC status dot (“Plugin to control plane connection status”), and sparkline canvas (“Bitrate sparkline: green = >=85% of target, yellow = 70-85%, red = <70%”).
Key Decisions
- 2026-03-18: Video stabilization will be local-only, never cloud-hosted. Cloud processing rejected due to 55-135ms latency per frame, 6-15 MB/s bandwidth overhead, and $0.30-1.20/hr GPU instance costs. Relay-side processing also rejected as it would require GPU-equipped instances breaking the ARM64 EC2 architecture.
- 2026-03-18: Stabilization will be built fresh in Rust with wgpu compute shaders, not forked from LiveVisionKit (LVK). LVK’s OpenCV + OpenCL C++ codebase introduces driver compatibility issues and different design conventions. LVK used as algorithm reference only.
- 2026-03-20: Density and font scale are decoupled. fontSizePx reflects only font point size converted to pixels. densityLevel is the raw OBS Density= integer from user.ini. This allows users to independently control text zoom and layout spacing. Previously, density was folded into fontSizePx.
- 2026-03-20: Density scale uses a linear mapping: 1.0 + densityLevel * 0.1, clamped to [0.5, 1.5]. OBS Classic (density -3) maps to 0.70x spacing, Normal (0) to 1.0x, Comfortable (+2) to 1.2x.
- 2026-03-23: Sparklines self-calibrate to each output’s target bitrate. A 40 Mbps stream and a 6 Mbps stream both show green when near their respective targets. No absolute thresholds.
- 2026-03-23: All theme palettes standardized to textMuted: #999999 (matching OBS native muted grey). Grey theme accent changed from invisible 4D4D4D to blue 2D7AED. Acri surface darkened to #181819 with blue accent. Rachni scrollbar changed from pink 914C67 to neutral grey 5A5F66.
- 2026-03-23: Minimum font size floor set at 10px across all dock components. Nothing renders below 10px.
- 2026-03-23: Failover Engine, Output Config, and Event Log sections default to collapsed (defaultOpen={false}).
Gotchas & Known Issues
- Dock bundles still reference telemyapp paths. Blocked until OBS plugin repo is migrated to GoLiveBro.
- CEF caches dock assets. If the dock shows a black screen after DLL update, force-close OBS and reopen.
- The webpage dock demo bundle requires a separate entry point (dock-demo-entry.jsx) that wires useSimulatedState() directly since window.telemyDockNative does not exist in the browser context.
- The dock’s internal CSS is injected by getDockCss() inside its own component tree. The webpage landing page CSS only controls the dock frame container, not dock internals.
- Sign-out confirmation button font sizes (8-9px in compact/normal) are below the 10px minimum established in Task 2. These were set intentionally for the tight inline Yes/No prompt.
- OBS theme Classic already has textMuted at #868686, close to #999999. It was left as-is during the theme standardization pass.
- Per-link relay sparklines are explicitly out of scope for the sparkline implementation. Existing bars are kept for relay connections.
- The C++ DLL must be rebuilt whenever metrics_collector.cpp changes (e.g., adding target_bitrate_kbps). The cmake build directory is at obs-plugin/build-obs-cef/.
Open Questions
- Video stabilization: Which motion estimation algorithm (optical flow, phase correlation, block matching) gives the best quality/performance tradeoff in wgpu compute shaders?
- Video stabilization: Can audio delay compensation from frame buffering be automated in the Rust core, or will users need manual adjustment?
- Video stabilization: Should the stabilizer register as an OBS filter (per-source) or run entirely within telemy-core before frames reach OBS?
- Video stabilization: Can gyroscope metadata from phones be used for hybrid stabilization when available via SRT feed?
- Stabilization hardware gating: Minimum RTX 2000 / RX 5000 series, 1GB free VRAM, 75% compute utilization ceiling proposed but not validated with benchmarks.
- Hover tooltips on sparklines and zoom/pan interactions are out of scope. Will these be revisited?
- When will the dock bundle paths be migrated from telemyapp to GoLiveBro references?