Debugging & Logging
MasterSelects includes a Logger service plus several playback and health monitors that are surfaced both in the browser console and through the AI bridge.
Overview
Section titled “Overview”The Logger service (src/services/logger.ts) provides:
| Feature | Description |
|---|---|
| Log levels | DEBUG, INFO, WARN, ERROR with level filtering |
| Module filtering | Enable debug logs for specific modules only |
| In-memory buffer | 500 entries stored for inspection |
| Global access | window.Logger in the browser console |
| AI-agent support | Structured summaries for tool inspection |
| Timestamps | Timestamp prefixes enabled by default |
| Stack traces | Captured when an error object is logged |
| Log sync | Development log sync through window.LogSync |
Default log level: WARN. Errors are always shown and always buffered. WARN and ERROR entries are buffered even when they are not displayed.
Console Commands
Section titled “Console Commands”All commands are available via window.Logger or just Logger in the browser console.
Enable / Disable Debug Logs
Section titled “Enable / Disable Debug Logs”Logger.enable('WebGPU,FFmpeg,Export')Logger.enable('*')Logger.disable()Set Log Level
Section titled “Set Log Level”Logger.setLevel('DEBUG')Logger.setLevel('INFO')Logger.setLevel('WARN')Logger.setLevel('ERROR')Inspect Logs
Section titled “Inspect Logs”Logger.getBuffer()Logger.getBuffer('ERROR')Logger.getBuffer('WARN')Logger.search('device')Logger.errors()Logger.dump(50)Logger.summary()Logger.export()Status & Configuration
Section titled “Status & Configuration”Logger.status()Logger.modules()Logger.clear()Logger.setTimestamps(false)Log Sync
Section titled “Log Sync”In development mode the browser automatically syncs redacted log summaries to the dev server every 2 seconds.
window.LogSync exposes:
LogSync.status() // 'running' or 'stopped'LogSync.stop()LogSync.start()LogSync.flush()If the dev bridge token is not present, the browser falls back to sendBeacon for the local /api/logs endpoint. The payload is still redacted before it leaves the page.
AI Tool Debug Surface
Section titled “AI Tool Debug Surface”In development, the HMR-backed browser client registers the dev HTTP bridge. It dispatches through the shared AI-tool registry with the devBridge caller context:
POST /api/ai-toolsIt supports the _list and _status meta-commands, plus targeted execution against a connected browser tab through the HMR bridge.
For bridge preflight, GET /api/ai-tools reports connected browser tabs without auth, while GET /api/ai-tools/auth-check validates the bearer token without dispatching a browser tool. This catches stale .ai-bridge-token files when multiple dev servers are running.
$token = Get-Content -Path .ai-bridge-token -Raw$headers = @{ Authorization = "Bearer $token"; 'Content-Type' = 'application/json' }Invoke-RestMethod -Uri 'http://localhost:5173/api/ai-tools/auth-check' -Method Get -Headers $headersThe worker-first platform-evidence helper wraps these checks:
npm run worker-first:platform:doctor -- --latest-per-platformnpm run worker-first:platform:status -- --latest-per-platformnpm run worker-first:platform:macos-runbookdoctor prints matrix status, platform proof summaries, bridge tab status,
fresh/stale tab counts, and Bridge auth: ok or the token error. collect
first waits for a fresh dev-bridge target tab to register
(lastSeenAgoMs <= 10000 and not unresponsive), then waits --wait-ms again
after target-tab selection before dispatching the proof tool; the default is
5000ms. If doctor reports Fresh tabs: 0/..., foreground or reload the target
browser tab before collecting. Collection reports include readiness metadata
(targetPollCount, targetWaitedMs, selected tab before/after settle, and
actual settle wait) so a package can be audited for the required post-load wait.
status, verify, and doctor read matching companion *.report.json files
when present and print a non-blocking readiness audit (missing report,
legacy report, or invalid). Failed collect payloads are written as
*.failed.json, never *.package.json, so incomplete runs cannot displace the
latest valid per-platform package. macos-runbook prints the exact real-Mac
Safari/Firefox collection commands for the remaining platform packages; it is
not synthetic platform evidence.
Export Debug Via Bridge
Section titled “Export Debug Via Bridge”Use debugExport when the UI export fails or appears stuck and the dev server plus browser tab are already running. It is a dev-bridge-only handler, not a public chat tool.
$token = Get-Content -Path .ai-bridge-token -Raw$headers = @{ Authorization = "Bearer $token"; 'Content-Type' = 'application/json' }
$body = @{ tool = 'debugExport' args = @{ startTime = 0 durationSeconds = 1.0 width = 640 height = 360 fps = 15 includeAudio = $false exportMode = 'fast' download = $false maxRuntimeMs = 25000 }} | ConvertTo-Json -Depth 6
Invoke-RestMethod -Uri 'http://localhost:5173/api/ai-tools' -Method Post -Headers $headers -Body $bodyFor the current timeline and export defaults:
$body = @{ tool = 'debugExport'; args = @{ includeAudio = $true; exportMode = 'fast'; download = $false } } | ConvertTo-Json -Depth 6Invoke-RestMethod -Uri 'http://localhost:5173/api/ai-tools' -Method Post -Headers $headers -Body $bodyThe result includes blob size/type, progress samples, settings, engine state before/after export, and recent export/GPU warnings or errors. maxRuntimeMs cancels the export cleanly before the dev-bridge request appears hung. A blob with size > 0 proves the browser FrameExporter path can render and encode. If the UI still fails afterward, inspect ExportPanel, preset state, progress state, and download handling.
If logs show WebGPU device lost during export and getStats reports renderLoop.isRunning=false, renderDispatcher=null, or targetCanvasCount=0, the browser engine is in a stale device state. Use reloadApp or hard-reload the tab before retesting. Windows powerPreference warnings and NativeHelper WebSocket failures are not automatically export blockers.
Full-App Screenshots And UI Probes
Section titled “Full-App Screenshots And UI Probes”For a visual UI failure, select the intended browser session explicitly and call captureAppScreenshot on the devBridge surface. The default captures the visible app viewport; fullPage: true captures the complete scrolling document. Output scaling is reduced automatically when needed to stay within bridge-safe image dimensions. The result is returned as MCP image content and its base64 payload is omitted from durable traces.
Use clickAppControl to reproduce a visible button, link, disclosure, or other specific control without switching to a separate browser automation stack. Use probeSameOriginRequest to inspect a failing local /api/ call from the authenticated tab; it returns selected headers and a bounded redacted body instead of exposing cookies or unrestricted URLs. All three tools are development-only and must be called with an explicit target session when multiple tabs are present.
Monitoring Surfaces
Section titled “Monitoring Surfaces”The app exposes several runtime monitors that feed the AI debug tools and the console:
| Surface | What it exposes |
|---|---|
window.__WC_PIPELINE__ | WebCodecs ring-buffer events, stalls, seeks, timeline views, and aggregate stats |
window.__VF_PIPELINE__ | HTMLVideo / VideoFrame ring-buffer events, audio timelines, stall context, and aggregate stats |
window.__PLAYBACK_HEALTH__ | Health snapshot, anomaly list, active video states, and recovery helpers |
The playback-related AI tools read from the same sources:
getStatsgetStatsHistorygetAudioDiagnosticsgetLogsgetRuntimeDiagnosticsclearRuntimeDiagnosticsgetPlaybackTracepurgePlaybackPathsamplePlaybackFramePacing
Those tools surface:
- Engine state and readiness
- Timing breakdowns
- Decoder and drop information
- Playback health and anomaly data
- Cache and slot-deck stats
- Render loop and render dispatcher state
- WebCodecs / VF pipeline event windows
- Audio media element ready/buffer state, Web Audio context latency, routing graph state, and recent audio drift/correction events
- Captured console output, window errors, unhandled rejections, WebGPU uncaptured errors, and device-lost events
purgePlaybackPath resets the live playback path at the current playhead without a page reload. It clears VideoSync warmups/seeks, retargets active HTMLVideo/WebCodecs providers, resets GPU-ready state, and can resume playback automatically. The health monitor can invoke the same path when vf_preview_frame telemetry shows the playhead target moving while the preview frame remains frozen.
When playback start has to wait for active HTML video readiness, TimelineState.playbackWarmup is set until the readiness gate finishes or is canceled. A settled current frame (HAVE_CURRENT_DATA, not seeking) starts immediately after a hop or scrub. A last presented frame within 350 ms of the exact mapped source target is also reusable, so playback can start while the decoder catches up behind the active layer’s frame hold. The gate and its small Preparing playback overlay remain for genuinely cold targets where no reusable frame exists; background VideoSync warmups during normal playback do not look like blocking loading states.
HTML playback stop keeps a decoded frame within 50 ms of the playhead and aligns the playhead to that presented frame instead of issuing another precision seek. Larger lag still settles exactly; the tolerance prevents rapid play/pause cycles from creating a seek queue that makes later starts cold.
getAudioDiagnostics is the focused bridge tool for audio crackle/dropout debugging. Capture it during audible playback to inspect mediaSummary, per-element buffered.bufferedAheadSeconds, routing.context.baseLatencyMs, status.drift, and events.correctionMs.
getStatsHistory is capped to 1-30 samples, getAudioDiagnostics caps the inspected event window and returned event count, getLogs caps the returned buffer to 1-500 entries, getRuntimeDiagnostics caps returned entries to 1-1000, and getPlaybackTrace caps the inspected time window and event count so the bridge stays responsive.
getRuntimeDiagnostics reads the browser runtime-diagnostics buffer. Use clearRuntimeDiagnostics before a reproducible dev-bridge run; the buffer records console calls, window errors, unhandled rejections, and WebGPU errors/device-loss events.
Usage in Code
Section titled “Usage in Code”import { Logger } from '@/services/logger';
const log = Logger.create('MyModule');
log.debug('Verbose debugging info', { data });log.info('Important event');log.warn('Warning message', data);log.error('Error occurred', error);Timing Helper
Section titled “Timing Helper”const log = Logger.create('Export');const done = log.time('Encoding video');// ...done();Grouped Logs
Section titled “Grouped Logs”const log = Logger.create('Compositor');
log.group('Rendering frame 42', () => { log.debug('Collecting layers'); log.debug('Applying effects'); log.debug('Compositing');});Module Naming Convention
Section titled “Module Naming Convention”Modules are named after their file or class:
| File | Module Name |
|---|---|
WebGPUEngine.ts | WebGPUEngine |
FFmpegBridge.ts | FFmpegBridge |
AudioEncoder.ts | AudioEncoder |
ProjectCoreService.ts | ProjectCore |
Timeline.tsx | Timeline |
Toolbar.tsx | Toolbar |
PerformanceMonitor.ts | PerformanceMonitor |
useGlobalHistory.ts | History |
Common Module Groups
Section titled “Common Module Groups”Logger.enable('WebGPU,Compositor,RenderLoop,TextureManager')Logger.enable('Export,FrameExporter,VideoEncoder,AudioEncoder,FFmpeg')Logger.enable('Audio,AudioMixer,AudioEncoder,TimeStretch')Logger.enable('Project,ProjectCore,FileStorage')Logger.enable('Timeline,Clip,Track,Keyframe')AI-Agent Inspection
Section titled “AI-Agent Inspection”The Logger is designed to help AI code assistants understand what is happening in the application.
Summary for AI
Section titled “Summary for AI”const summary = Logger.summary();// {// totalLogs: 234,// errorCount: 2,// warnCount: 5,// recentErrors: [...],// activeModules: ['WebGPUEngine', 'Export', 'FFmpegBridge']// }Search for Issues
Section titled “Search for Issues”Logger.search('device lost')Logger.search('encode failed')Logger.search('permission denied')Export for Analysis
Section titled “Export for Analysis”const logData = Logger.export();// Includes config, registered modules, and the buffered logsPlayback Debugging
Section titled “Playback Debugging”The most useful browser-console globals for playback issues are:
window.__WC_PIPELINE__window.__VF_PIPELINE__window.__PLAYBACK_HEALTH__
Useful log modules:
Logger.enable('WebCodecsPlayer,PlaybackHealth,LayerCollector')Logger.enable('VideoSyncManager,ParallelDecode,RenderLoop')Logger.setLevel('DEBUG')The playback monitors feed the AI bridge stats tools, so getStats and getPlaybackTrace are the canonical way to capture a reproducible snapshot when the browser console alone is not enough.
Log Entry Structure
Section titled “Log Entry Structure”Each log entry contains:
{ timestamp: string; level: 'DEBUG' | 'INFO' | 'WARN' | 'ERROR'; module: string; message: string; data?: unknown; stack?: string;}Source: src/services/logger.ts, src/services/runtimeDiagnostics.ts, src/services/playbackDebugSnapshot.ts, src/services/playbackDebugStats.ts, src/services/playbackHealthMonitor.ts, src/services/wcPipelineMonitor.ts, src/services/vfPipelineMonitor.ts, src/services/aiTools/bridge.ts, src/services/aiTools/handlers/stats.ts, tools/devBridge/vitePlugin.ts