You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: AGENTS.md
+2Lines changed: 2 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -286,7 +286,9 @@ Repo-specific design rules:
286
286
- Keep shared package versions in `Directory.Packages.props`.
287
287
- Keep the pinned SDK version in `global.json`.
288
288
- Treat `new-design/index.html`, `new-design/tokens.css`, `new-design/components.css`, `new-design/styles.css`, and `new-design/app.js` as the exact design reference.
289
+
- Treat every file under `new-design/` as a static design/prototype reference only. Production UI must be implemented as Blazor components in `src/PrompterLive.Shared`; do not ship raw `new-design` HTML as runtime UI.
289
290
- Do not re-invent the UI when the answer should be “port the markup and classes from `new-design`”.
291
+
- For parity tasks, port the full routed screen from its matching `new-design/*.html` reference, not just isolated high-signal blocks. Settings, Editor, Learn, Teleprompter, and Go Live must match the reference screen in layout and intended interaction while staying Blazor/C# owned.
290
292
- Do not introduce a server host for the app runtime.
291
293
- Preserve stable `data-testid` selectors on core flows because the Playwright suite depends on them.
292
294
- Keep UI routes in shared route constants and keep `data-testid` names in shared UI contract constants.
Copy file name to clipboardExpand all lines: docs/Architecture.md
+1-1Lines changed: 1 addition & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -64,7 +64,7 @@ flowchart LR
64
64
## Vertical Slice Layout
65
65
66
66
-`src/PrompterLive.Shared` keeps routed UI in feature slices: `AppShell`, `Diagnostics`, `Editor`, `Library`, `Learn`, `Teleprompter`, `GoLive`, `Settings`, and `Media`.
67
-
-`src/PrompterLive.Core` keeps host-neutral behavior in matching domain slices: `Tps`, `Editor`, `Workspace`, `Library`, `Rsvp`, `Media`, `Streaming`, `Localization`, and `Samples`.
67
+
-`src/PrompterLive.Core` keeps host-neutral behavior in matching domain slices: `Tps`, `Editor`, `Workspace`, `Library`, `Rsvp`, `Media`, `Streaming`, and `Localization`.
68
68
-`tests/PrompterLive.Core.Tests`, `tests/PrompterLive.App.Tests`, and `tests/PrompterLive.App.UITests` mirror those feature slices and reserve `Support` or `Infrastructure` for shared harness code.
Copy file name to clipboardExpand all lines: docs/Features/GoLiveRuntime.md
+93-1Lines changed: 93 additions & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -12,6 +12,22 @@ The current page layout is a production-style studio surface:
12
12
- right rail for live preview plus stream, audio, and network telemetry
13
13
- lower routing decks for local outputs and cloud destinations
14
14
15
+
The runtime now owns real browser media outputs for the composed program scene and the current audio bus:
16
+
17
+
-`Go Live` builds one browser-side program stream from the scene camera cards by drawing the selected primary camera full-frame and then layering additional included cameras as positioned overlays on a canvas
18
+
- the scene `AudioBus` is mixed into one program audio track through `AudioContext`, delay, and gain nodes before the final program stream is published or recorded
19
+
- OBS browser output stays browser-only and exposes the composed program audio inside an OBS Browser Source environment
20
+
- LiveKit publishing uses the vendored browser SDK and publishes real composed `MediaStreamTrack` objects for video and audio
21
+
- local recording uses the browser `MediaRecorder` API against the same composed program stream and prefers `showSaveFilePicker()` for real local file writing when the browser allows it, with download fallback otherwise
22
+
- recording export profiles are honest browser probes only: the runtime checks `MediaRecorder.isTypeSupported()` and `MediaCapabilities.encodingInfo()` before choosing the resolved MIME type and falls back to a supported browser codec/container when the requested profile is unavailable
23
+
- stream start, stop, recording start, recording stop, and source switching update the active browser output session instead of only flipping local UI state
24
+
- the session timer and right-rail `Status` / `Runtime` cards are driven from live session/runtime state, not hardcoded demo telemetry
GoLive->>Runtime: Build request from scene snapshot + audio bus + recording export prefs
71
+
Runtime->>Browser: Start MediaRecorder on the composed program session
72
+
User->>GoLive: Switch source
73
+
GoLive->>Runtime: Update scene-backed program request
74
+
Browser->>Browser: Recompose the same program stream with the new primary source
46
75
User->>Reader: Open teleprompter
47
76
Reader->>Scene: Reuse same scene cameras under text
48
77
```
@@ -61,10 +90,18 @@ flowchart LR
61
90
Studio["StreamStudioSettings"]
62
91
Routing["GoLiveDestinationRouting"]
63
92
Scene["MediaSceneState"]
93
+
AudioBus["AudioBusState"]
64
94
CameraInterop["CameraPreviewInterop"]
95
+
Runtime["GoLiveOutputRuntimeService"]
96
+
RuntimeInterop["GoLiveOutputInterop"]
97
+
OutputSupport["go-live-output-support.js"]
98
+
BrowserRuntime["go-live-output.js"]
99
+
Composer["go-live-media-compositor.js"]
65
100
LiveKit["LiveKitOutputProvider"]
66
101
Vdo["VdoNinjaOutputProvider"]
67
102
Rtmp["RtmpStreamingOutputProvider"]
103
+
LiveKitSdk["vendored livekit-client"]
104
+
ObsBrowser["OBS Browser Source"]
68
105
69
106
Page --> SessionBar
70
107
Page --> PreviewRail
@@ -75,12 +112,53 @@ flowchart LR
75
112
Page --> Studio
76
113
Page --> Routing
77
114
Page --> Scene
115
+
Page --> AudioBus
116
+
Page --> Runtime
78
117
Preview --> CameraInterop
118
+
Runtime --> RuntimeInterop
119
+
RuntimeInterop --> OutputSupport
120
+
RuntimeInterop --> BrowserRuntime
121
+
BrowserRuntime --> Composer
122
+
BrowserRuntime --> LiveKitSdk
123
+
BrowserRuntime --> ObsBrowser
79
124
Page --> LiveKit
80
125
Page --> Vdo
81
126
Page --> Rtmp
82
127
```
83
128
129
+
## Runtime Pipeline
130
+
131
+
```mermaid
132
+
flowchart LR
133
+
Scene["Scene cameras + transforms"]
134
+
Audio["Audio bus inputs + gains + delay"]
135
+
Factory["GoLiveOutputRequestFactory"]
136
+
Runtime["GoLiveOutputRuntimeService"]
137
+
Support["go-live-output-support.js"]
138
+
Composer["go-live-media-compositor.js"]
139
+
Canvas["canvas.captureStream()"]
140
+
Mix["AudioContext + MediaStreamDestination"]
141
+
Program["Composed MediaStream"]
142
+
Recorder["MediaRecorder"]
143
+
Save["File picker or download fallback"]
144
+
LiveKit["LiveKit publishTrack(...)"]
145
+
Obs["OBS browser audio bridge"]
146
+
147
+
Scene --> Factory
148
+
Audio --> Factory
149
+
Factory --> Runtime
150
+
Runtime --> Support
151
+
Runtime --> Composer
152
+
Composer --> Canvas
153
+
Composer --> Mix
154
+
Canvas --> Program
155
+
Mix --> Program
156
+
Program --> Recorder
157
+
Recorder --> Save
158
+
Program --> LiveKit
159
+
Program --> Obs
160
+
```
161
+
84
162
## Rules
85
163
86
164
-`Settings` must not own live destination routing anymore.
@@ -93,6 +171,20 @@ flowchart LR
93
171
- any shared `Go Live` localized copy must come from `PrompterLive.Shared.Localization.UiTextCatalog`, so supported browser cultures localize the studio surface without feature-local string copies.
94
172
- each live destination must persist its own selected scene cameras, independent of the shared program feed source list
95
173
- legacy streaming settings must normalize to the current included program cameras so existing browser storage keeps working
174
+
-`VirtualCamera` mode normalizes to OBS armed by default, so browser sessions keep the legacy desktop-capture workflow unless the user explicitly turns OBS off
96
175
- Camera source inclusion is persisted through `MediaSceneState`.
97
176
- Destination credentials and endpoints are persisted only in browser storage for this standalone runtime.
177
+
- LiveKit browser publishing must use the vendored SDK shipped in the repo, not a CDN copy.
178
+
- OBS browser integration must stay a thin browser bridge; no server relay or backend media graph is introduced.
179
+
- local recording must stay browser-local and use the same active program media session as OBS / LiveKit so record and source switching stay in sync
180
+
- local recording must prefer real local file writing through the File System Access API when the browser exposes it, but must fall back to browser download instead of pretending save-to-disk is universally available
181
+
- recording codec/container export must never advertise unsupported browser encoders as if they are guaranteed; the runtime must probe support and choose a real fallback profile
182
+
- right-rail telemetry must never show fake packet-loss, jitter, ping, or upload metrics when the browser runtime does not actually own those measurements
183
+
- remote room UI must not render fake guest personas; when no real remote guest transport exists, it may only show honest local-host state and persisted room identity
98
184
- Browser acceptance verifies `Go Live` preview and source switching against deterministic synthetic cameras, not only against static DOM state.
185
+
- Browser acceptance for LiveKit and OBS verifies real `getUserMedia` audio/video requests and runtime session state, not only button labels.
186
+
187
+
## Exception Notes
188
+
189
+
-`src/PrompterLive.Shared/wwwroot/media/go-live-media-compositor.js` temporarily exceeds the root `file_max_loc` limit because canvas compositing, shared device capture, and audio-bus graph ownership are tightly coupled around browser-only APIs. Scope: only the browser program graph. Removal plan: split video composition and audio graph helpers once the pipeline stabilizes and the recording/export profile surface is no longer moving.
190
+
-`src/PrompterLive.Shared/wwwroot/media/go-live-output-support.js` temporarily exceeds the root `file_max_loc` limit because request normalization, codec probing, and local-save recording helpers must currently stay aligned with the browser runtime contract in one place. Scope: request normalization and browser recording/export helpers. Removal plan: split request normalization from recording/export helpers after the profile mapping rules settle.
0 commit comments