@livepeer-frameworks/streamcrafter-wc 0.1.0 → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE.md +24 -0
- package/dist/cjs/components/fw-sc-advanced.js +555 -71
- package/dist/cjs/components/fw-sc-advanced.js.map +1 -1
- package/dist/cjs/components/fw-streamcrafter.js +176 -1
- package/dist/cjs/components/fw-streamcrafter.js.map +1 -1
- package/dist/cjs/controllers/ingest-controller-host.js +34 -1
- package/dist/cjs/controllers/ingest-controller-host.js.map +1 -1
- package/dist/esm/components/fw-sc-advanced.js +556 -72
- package/dist/esm/components/fw-sc-advanced.js.map +1 -1
- package/dist/esm/components/fw-streamcrafter.js +177 -2
- package/dist/esm/components/fw-streamcrafter.js.map +1 -1
- package/dist/esm/controllers/ingest-controller-host.js +34 -1
- package/dist/esm/controllers/ingest-controller-host.js.map +1 -1
- package/dist/fw-streamcrafter.iife.js +646 -204
- package/dist/fw-streamcrafter.iife.js.map +1 -1
- package/dist/types/components/fw-sc-advanced.d.ts +12 -2
- package/dist/types/components/fw-streamcrafter.d.ts +12 -0
- package/dist/types/controllers/ingest-controller-host.d.ts +5 -0
- package/package.json +13 -13
- package/src/components/fw-sc-advanced.ts +569 -93
- package/src/components/fw-streamcrafter.ts +178 -1
- package/src/controllers/ingest-controller-host.ts +36 -1
|
@@ -1,103 +1,484 @@
|
|
|
1
1
|
import { __decorate } from '../node_modules/.pnpm/@rollup_plugin-typescript@12.3.0_rollup@4.57.1_tslib@2.8.1_typescript@5.9.3/node_modules/tslib/tslib.es6.js';
|
|
2
|
-
import { css, LitElement,
|
|
2
|
+
import { css, LitElement, nothing, html } from 'lit';
|
|
3
3
|
import { property, state, customElement } from 'lit/decorators.js';
|
|
4
4
|
import { classMap } from 'lit/directives/class-map.js';
|
|
5
5
|
import { sharedStyles } from '../styles/shared-styles.js';
|
|
6
6
|
import { utilityStyles } from '../styles/utility-styles.js';
|
|
7
7
|
import { xIcon } from '../icons/index.js';
|
|
8
8
|
|
|
9
|
+
function formatBitrate(bps) {
|
|
10
|
+
if (bps >= 1_000_000)
|
|
11
|
+
return `${(bps / 1_000_000).toFixed(1)} Mbps`;
|
|
12
|
+
return `${(bps / 1000).toFixed(0)} kbps`;
|
|
13
|
+
}
|
|
9
14
|
let FwScAdvanced = class FwScAdvanced extends LitElement {
|
|
10
15
|
constructor() {
|
|
11
16
|
super(...arguments);
|
|
12
|
-
this.
|
|
17
|
+
this.compositorEnabled = false;
|
|
18
|
+
this.compositorRendererType = null;
|
|
19
|
+
this.compositorStats = null;
|
|
20
|
+
this.sceneCount = 0;
|
|
21
|
+
this.layerCount = 0;
|
|
22
|
+
this._activeTab = "audio";
|
|
13
23
|
}
|
|
14
24
|
render() {
|
|
15
25
|
return html `
|
|
16
26
|
<div class="panel">
|
|
17
27
|
<div class="header">
|
|
18
|
-
<
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
28
|
+
<button
|
|
29
|
+
class=${classMap({ tab: true, "tab--active": this._activeTab === "audio" })}
|
|
30
|
+
@click=${() => {
|
|
31
|
+
this._activeTab = "audio";
|
|
32
|
+
}}
|
|
33
|
+
>
|
|
34
|
+
Audio
|
|
35
|
+
</button>
|
|
36
|
+
<button
|
|
37
|
+
class=${classMap({ tab: true, "tab--active": this._activeTab === "stats" })}
|
|
38
|
+
@click=${() => {
|
|
22
39
|
this._activeTab = "stats";
|
|
23
40
|
}}
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
41
|
+
>
|
|
42
|
+
Stats
|
|
43
|
+
</button>
|
|
44
|
+
<button
|
|
45
|
+
class=${classMap({ tab: true, "tab--active": this._activeTab === "info" })}
|
|
46
|
+
@click=${() => {
|
|
30
47
|
this._activeTab = "info";
|
|
31
48
|
}}
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
49
|
+
>
|
|
50
|
+
Info
|
|
51
|
+
</button>
|
|
52
|
+
${this.compositorEnabled
|
|
53
|
+
? html `
|
|
54
|
+
<button
|
|
55
|
+
class=${classMap({
|
|
56
|
+
tab: true,
|
|
57
|
+
"tab--active": this._activeTab === "compositor",
|
|
58
|
+
})}
|
|
59
|
+
@click=${() => {
|
|
60
|
+
this._activeTab = "compositor";
|
|
61
|
+
}}
|
|
62
|
+
>
|
|
63
|
+
Comp
|
|
64
|
+
</button>
|
|
65
|
+
`
|
|
66
|
+
: nothing}
|
|
67
|
+
<div style="flex:1"></div>
|
|
36
68
|
<button
|
|
37
69
|
class="close"
|
|
38
70
|
@click=${() => this.dispatchEvent(new CustomEvent("fw-close", { bubbles: true, composed: true }))}
|
|
39
|
-
aria-label="Close panel"
|
|
71
|
+
aria-label="Close advanced panel"
|
|
40
72
|
>
|
|
41
|
-
${xIcon(
|
|
73
|
+
${xIcon(12)}
|
|
42
74
|
</button>
|
|
43
75
|
</div>
|
|
44
76
|
<div class="body">
|
|
45
|
-
${this._activeTab === "
|
|
77
|
+
${this._activeTab === "audio"
|
|
78
|
+
? this._renderAudio()
|
|
79
|
+
: this._activeTab === "stats"
|
|
80
|
+
? this._renderStats()
|
|
81
|
+
: this._activeTab === "info"
|
|
82
|
+
? this._renderInfo()
|
|
83
|
+
: this._renderCompositor()}
|
|
46
84
|
</div>
|
|
47
85
|
</div>
|
|
48
86
|
`;
|
|
49
87
|
}
|
|
88
|
+
// ---- Audio Tab ----
|
|
89
|
+
_renderAudio() {
|
|
90
|
+
const s = this.ic.s;
|
|
91
|
+
const masterVolume = this.ic.getMasterVolume();
|
|
92
|
+
const audioLevel = s.audioLevel;
|
|
93
|
+
const levelColor = audioLevel > 0.9 ? "#f7768e" : audioLevel > 0.7 ? "#e0af68" : "#9ece6a";
|
|
94
|
+
const volColor = masterVolume > 1 ? "#e0af68" : masterVolume === 1 ? "#9ece6a" : "#c0caf5";
|
|
95
|
+
return html `
|
|
96
|
+
<!-- Master Volume -->
|
|
97
|
+
<div class="section">
|
|
98
|
+
<div class="section-header">Master Volume</div>
|
|
99
|
+
<div style="display:flex;align-items:center;gap:12px">
|
|
100
|
+
<fw-sc-volume
|
|
101
|
+
.value=${masterVolume}
|
|
102
|
+
.min=${0}
|
|
103
|
+
.max=${2}
|
|
104
|
+
@fw-sc-volume-change=${(e) => this.ic.setMasterVolume(e.detail.value)}
|
|
105
|
+
></fw-sc-volume>
|
|
106
|
+
<span
|
|
107
|
+
style="font-size:14px;min-width:48px;text-align:right;color:${volColor}"
|
|
108
|
+
>
|
|
109
|
+
${Math.round(masterVolume * 100)}%
|
|
110
|
+
</span>
|
|
111
|
+
</div>
|
|
112
|
+
${masterVolume > 1
|
|
113
|
+
? html `<div style="font-size:10px;color:#e0af68;margin-top:4px">
|
|
114
|
+
+${((masterVolume - 1) * 100).toFixed(0)}% boost
|
|
115
|
+
</div>`
|
|
116
|
+
: nothing}
|
|
117
|
+
</div>
|
|
118
|
+
|
|
119
|
+
<!-- Audio Level -->
|
|
120
|
+
<div class="section">
|
|
121
|
+
<div class="section-header">Output Level</div>
|
|
122
|
+
<div class="level-bar">
|
|
123
|
+
<div
|
|
124
|
+
class="level-fill"
|
|
125
|
+
style="width:${audioLevel * 100}%;background:${levelColor}"
|
|
126
|
+
></div>
|
|
127
|
+
</div>
|
|
128
|
+
<div class="level-labels">
|
|
129
|
+
<span>-60dB</span><span>0dB</span>
|
|
130
|
+
</div>
|
|
131
|
+
</div>
|
|
132
|
+
|
|
133
|
+
<!-- Audio Mixing Status -->
|
|
134
|
+
<div class="section">
|
|
135
|
+
<div style="display:flex;justify-content:space-between;align-items:center">
|
|
136
|
+
<span class="section-header" style="margin-bottom:0">Audio Mixing</span>
|
|
137
|
+
<span
|
|
138
|
+
class="badge"
|
|
139
|
+
style="background:rgba(158,206,106,0.2);color:#9ece6a"
|
|
140
|
+
>
|
|
141
|
+
ON
|
|
142
|
+
</span>
|
|
143
|
+
</div>
|
|
144
|
+
<div style="font-size:10px;color:#565f89;margin-top:4px">
|
|
145
|
+
Compressor + Limiter active
|
|
146
|
+
</div>
|
|
147
|
+
</div>
|
|
148
|
+
|
|
149
|
+
<!-- Audio Processing -->
|
|
150
|
+
<div style="border-bottom:1px solid rgba(65,72,104,0.3)">
|
|
151
|
+
<div class="section-dark">
|
|
152
|
+
<span class="section-header" style="margin-bottom:0">Processing</span>
|
|
153
|
+
<span style="font-size:9px;color:#565f89">
|
|
154
|
+
profile: ${s.qualityProfile}
|
|
155
|
+
</span>
|
|
156
|
+
</div>
|
|
157
|
+
${this._renderToggle("Echo Cancellation", true)}
|
|
158
|
+
${this._renderToggle("Noise Suppression", true)}
|
|
159
|
+
${this._renderToggle("Auto Gain Control", true)}
|
|
160
|
+
</div>
|
|
161
|
+
`;
|
|
162
|
+
}
|
|
163
|
+
_renderToggle(label, checked) {
|
|
164
|
+
return html `
|
|
165
|
+
<div class="processing-row">
|
|
166
|
+
<span class="processing-label">${label}</span>
|
|
167
|
+
<button
|
|
168
|
+
type="button"
|
|
169
|
+
role="switch"
|
|
170
|
+
aria-checked=${checked}
|
|
171
|
+
class="toggle ${checked ? "toggle--on" : "toggle--off"}"
|
|
172
|
+
>
|
|
173
|
+
<div class="toggle-knob"></div>
|
|
174
|
+
</button>
|
|
175
|
+
</div>
|
|
176
|
+
`;
|
|
177
|
+
}
|
|
178
|
+
// ---- Stats Tab ----
|
|
50
179
|
_renderStats() {
|
|
51
180
|
const s = this.ic.s;
|
|
52
181
|
const stats = s.stats;
|
|
182
|
+
const stateColor = s.state === "streaming"
|
|
183
|
+
? "#9ece6a"
|
|
184
|
+
: s.state === "connecting"
|
|
185
|
+
? "#7aa2f7"
|
|
186
|
+
: s.state === "error"
|
|
187
|
+
? "#f7768e"
|
|
188
|
+
: "#c0caf5";
|
|
53
189
|
return html `
|
|
54
190
|
<div class="section">
|
|
55
|
-
<div class="
|
|
56
|
-
|
|
57
|
-
|
|
191
|
+
<div class="section-header" style="margin-bottom:4px">Connection</div>
|
|
192
|
+
<div style="font-size:14px;font-weight:600;color:${stateColor}">
|
|
193
|
+
${s.state.charAt(0).toUpperCase() + s.state.slice(1)}
|
|
194
|
+
</div>
|
|
58
195
|
</div>
|
|
59
196
|
${stats
|
|
60
197
|
? html `
|
|
61
|
-
<div class="
|
|
62
|
-
<
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
198
|
+
<div class="row">
|
|
199
|
+
<span class="row-label">Bitrate</span>
|
|
200
|
+
<span class="row-value">
|
|
201
|
+
${formatBitrate(stats.video.bitrate + stats.audio.bitrate)}
|
|
202
|
+
</span>
|
|
203
|
+
</div>
|
|
204
|
+
<div class="row">
|
|
205
|
+
<span class="row-label">Video</span>
|
|
206
|
+
<span class="row-value" style="color:#7aa2f7">
|
|
207
|
+
${formatBitrate(stats.video.bitrate)}
|
|
208
|
+
</span>
|
|
209
|
+
</div>
|
|
210
|
+
<div class="row">
|
|
211
|
+
<span class="row-label">Audio</span>
|
|
212
|
+
<span class="row-value" style="color:#7aa2f7">
|
|
213
|
+
${formatBitrate(stats.audio.bitrate)}
|
|
214
|
+
</span>
|
|
215
|
+
</div>
|
|
216
|
+
<div class="row">
|
|
217
|
+
<span class="row-label">Frame Rate</span>
|
|
218
|
+
<span class="row-value">
|
|
219
|
+
${stats.video.framesPerSecond.toFixed(0)} fps
|
|
220
|
+
</span>
|
|
221
|
+
</div>
|
|
222
|
+
<div class="row">
|
|
223
|
+
<span class="row-label">Frames Encoded</span>
|
|
224
|
+
<span class="row-value">${stats.video.framesEncoded}</span>
|
|
225
|
+
</div>
|
|
226
|
+
${stats.video.packetsLost > 0 || stats.audio.packetsLost > 0
|
|
227
|
+
? html `
|
|
228
|
+
<div class="row">
|
|
229
|
+
<span class="row-label">Packets Lost</span>
|
|
230
|
+
<span class="row-value" style="color:#f7768e">
|
|
231
|
+
${stats.video.packetsLost + stats.audio.packetsLost}
|
|
232
|
+
</span>
|
|
233
|
+
</div>
|
|
234
|
+
`
|
|
235
|
+
: nothing}
|
|
236
|
+
<div class="row">
|
|
237
|
+
<span class="row-label">RTT</span>
|
|
238
|
+
<span
|
|
239
|
+
class="row-value"
|
|
240
|
+
style="color:${stats.connection.rtt > 200 ? "#e0af68" : "#c0caf5"}"
|
|
241
|
+
>
|
|
242
|
+
${stats.connection.rtt.toFixed(0)} ms
|
|
243
|
+
</span>
|
|
244
|
+
</div>
|
|
245
|
+
<div class="row">
|
|
246
|
+
<span class="row-label">ICE State</span>
|
|
247
|
+
<span class="row-value" style="text-transform:capitalize">
|
|
248
|
+
${stats.connection.iceState}
|
|
249
|
+
</span>
|
|
250
|
+
</div>
|
|
251
|
+
`
|
|
252
|
+
: html `
|
|
253
|
+
<div style="color:#565f89;text-align:center;padding:24px">
|
|
254
|
+
${s.state === "streaming"
|
|
255
|
+
? "Waiting for stats..."
|
|
256
|
+
: "Start streaming to see stats"}
|
|
257
|
+
</div>
|
|
258
|
+
`}
|
|
259
|
+
${s.error
|
|
260
|
+
? html `
|
|
261
|
+
<div
|
|
262
|
+
style="padding:12px;border-top:1px solid rgba(247,118,142,0.3);background:rgba(247,118,142,0.1)"
|
|
263
|
+
>
|
|
264
|
+
<div class="section-header" style="color:#f7768e;margin-bottom:4px">
|
|
265
|
+
Error
|
|
266
|
+
</div>
|
|
267
|
+
<div style="font-size:12px;color:#f7768e">${s.error}</div>
|
|
69
268
|
</div>
|
|
70
269
|
`
|
|
71
270
|
: nothing}
|
|
72
271
|
${s.encoderStats
|
|
73
272
|
? html `
|
|
74
|
-
<div
|
|
75
|
-
<div class="
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
273
|
+
<div style="border-top:1px solid rgba(65,72,104,0.3)">
|
|
274
|
+
<div class="section-dark">
|
|
275
|
+
<span class="section-header" style="margin-bottom:0">Encoder</span>
|
|
276
|
+
</div>
|
|
277
|
+
<div class="row">
|
|
278
|
+
<span class="row-label">Video frames</span>
|
|
279
|
+
<span class="row-value">${s.encoderStats.video.framesEncoded}</span>
|
|
280
|
+
</div>
|
|
281
|
+
<div class="row">
|
|
282
|
+
<span class="row-label">Video pending</span>
|
|
283
|
+
<span
|
|
284
|
+
class="row-value"
|
|
285
|
+
style="color:${s.encoderStats.video.framesPending > 5
|
|
286
|
+
? "#e0af68"
|
|
287
|
+
: "#c0caf5"}"
|
|
288
|
+
>
|
|
289
|
+
${s.encoderStats.video.framesPending}
|
|
290
|
+
</span>
|
|
291
|
+
</div>
|
|
292
|
+
<div class="row">
|
|
293
|
+
<span class="row-label">Audio samples</span>
|
|
294
|
+
<span class="row-value">${s.encoderStats.audio.samplesEncoded}</span>
|
|
295
|
+
</div>
|
|
79
296
|
</div>
|
|
80
297
|
`
|
|
81
298
|
: nothing}
|
|
82
299
|
`;
|
|
83
300
|
}
|
|
301
|
+
// ---- Info Tab ----
|
|
84
302
|
_renderInfo() {
|
|
85
303
|
const s = this.ic.s;
|
|
86
304
|
return html `
|
|
87
305
|
<div class="section">
|
|
88
|
-
<div class="
|
|
89
|
-
|
|
90
|
-
|
|
306
|
+
<div class="section-header" style="margin-bottom:4px">Quality Profile</div>
|
|
307
|
+
<div style="font-size:14px;color:#c0caf5;text-transform:capitalize">
|
|
308
|
+
${s.qualityProfile}
|
|
309
|
+
</div>
|
|
91
310
|
</div>
|
|
311
|
+
|
|
92
312
|
<div class="section">
|
|
93
|
-
<div class="
|
|
94
|
-
${
|
|
95
|
-
|
|
96
|
-
|
|
313
|
+
<div class="section-header" style="margin-bottom:4px">Configuration</div>
|
|
314
|
+
${this._simpleRow("WebCodecs", s.isWebCodecsAvailable ? "Available" : "Unavailable")}
|
|
315
|
+
${this._simpleRow("WebCodecs Active", s.isWebCodecsActive ? "Yes" : s.useWebCodecs ? "Pending" : "No")}
|
|
316
|
+
${this._simpleRow("Sources", String(s.sources.length))}
|
|
317
|
+
</div>
|
|
318
|
+
|
|
319
|
+
${s.sources.length > 0
|
|
320
|
+
? html `
|
|
321
|
+
<div style="border-bottom:1px solid rgba(65,72,104,0.3)">
|
|
322
|
+
<div class="section-dark">
|
|
323
|
+
<span class="section-header" style="margin-bottom:0">
|
|
324
|
+
Sources (${s.sources.length})
|
|
325
|
+
</span>
|
|
326
|
+
</div>
|
|
327
|
+
${s.sources.map((source, idx) => html `
|
|
328
|
+
<div
|
|
329
|
+
style="padding:8px 12px;${idx > 0
|
|
330
|
+
? "border-top:1px solid rgba(65,72,104,0.2)"
|
|
331
|
+
: ""}"
|
|
332
|
+
>
|
|
333
|
+
<div style="display:flex;align-items:center;gap:8px">
|
|
334
|
+
<span
|
|
335
|
+
class="source-type"
|
|
336
|
+
style="background:${source.type === "camera"
|
|
337
|
+
? "rgba(122,162,247,0.2)"
|
|
338
|
+
: source.type === "screen"
|
|
339
|
+
? "rgba(158,206,106,0.2)"
|
|
340
|
+
: "rgba(224,175,104,0.2)"};color:${source.type === "camera"
|
|
341
|
+
? "#7aa2f7"
|
|
342
|
+
: source.type === "screen"
|
|
343
|
+
? "#9ece6a"
|
|
344
|
+
: "#e0af68"}"
|
|
345
|
+
>
|
|
346
|
+
${source.type}
|
|
347
|
+
</span>
|
|
348
|
+
<span
|
|
349
|
+
style="color:#c0caf5;font-size:12px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap"
|
|
350
|
+
>
|
|
351
|
+
${source.label}
|
|
352
|
+
</span>
|
|
353
|
+
</div>
|
|
354
|
+
<div
|
|
355
|
+
style="display:flex;gap:12px;margin-top:4px;font-size:10px;color:#565f89"
|
|
356
|
+
>
|
|
357
|
+
<span>Vol: ${Math.round(source.volume * 100)}%</span>
|
|
358
|
+
${source.muted
|
|
359
|
+
? html `<span style="color:#f7768e">Muted</span>`
|
|
360
|
+
: nothing}
|
|
361
|
+
</div>
|
|
362
|
+
</div>
|
|
363
|
+
`)}
|
|
364
|
+
</div>
|
|
365
|
+
`
|
|
366
|
+
: nothing}
|
|
367
|
+
`;
|
|
368
|
+
}
|
|
369
|
+
// ---- Compositor Tab ----
|
|
370
|
+
_renderCompositor() {
|
|
371
|
+
const s = this.ic.s;
|
|
372
|
+
const rt = this.compositorRendererType;
|
|
373
|
+
const stats = this.compositorStats;
|
|
374
|
+
const rendererColor = rt === "webgpu" ? "#bb9af7" : rt === "webgl" ? "#7aa2f7" : "#9ece6a";
|
|
375
|
+
const rendererLabel = rt === "webgpu"
|
|
376
|
+
? "WebGPU"
|
|
377
|
+
: rt === "webgl"
|
|
378
|
+
? "WebGL"
|
|
379
|
+
: rt === "canvas2d"
|
|
380
|
+
? "Canvas2D"
|
|
381
|
+
: "Not initialized";
|
|
382
|
+
return html `
|
|
383
|
+
<div class="section">
|
|
384
|
+
<div class="section-header">Renderer</div>
|
|
385
|
+
<div style="font-size:14px;font-weight:600;color:${rendererColor}">
|
|
386
|
+
${rendererLabel}
|
|
387
|
+
</div>
|
|
388
|
+
</div>
|
|
389
|
+
|
|
390
|
+
${stats
|
|
391
|
+
? html `
|
|
392
|
+
<div style="border-bottom:1px solid rgba(65,72,104,0.3)">
|
|
393
|
+
<div class="section-dark">
|
|
394
|
+
<span class="section-header" style="margin-bottom:0">Performance</span>
|
|
395
|
+
</div>
|
|
396
|
+
<div class="row">
|
|
397
|
+
<span class="row-label">Frame Rate</span>
|
|
398
|
+
<span class="row-value">${stats.fps} fps</span>
|
|
399
|
+
</div>
|
|
400
|
+
<div class="row">
|
|
401
|
+
<span class="row-label">Frame Time</span>
|
|
402
|
+
<span
|
|
403
|
+
class="row-value"
|
|
404
|
+
style="color:${stats.frameTimeMs > 16 ? "#e0af68" : "#c0caf5"}"
|
|
405
|
+
>
|
|
406
|
+
${stats.frameTimeMs.toFixed(2)} ms
|
|
407
|
+
</span>
|
|
408
|
+
</div>
|
|
409
|
+
${stats.gpuMemoryMB !== undefined
|
|
410
|
+
? html `
|
|
411
|
+
<div class="row">
|
|
412
|
+
<span class="row-label">GPU Memory</span>
|
|
413
|
+
<span class="row-value">
|
|
414
|
+
${stats.gpuMemoryMB.toFixed(1)} MB
|
|
415
|
+
</span>
|
|
416
|
+
</div>
|
|
417
|
+
`
|
|
418
|
+
: nothing}
|
|
419
|
+
</div>
|
|
420
|
+
`
|
|
421
|
+
: nothing}
|
|
422
|
+
|
|
423
|
+
<div style="border-bottom:1px solid rgba(65,72,104,0.3)">
|
|
424
|
+
<div class="section-dark">
|
|
425
|
+
<span class="section-header" style="margin-bottom:0">Composition</span>
|
|
426
|
+
</div>
|
|
427
|
+
<div class="row">
|
|
428
|
+
<span class="row-label">Scenes</span>
|
|
429
|
+
<span class="row-value">${this.sceneCount}</span>
|
|
430
|
+
</div>
|
|
431
|
+
<div class="row">
|
|
432
|
+
<span class="row-label">Layers</span>
|
|
433
|
+
<span class="row-value">${this.layerCount}</span>
|
|
434
|
+
</div>
|
|
435
|
+
</div>
|
|
436
|
+
|
|
437
|
+
<!-- Encoder -->
|
|
438
|
+
<div style="border-bottom:1px solid rgba(65,72,104,0.3)">
|
|
439
|
+
<div class="section-dark">
|
|
440
|
+
<span class="section-header" style="margin-bottom:0">Encoder</span>
|
|
441
|
+
</div>
|
|
442
|
+
<div class="row">
|
|
443
|
+
<span class="row-label">Type</span>
|
|
444
|
+
<span
|
|
445
|
+
class="badge"
|
|
446
|
+
style="background:${s.useWebCodecs && s.isWebCodecsAvailable
|
|
447
|
+
? "rgba(187,154,247,0.2)"
|
|
448
|
+
: "rgba(122,162,247,0.2)"};color:${s.useWebCodecs && s.isWebCodecsAvailable
|
|
449
|
+
? "#bb9af7"
|
|
450
|
+
: "#7aa2f7"}"
|
|
451
|
+
>
|
|
452
|
+
${s.useWebCodecs && s.isWebCodecsAvailable ? "WebCodecs" : "Browser"}
|
|
453
|
+
${s.state === "streaming"
|
|
454
|
+
? html `<span style="opacity:0.7;margin-left:4px">
|
|
455
|
+
${s.isWebCodecsActive ? "(active)" : "(pending)"}
|
|
456
|
+
</span>`
|
|
457
|
+
: nothing}
|
|
458
|
+
</span>
|
|
459
|
+
</div>
|
|
460
|
+
<div class="processing-row">
|
|
461
|
+
<span class="processing-label">Use WebCodecs</span>
|
|
462
|
+
<button
|
|
463
|
+
type="button"
|
|
464
|
+
role="switch"
|
|
465
|
+
aria-checked=${s.useWebCodecs}
|
|
466
|
+
class="toggle ${s.useWebCodecs ? "toggle--on" : "toggle--off"}"
|
|
467
|
+
?disabled=${s.state === "streaming" || !s.isWebCodecsAvailable}
|
|
468
|
+
@click=${() => this.ic.setUseWebCodecs(!s.useWebCodecs)}
|
|
469
|
+
>
|
|
470
|
+
<div class="toggle-knob"></div>
|
|
471
|
+
</button>
|
|
472
|
+
</div>
|
|
473
|
+
${!s.isWebCodecsAvailable
|
|
474
|
+
? html `<div style="padding:8px 12px;font-size:10px;color:#f7768e">
|
|
475
|
+
Not available - RTCRtpScriptTransform unsupported
|
|
476
|
+
</div>`
|
|
477
|
+
: nothing}
|
|
97
478
|
</div>
|
|
98
479
|
`;
|
|
99
480
|
}
|
|
100
|
-
|
|
481
|
+
_simpleRow(label, value) {
|
|
101
482
|
return html `<div class="row">
|
|
102
483
|
<span class="row-label">${label}</span><span class="row-value">${value}</span>
|
|
103
484
|
</div>`;
|
|
@@ -111,68 +492,80 @@ FwScAdvanced.styles = [
|
|
|
111
492
|
display: block;
|
|
112
493
|
}
|
|
113
494
|
.panel {
|
|
114
|
-
width:
|
|
495
|
+
width: 280px;
|
|
115
496
|
height: 100%;
|
|
116
|
-
border-left: 1px solid rgba(
|
|
497
|
+
border-left: 1px solid rgba(65, 72, 104, 0.5);
|
|
117
498
|
background: #1a1b26;
|
|
118
|
-
|
|
119
|
-
|
|
499
|
+
display: flex;
|
|
500
|
+
flex-direction: column;
|
|
501
|
+
font-size: 12px;
|
|
502
|
+
font-family: ui-monospace, SFMono-Regular, SF Mono, Menlo, Consolas, monospace;
|
|
120
503
|
color: #a9b1d6;
|
|
504
|
+
flex-shrink: 0;
|
|
505
|
+
z-index: 40;
|
|
121
506
|
}
|
|
122
507
|
.header {
|
|
123
508
|
display: flex;
|
|
124
509
|
align-items: center;
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
border-bottom: 1px solid rgba(90, 96, 127, 0.3);
|
|
128
|
-
}
|
|
129
|
-
.tabs {
|
|
130
|
-
display: flex;
|
|
131
|
-
gap: 0.5rem;
|
|
510
|
+
border-bottom: 1px solid rgba(65, 72, 104, 0.3);
|
|
511
|
+
background: #16161e;
|
|
132
512
|
}
|
|
133
513
|
.tab {
|
|
134
|
-
padding:
|
|
514
|
+
padding: 8px 12px;
|
|
515
|
+
font-size: 10px;
|
|
516
|
+
text-transform: uppercase;
|
|
517
|
+
letter-spacing: 0.05em;
|
|
518
|
+
font-weight: 600;
|
|
135
519
|
border: none;
|
|
136
|
-
background:
|
|
520
|
+
background: transparent;
|
|
137
521
|
color: #565f89;
|
|
138
|
-
font-size: 0.6875rem;
|
|
139
|
-
font-weight: 600;
|
|
140
522
|
cursor: pointer;
|
|
141
|
-
|
|
523
|
+
transition: all 0.15s;
|
|
142
524
|
}
|
|
143
525
|
.tab--active {
|
|
526
|
+
background: #1a1b26;
|
|
144
527
|
color: #c0caf5;
|
|
145
|
-
background: rgba(90, 96, 127, 0.2);
|
|
146
528
|
}
|
|
147
529
|
.close {
|
|
148
530
|
display: flex;
|
|
149
|
-
background:
|
|
531
|
+
background: transparent;
|
|
150
532
|
border: none;
|
|
151
533
|
color: #565f89;
|
|
152
534
|
cursor: pointer;
|
|
153
|
-
padding:
|
|
535
|
+
padding: 8px;
|
|
536
|
+
transition: color 0.15s;
|
|
154
537
|
}
|
|
155
538
|
.close:hover {
|
|
156
539
|
color: #c0caf5;
|
|
157
540
|
}
|
|
158
541
|
.body {
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
.section {
|
|
162
|
-
margin-bottom: 0.75rem;
|
|
542
|
+
flex: 1;
|
|
543
|
+
overflow-y: auto;
|
|
163
544
|
}
|
|
164
|
-
.
|
|
165
|
-
font-size:
|
|
166
|
-
|
|
545
|
+
.section-header {
|
|
546
|
+
font-size: 10px;
|
|
547
|
+
color: #565f89;
|
|
167
548
|
text-transform: uppercase;
|
|
168
549
|
letter-spacing: 0.05em;
|
|
169
|
-
|
|
170
|
-
margin-bottom:
|
|
550
|
+
font-weight: 600;
|
|
551
|
+
margin-bottom: 8px;
|
|
552
|
+
}
|
|
553
|
+
.section {
|
|
554
|
+
padding: 12px;
|
|
555
|
+
border-bottom: 1px solid rgba(65, 72, 104, 0.3);
|
|
556
|
+
}
|
|
557
|
+
.section-dark {
|
|
558
|
+
padding: 8px 12px;
|
|
559
|
+
background: #16161e;
|
|
560
|
+
display: flex;
|
|
561
|
+
justify-content: space-between;
|
|
562
|
+
align-items: center;
|
|
171
563
|
}
|
|
172
564
|
.row {
|
|
173
565
|
display: flex;
|
|
174
566
|
justify-content: space-between;
|
|
175
|
-
padding:
|
|
567
|
+
padding: 8px 12px;
|
|
568
|
+
border-top: 1px solid rgba(65, 72, 104, 0.2);
|
|
176
569
|
}
|
|
177
570
|
.row-label {
|
|
178
571
|
color: #565f89;
|
|
@@ -182,11 +575,102 @@ FwScAdvanced.styles = [
|
|
|
182
575
|
font-family: ui-monospace, monospace;
|
|
183
576
|
font-variant-numeric: tabular-nums;
|
|
184
577
|
}
|
|
578
|
+
.level-bar {
|
|
579
|
+
height: 8px;
|
|
580
|
+
background: rgba(65, 72, 104, 0.3);
|
|
581
|
+
border-radius: 4px;
|
|
582
|
+
overflow: hidden;
|
|
583
|
+
}
|
|
584
|
+
.level-fill {
|
|
585
|
+
height: 100%;
|
|
586
|
+
transition: all 75ms;
|
|
587
|
+
}
|
|
588
|
+
.level-labels {
|
|
589
|
+
display: flex;
|
|
590
|
+
justify-content: space-between;
|
|
591
|
+
font-size: 10px;
|
|
592
|
+
color: #565f89;
|
|
593
|
+
margin-top: 4px;
|
|
594
|
+
}
|
|
595
|
+
.badge {
|
|
596
|
+
font-size: 12px;
|
|
597
|
+
font-family: monospace;
|
|
598
|
+
padding: 2px 6px;
|
|
599
|
+
}
|
|
600
|
+
.toggle {
|
|
601
|
+
position: relative;
|
|
602
|
+
display: inline-flex;
|
|
603
|
+
height: 20px;
|
|
604
|
+
width: 36px;
|
|
605
|
+
flex-shrink: 0;
|
|
606
|
+
cursor: pointer;
|
|
607
|
+
border-radius: 10px;
|
|
608
|
+
border: 2px solid transparent;
|
|
609
|
+
transition: background 0.2s;
|
|
610
|
+
padding: 0;
|
|
611
|
+
}
|
|
612
|
+
.toggle:disabled {
|
|
613
|
+
opacity: 0.5;
|
|
614
|
+
cursor: not-allowed;
|
|
615
|
+
}
|
|
616
|
+
.toggle-knob {
|
|
617
|
+
position: absolute;
|
|
618
|
+
top: 2px;
|
|
619
|
+
width: 12px;
|
|
620
|
+
height: 12px;
|
|
621
|
+
border-radius: 50%;
|
|
622
|
+
background: white;
|
|
623
|
+
transition: left 0.2s;
|
|
624
|
+
}
|
|
625
|
+
.toggle--on {
|
|
626
|
+
background: #7aa2f7;
|
|
627
|
+
}
|
|
628
|
+
.toggle--off {
|
|
629
|
+
background: rgba(65, 72, 104, 0.5);
|
|
630
|
+
}
|
|
631
|
+
.toggle--on .toggle-knob {
|
|
632
|
+
left: 18px;
|
|
633
|
+
}
|
|
634
|
+
.toggle--off .toggle-knob {
|
|
635
|
+
left: 4px;
|
|
636
|
+
}
|
|
637
|
+
.processing-row {
|
|
638
|
+
display: flex;
|
|
639
|
+
justify-content: space-between;
|
|
640
|
+
align-items: center;
|
|
641
|
+
padding: 8px 12px;
|
|
642
|
+
border-top: 1px solid rgba(65, 72, 104, 0.2);
|
|
643
|
+
}
|
|
644
|
+
.processing-label {
|
|
645
|
+
font-size: 12px;
|
|
646
|
+
color: #a9b1d6;
|
|
647
|
+
}
|
|
648
|
+
.source-type {
|
|
649
|
+
font-size: 10px;
|
|
650
|
+
font-family: monospace;
|
|
651
|
+
padding: 2px 6px;
|
|
652
|
+
text-transform: uppercase;
|
|
653
|
+
}
|
|
185
654
|
`,
|
|
186
655
|
];
|
|
187
656
|
__decorate([
|
|
188
657
|
property({ attribute: false })
|
|
189
658
|
], FwScAdvanced.prototype, "ic", void 0);
|
|
659
|
+
__decorate([
|
|
660
|
+
property({ type: Boolean, attribute: "compositor-enabled" })
|
|
661
|
+
], FwScAdvanced.prototype, "compositorEnabled", void 0);
|
|
662
|
+
__decorate([
|
|
663
|
+
property({ type: String, attribute: "compositor-renderer" })
|
|
664
|
+
], FwScAdvanced.prototype, "compositorRendererType", void 0);
|
|
665
|
+
__decorate([
|
|
666
|
+
property({ attribute: false })
|
|
667
|
+
], FwScAdvanced.prototype, "compositorStats", void 0);
|
|
668
|
+
__decorate([
|
|
669
|
+
property({ type: Number, attribute: "scene-count" })
|
|
670
|
+
], FwScAdvanced.prototype, "sceneCount", void 0);
|
|
671
|
+
__decorate([
|
|
672
|
+
property({ type: Number, attribute: "layer-count" })
|
|
673
|
+
], FwScAdvanced.prototype, "layerCount", void 0);
|
|
190
674
|
__decorate([
|
|
191
675
|
state()
|
|
192
676
|
], FwScAdvanced.prototype, "_activeTab", void 0);
|