@bitmagic/cli 0.1.60 → 0.1.61-dev.1
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/README.md +47 -8
- package/assets/fonts/NotoSans-Bold.ttf +0 -0
- package/assets/fonts/OFL.txt +94 -0
- package/dist/chrome-launch.d.ts +18 -0
- package/dist/chrome-launch.js +24 -0
- package/dist/chrome-launch.js.map +1 -0
- package/dist/cli.d.ts +1 -0
- package/dist/cli.js +2 -0
- package/dist/cli.js.map +1 -1
- package/dist/commands/generate.d.ts +44 -0
- package/dist/commands/generate.js +143 -0
- package/dist/commands/generate.js.map +1 -1
- package/dist/commands/trailer-publish.d.ts +15 -0
- package/dist/commands/trailer-publish.js +45 -0
- package/dist/commands/trailer-publish.js.map +1 -0
- package/dist/commands/trailer.d.ts +3 -0
- package/dist/commands/trailer.js +396 -0
- package/dist/commands/trailer.js.map +1 -0
- package/dist/editor/hud-replay-page.d.ts +7 -0
- package/dist/editor/hud-replay-page.js +219 -0
- package/dist/editor/hud-replay-page.js.map +1 -0
- package/dist/editor/recording-panel.d.ts +3 -1
- package/dist/editor/recording-panel.js +6 -2
- package/dist/editor/recording-panel.js.map +1 -1
- package/dist/editor/recording-sink.d.ts +3 -20
- package/dist/editor/recording-sink.js +14 -35
- package/dist/editor/recording-sink.js.map +1 -1
- package/dist/editor/server.js +15 -18
- package/dist/editor/server.js.map +1 -1
- package/dist/editor/shell-page.d.ts +0 -8
- package/dist/editor/shell-page.js +23 -19
- package/dist/editor/shell-page.js.map +1 -1
- package/dist/generate/music.d.ts +51 -0
- package/dist/generate/music.js +93 -0
- package/dist/generate/music.js.map +1 -0
- package/dist/generate/stream.d.ts +13 -0
- package/dist/generate/stream.js +17 -1
- package/dist/generate/stream.js.map +1 -1
- package/dist/project/jobs.d.ts +1 -1
- package/dist/scaffold/project-files.d.ts +0 -1
- package/dist/scaffold/project-files.js +6 -33
- package/dist/scaffold/project-files.js.map +1 -1
- package/dist/scaffold/project.js +3 -1
- package/dist/scaffold/project.js.map +1 -1
- package/dist/scaffold/skill-files.d.ts +22 -0
- package/dist/scaffold/skill-files.js +198 -0
- package/dist/scaffold/skill-files.js.map +1 -0
- package/dist/trailer/analyze.d.ts +23 -0
- package/dist/trailer/analyze.js +186 -0
- package/dist/trailer/analyze.js.map +1 -0
- package/dist/trailer/auto-edl.d.ts +46 -0
- package/dist/trailer/auto-edl.js +143 -0
- package/dist/trailer/auto-edl.js.map +1 -0
- package/dist/trailer/beat-cut.d.ts +57 -0
- package/dist/trailer/beat-cut.js +232 -0
- package/dist/trailer/beat-cut.js.map +1 -0
- package/dist/trailer/client.d.ts +52 -0
- package/dist/trailer/client.js +133 -0
- package/dist/trailer/client.js.map +1 -0
- package/dist/trailer/edl-time.d.ts +61 -0
- package/dist/trailer/edl-time.js +105 -0
- package/dist/trailer/edl-time.js.map +1 -0
- package/dist/trailer/ffmpeg.d.ts +8 -0
- package/dist/trailer/ffmpeg.js +55 -0
- package/dist/trailer/ffmpeg.js.map +1 -0
- package/dist/trailer/hud-raster.d.ts +28 -0
- package/dist/trailer/hud-raster.js +114 -0
- package/dist/trailer/hud-raster.js.map +1 -0
- package/dist/trailer/hud-state.d.ts +110 -0
- package/dist/trailer/hud-state.js +410 -0
- package/dist/trailer/hud-state.js.map +1 -0
- package/dist/trailer/io.d.ts +20 -0
- package/dist/trailer/io.js +15 -0
- package/dist/trailer/io.js.map +1 -0
- package/dist/trailer/make.d.ts +54 -0
- package/dist/trailer/make.js +205 -0
- package/dist/trailer/make.js.map +1 -0
- package/dist/trailer/merge.d.ts +7 -0
- package/dist/trailer/merge.js +144 -0
- package/dist/trailer/merge.js.map +1 -0
- package/dist/trailer/music-beats.d.ts +123 -0
- package/dist/trailer/music-beats.js +707 -0
- package/dist/trailer/music-beats.js.map +1 -0
- package/dist/trailer/paths.d.ts +28 -0
- package/dist/trailer/paths.js +101 -0
- package/dist/trailer/paths.js.map +1 -0
- package/dist/trailer/publish-record.d.ts +17 -0
- package/dist/trailer/publish-record.js +59 -0
- package/dist/trailer/publish-record.js.map +1 -0
- package/dist/trailer/publish.d.ts +45 -0
- package/dist/trailer/publish.js +149 -0
- package/dist/trailer/publish.js.map +1 -0
- package/dist/trailer/record-session.d.ts +72 -0
- package/dist/trailer/record-session.js +328 -0
- package/dist/trailer/record-session.js.map +1 -0
- package/dist/trailer/render.d.ts +57 -0
- package/dist/trailer/render.js +475 -0
- package/dist/trailer/render.js.map +1 -0
- package/dist/trailer/revision.d.ts +8 -0
- package/dist/trailer/revision.js +31 -0
- package/dist/trailer/revision.js.map +1 -0
- package/dist/trailer/synth.d.ts +9 -0
- package/dist/trailer/synth.js +120 -0
- package/dist/trailer/synth.js.map +1 -0
- package/dist/trailer/timeline-types.d.ts +176 -0
- package/dist/trailer/timeline-types.js +379 -0
- package/dist/trailer/timeline-types.js.map +1 -0
- package/dist/trailer/title-raster.d.ts +6 -0
- package/dist/trailer/title-raster.js +47 -0
- package/dist/trailer/title-raster.js.map +1 -0
- package/dist/trailer/titles.d.ts +44 -0
- package/dist/trailer/titles.js +119 -0
- package/dist/trailer/titles.js.map +1 -0
- package/dist/trailer/video-chain.d.ts +41 -0
- package/dist/trailer/video-chain.js +78 -0
- package/dist/trailer/video-chain.js.map +1 -0
- package/dist/verify/browser.js +12 -19
- package/dist/verify/browser.js.map +1 -1
- package/package.json +5 -4
|
@@ -0,0 +1,410 @@
|
|
|
1
|
+
import { exclusiveOutputEnd, sourceFrameToOutputSec } from './edl-time.js';
|
|
2
|
+
import { warn } from './io.js';
|
|
3
|
+
/**
|
|
4
|
+
* Engine-owned chrome that lives in the HUD element registry but must never
|
|
5
|
+
* reach a trailer: interactive controls the viewer can't click in a video.
|
|
6
|
+
* `mute-button` is `MuteControl`'s custom element (engine/ui/MuteControl.ts).
|
|
7
|
+
*/
|
|
8
|
+
export const CHROME_ELEMENT_IDS = new Set(['mute-button']);
|
|
9
|
+
// ---------------------------------------------------------------------------
|
|
10
|
+
// Defaults
|
|
11
|
+
// ---------------------------------------------------------------------------
|
|
12
|
+
/** The engine records `frame` on a 60fps source clock. */
|
|
13
|
+
export const DEFAULT_HUD_FPS = 60;
|
|
14
|
+
/** IGameHUD.showToast's default duration. */
|
|
15
|
+
export const DEFAULT_TOAST_MS = 2500;
|
|
16
|
+
/** IGameHUD's per-kind default anchor, used when a create op omits one. */
|
|
17
|
+
const DEFAULT_ANCHOR = {
|
|
18
|
+
progress: 'top-left',
|
|
19
|
+
counter: 'top-right',
|
|
20
|
+
'icon-text': 'bottom-left',
|
|
21
|
+
timer: 'top-center',
|
|
22
|
+
custom: 'top-left'
|
|
23
|
+
};
|
|
24
|
+
/** Derived timer seconds are rounded to this many decimals for a stable key. */
|
|
25
|
+
const SECONDS_DECIMALS = 3;
|
|
26
|
+
// ---------------------------------------------------------------------------
|
|
27
|
+
// Reduction
|
|
28
|
+
// ---------------------------------------------------------------------------
|
|
29
|
+
function readString(params, key) {
|
|
30
|
+
const value = params[key];
|
|
31
|
+
return typeof value === 'string' ? value : undefined;
|
|
32
|
+
}
|
|
33
|
+
function readNumber(params, key) {
|
|
34
|
+
const value = params[key];
|
|
35
|
+
return typeof value === 'number' && Number.isFinite(value) ? value : undefined;
|
|
36
|
+
}
|
|
37
|
+
function readBoolean(params, key) {
|
|
38
|
+
const value = params[key];
|
|
39
|
+
return typeof value === 'boolean' ? value : undefined;
|
|
40
|
+
}
|
|
41
|
+
function round(value) {
|
|
42
|
+
const factor = 10 ** SECONDS_DECIMALS;
|
|
43
|
+
return Math.round(value * factor) / factor;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Incremental reducer over a frame-sorted op stream. Public callers go through
|
|
47
|
+
* `reduceHudState`; `collectUiKeyframes` drives one instance forward across a
|
|
48
|
+
* clip so a frame-by-frame walk stays linear in the op count.
|
|
49
|
+
*/
|
|
50
|
+
class HudReducer {
|
|
51
|
+
ops;
|
|
52
|
+
fps;
|
|
53
|
+
cursor = 0;
|
|
54
|
+
hudVisible = true;
|
|
55
|
+
health = null;
|
|
56
|
+
theme = null;
|
|
57
|
+
elements = [];
|
|
58
|
+
toasts = [];
|
|
59
|
+
constructor(ops, fps) {
|
|
60
|
+
// Stable sort: entries recorded on the same frame keep emission order,
|
|
61
|
+
// which IS the stacking order within an anchor.
|
|
62
|
+
this.ops = [...ops].sort((a, b) => a.frame - b.frame);
|
|
63
|
+
this.fps = fps;
|
|
64
|
+
}
|
|
65
|
+
/** Apply every op at or before `frame`. Frames must not go backwards. */
|
|
66
|
+
advanceTo(frame) {
|
|
67
|
+
while (this.cursor < this.ops.length && this.ops[this.cursor].frame <= frame) {
|
|
68
|
+
this.apply(this.ops[this.cursor]);
|
|
69
|
+
this.cursor++;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
find(id) {
|
|
73
|
+
return this.elements.find((el) => el.id === id);
|
|
74
|
+
}
|
|
75
|
+
apply(op) {
|
|
76
|
+
// Engine chrome is part of the HUD but never part of a trailer.
|
|
77
|
+
if ('id' in op && CHROME_ELEMENT_IDS.has(op.id))
|
|
78
|
+
return;
|
|
79
|
+
switch (op.op) {
|
|
80
|
+
case 'create':
|
|
81
|
+
this.applyCreate(op.frame, op.id, op.elType, op.params);
|
|
82
|
+
break;
|
|
83
|
+
case 'update':
|
|
84
|
+
this.applyUpdate(op.id, op.text, op.icon, op.percent);
|
|
85
|
+
break;
|
|
86
|
+
case 'custom-html': {
|
|
87
|
+
const el = this.find(op.id);
|
|
88
|
+
if (el !== undefined)
|
|
89
|
+
el.html = op.html;
|
|
90
|
+
break;
|
|
91
|
+
}
|
|
92
|
+
case 'timer':
|
|
93
|
+
this.applyTimer(op.frame, op.id, op.action, op.seconds);
|
|
94
|
+
break;
|
|
95
|
+
case 'show':
|
|
96
|
+
case 'hide': {
|
|
97
|
+
const el = this.find(op.id);
|
|
98
|
+
if (el !== undefined)
|
|
99
|
+
el.visible = op.op === 'show';
|
|
100
|
+
break;
|
|
101
|
+
}
|
|
102
|
+
case 'remove': {
|
|
103
|
+
const index = this.elements.findIndex((el) => el.id === op.id);
|
|
104
|
+
if (index >= 0)
|
|
105
|
+
this.elements.splice(index, 1);
|
|
106
|
+
break;
|
|
107
|
+
}
|
|
108
|
+
case 'health':
|
|
109
|
+
this.health = { current: op.current, max: op.max, visible: this.health?.visible ?? false };
|
|
110
|
+
break;
|
|
111
|
+
case 'health-visible':
|
|
112
|
+
this.health = {
|
|
113
|
+
current: this.health?.current ?? 0,
|
|
114
|
+
max: this.health?.max ?? 100,
|
|
115
|
+
visible: op.visible
|
|
116
|
+
};
|
|
117
|
+
break;
|
|
118
|
+
case 'toast': {
|
|
119
|
+
const durationMs = op.durationMs ?? DEFAULT_TOAST_MS;
|
|
120
|
+
const toast = {
|
|
121
|
+
message: op.message,
|
|
122
|
+
startFrame: op.frame,
|
|
123
|
+
endFrame: op.frame + (durationMs / 1000) * this.fps
|
|
124
|
+
};
|
|
125
|
+
if (op.variant !== undefined)
|
|
126
|
+
toast.variant = op.variant;
|
|
127
|
+
this.toasts.push(toast);
|
|
128
|
+
break;
|
|
129
|
+
}
|
|
130
|
+
case 'hud-visible':
|
|
131
|
+
this.hudVisible = op.visible;
|
|
132
|
+
break;
|
|
133
|
+
case 'theme':
|
|
134
|
+
this.theme = op.theme;
|
|
135
|
+
break;
|
|
136
|
+
default:
|
|
137
|
+
// Forward compatibility: a newer engine may log ops we predate.
|
|
138
|
+
break;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
applyCreate(frame, id, elType, params) {
|
|
142
|
+
// Re-creating an id replaces the old element and re-appends it, matching
|
|
143
|
+
// the DOM's append-on-create stacking.
|
|
144
|
+
const existing = this.elements.findIndex((el) => el.id === id);
|
|
145
|
+
if (existing >= 0)
|
|
146
|
+
this.elements.splice(existing, 1);
|
|
147
|
+
const el = {
|
|
148
|
+
id,
|
|
149
|
+
type: elType,
|
|
150
|
+
anchor: readString(params, 'anchor') ?? DEFAULT_ANCHOR[elType] ?? 'top-left',
|
|
151
|
+
visible: true
|
|
152
|
+
};
|
|
153
|
+
const label = readString(params, 'label');
|
|
154
|
+
const color = readString(params, 'color');
|
|
155
|
+
const width = readNumber(params, 'width');
|
|
156
|
+
const showText = readBoolean(params, 'showText');
|
|
157
|
+
const percent = readNumber(params, 'percent');
|
|
158
|
+
const icon = readString(params, 'icon');
|
|
159
|
+
const text = readString(params, 'text');
|
|
160
|
+
const iconSize = readNumber(params, 'iconSize');
|
|
161
|
+
const countDown = readBoolean(params, 'countDown');
|
|
162
|
+
const format = readString(params, 'format');
|
|
163
|
+
const html = readString(params, 'html');
|
|
164
|
+
const css = readString(params, 'css');
|
|
165
|
+
if (label !== undefined)
|
|
166
|
+
el.label = label;
|
|
167
|
+
if (color !== undefined)
|
|
168
|
+
el.color = color;
|
|
169
|
+
if (width !== undefined)
|
|
170
|
+
el.width = width;
|
|
171
|
+
if (showText !== undefined)
|
|
172
|
+
el.showText = showText;
|
|
173
|
+
if (percent !== undefined)
|
|
174
|
+
el.percent = percent;
|
|
175
|
+
if (icon !== undefined)
|
|
176
|
+
el.icon = icon;
|
|
177
|
+
if (text !== undefined)
|
|
178
|
+
el.text = text;
|
|
179
|
+
if (iconSize !== undefined)
|
|
180
|
+
el.iconSize = iconSize;
|
|
181
|
+
if (countDown !== undefined)
|
|
182
|
+
el.countDown = countDown;
|
|
183
|
+
if (format !== undefined)
|
|
184
|
+
el.format = format;
|
|
185
|
+
if (html !== undefined)
|
|
186
|
+
el.html = html;
|
|
187
|
+
if (css !== undefined)
|
|
188
|
+
el.css = css;
|
|
189
|
+
if (elType === 'timer') {
|
|
190
|
+
const seconds = readNumber(params, 'seconds') ?? 0;
|
|
191
|
+
el.timer = { anchorSeconds: seconds, anchorFrame: frame, running: false, createSeconds: seconds };
|
|
192
|
+
}
|
|
193
|
+
this.elements.push(el);
|
|
194
|
+
}
|
|
195
|
+
applyUpdate(id, text, icon, percent) {
|
|
196
|
+
const el = this.find(id);
|
|
197
|
+
if (el === undefined)
|
|
198
|
+
return; // updates can trail a remove
|
|
199
|
+
if (text !== undefined)
|
|
200
|
+
el.text = text;
|
|
201
|
+
if (icon !== undefined)
|
|
202
|
+
el.icon = icon;
|
|
203
|
+
if (percent !== undefined)
|
|
204
|
+
el.percent = percent;
|
|
205
|
+
}
|
|
206
|
+
applyTimer(frame, id, action, seconds) {
|
|
207
|
+
const el = this.find(id);
|
|
208
|
+
const timer = el?.timer;
|
|
209
|
+
if (el === undefined || timer === undefined)
|
|
210
|
+
return;
|
|
211
|
+
switch (action) {
|
|
212
|
+
case 'start':
|
|
213
|
+
timer.anchorSeconds = seconds ?? derivedSeconds(timer, frame, el.countDown ?? false, this.fps);
|
|
214
|
+
timer.anchorFrame = frame;
|
|
215
|
+
timer.running = true;
|
|
216
|
+
break;
|
|
217
|
+
case 'pause':
|
|
218
|
+
timer.anchorSeconds = derivedSeconds(timer, frame, el.countDown ?? false, this.fps);
|
|
219
|
+
timer.anchorFrame = frame;
|
|
220
|
+
timer.running = false;
|
|
221
|
+
break;
|
|
222
|
+
case 'reset':
|
|
223
|
+
timer.anchorSeconds = seconds ?? timer.createSeconds;
|
|
224
|
+
timer.anchorFrame = frame;
|
|
225
|
+
timer.running = false;
|
|
226
|
+
break;
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
/** The replay state as of `frame`. Requires `advanceTo(frame)` first. */
|
|
230
|
+
snapshot(frame) {
|
|
231
|
+
this.toasts = this.toasts.filter((t) => t.endFrame > frame);
|
|
232
|
+
return {
|
|
233
|
+
version: 1,
|
|
234
|
+
hudVisible: this.hudVisible,
|
|
235
|
+
health: this.health === null ? null : { ...this.health },
|
|
236
|
+
theme: this.theme,
|
|
237
|
+
elements: this.elements.map((el) => emitElement(el, frame, this.fps)),
|
|
238
|
+
toasts: this.toasts
|
|
239
|
+
.filter((t) => t.startFrame <= frame)
|
|
240
|
+
.map((t) => (t.variant === undefined ? { message: t.message } : { message: t.message, variant: t.variant }))
|
|
241
|
+
};
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
function derivedSeconds(timer, frame, countDown, fps) {
|
|
245
|
+
if (!timer.running)
|
|
246
|
+
return timer.anchorSeconds;
|
|
247
|
+
const elapsed = Math.max(0, frame - timer.anchorFrame) / fps;
|
|
248
|
+
return countDown ? Math.max(0, timer.anchorSeconds - elapsed) : timer.anchorSeconds + elapsed;
|
|
249
|
+
}
|
|
250
|
+
/** Build the emitted element, in a fixed key order, omitting unset optionals. */
|
|
251
|
+
function emitElement(el, frame, fps) {
|
|
252
|
+
const state = { id: el.id, type: el.type, anchor: el.anchor, visible: el.visible };
|
|
253
|
+
if (el.label !== undefined)
|
|
254
|
+
state.label = el.label;
|
|
255
|
+
if (el.color !== undefined)
|
|
256
|
+
state.color = el.color;
|
|
257
|
+
if (el.width !== undefined)
|
|
258
|
+
state.width = el.width;
|
|
259
|
+
if (el.showText !== undefined)
|
|
260
|
+
state.showText = el.showText;
|
|
261
|
+
if (el.percent !== undefined)
|
|
262
|
+
state.percent = el.percent;
|
|
263
|
+
if (el.icon !== undefined)
|
|
264
|
+
state.icon = el.icon;
|
|
265
|
+
if (el.text !== undefined)
|
|
266
|
+
state.text = el.text;
|
|
267
|
+
if (el.iconSize !== undefined)
|
|
268
|
+
state.iconSize = el.iconSize;
|
|
269
|
+
if (el.timer !== undefined)
|
|
270
|
+
state.seconds = round(derivedSeconds(el.timer, frame, el.countDown ?? false, fps));
|
|
271
|
+
if (el.countDown !== undefined)
|
|
272
|
+
state.countDown = el.countDown;
|
|
273
|
+
if (el.format !== undefined)
|
|
274
|
+
state.format = el.format;
|
|
275
|
+
if (el.html !== undefined)
|
|
276
|
+
state.html = el.html;
|
|
277
|
+
if (el.css !== undefined)
|
|
278
|
+
state.css = el.css;
|
|
279
|
+
return state;
|
|
280
|
+
}
|
|
281
|
+
/**
|
|
282
|
+
* The complete HUD state at `frame`. Ops after `frame` are ignored; unknown
|
|
283
|
+
* op names are skipped rather than throwing.
|
|
284
|
+
*/
|
|
285
|
+
export function reduceHudState(ops, frame, fps = DEFAULT_HUD_FPS) {
|
|
286
|
+
const reducer = new HudReducer(ops, fps);
|
|
287
|
+
reducer.advanceTo(frame);
|
|
288
|
+
return reducer.snapshot(frame);
|
|
289
|
+
}
|
|
290
|
+
/** True when a state would rasterize to a fully transparent frame. */
|
|
291
|
+
export function isBlankHudState(state) {
|
|
292
|
+
if (!state.hudVisible)
|
|
293
|
+
return true;
|
|
294
|
+
if (state.toasts.length > 0)
|
|
295
|
+
return false;
|
|
296
|
+
if (state.health !== null && state.health.visible)
|
|
297
|
+
return false;
|
|
298
|
+
return !state.elements.some((el) => el.visible);
|
|
299
|
+
}
|
|
300
|
+
export const DEFAULT_MAX_KEYFRAMES_PER_SECOND = 10;
|
|
301
|
+
export const DEFAULT_MAX_KEYFRAMES_PER_CLIP = 240;
|
|
302
|
+
/**
|
|
303
|
+
* Frame times are exact ratios that land just under a spacing boundary in
|
|
304
|
+
* binary (frame 18 at 60fps is 0.09999999999999998s after frame 12), which
|
|
305
|
+
* would otherwise push every subsequent keyframe a frame later.
|
|
306
|
+
*/
|
|
307
|
+
const SPACING_EPSILON = 1e-9;
|
|
308
|
+
/**
|
|
309
|
+
* Structural identity of a state. Timer seconds collapse to whole displayed
|
|
310
|
+
* seconds (floor — where both floor- and ceil-based formatters change), so a
|
|
311
|
+
* ticking clock yields ~1 keyframe per second instead of one per frame.
|
|
312
|
+
*/
|
|
313
|
+
function stateKey(state) {
|
|
314
|
+
return JSON.stringify({
|
|
315
|
+
...state,
|
|
316
|
+
elements: state.elements.map((el) => el.seconds === undefined ? el : { ...el, seconds: Math.floor(el.seconds) })
|
|
317
|
+
});
|
|
318
|
+
}
|
|
319
|
+
/**
|
|
320
|
+
* Walk every enabled clip's source range and emit a keyframe wherever the
|
|
321
|
+
* reduced HUD state changes.
|
|
322
|
+
*
|
|
323
|
+
* A clip's overlays stop at `exclusiveOutputEnd`, so during a crossfade the
|
|
324
|
+
* incoming clip's UI takes over at the fade start and exactly one overlay is
|
|
325
|
+
* ever active — two stacked HUDs would double-draw every element.
|
|
326
|
+
*/
|
|
327
|
+
export function collectUiKeyframes(ops, clips, opts = {}) {
|
|
328
|
+
const fps = opts.fps ?? DEFAULT_HUD_FPS;
|
|
329
|
+
const maxPerSecond = opts.maxPerSecond ?? DEFAULT_MAX_KEYFRAMES_PER_SECOND;
|
|
330
|
+
const maxPerClip = opts.maxPerClip ?? DEFAULT_MAX_KEYFRAMES_PER_CLIP;
|
|
331
|
+
const clipEnabled = opts.clipEnabled ?? (() => true);
|
|
332
|
+
const log = opts.log ?? warn;
|
|
333
|
+
const minSpacingSec = maxPerSecond > 0 ? 1 / maxPerSecond : 0;
|
|
334
|
+
const keyframes = [];
|
|
335
|
+
for (let index = 0; index < clips.length; index++) {
|
|
336
|
+
if (!clipEnabled(index))
|
|
337
|
+
continue;
|
|
338
|
+
const timing = clips[index];
|
|
339
|
+
const windowEnd = exclusiveOutputEnd(clips, index);
|
|
340
|
+
const reducer = new HudReducer(ops, fps);
|
|
341
|
+
const clipFrames = [];
|
|
342
|
+
let lastEmittedKey = null;
|
|
343
|
+
let lastEmittedSec = Number.NEGATIVE_INFINITY;
|
|
344
|
+
// The newest state still waiting for a slot; superseding it loses it.
|
|
345
|
+
let pendingKey = null;
|
|
346
|
+
let coalesced = 0;
|
|
347
|
+
let droppedByCap = 0;
|
|
348
|
+
let capped = false;
|
|
349
|
+
let firstDroppedFrame = -1;
|
|
350
|
+
for (let frame = timing.in; frame < timing.out; frame++) {
|
|
351
|
+
const outputSec = sourceFrameToOutputSec(timing, frame, fps);
|
|
352
|
+
if (outputSec >= windowEnd)
|
|
353
|
+
break;
|
|
354
|
+
reducer.advanceTo(frame);
|
|
355
|
+
const state = reducer.snapshot(frame);
|
|
356
|
+
const key = stateKey(state);
|
|
357
|
+
if (key === lastEmittedKey)
|
|
358
|
+
continue;
|
|
359
|
+
if (clipFrames.length >= maxPerClip) {
|
|
360
|
+
if (pendingKey !== null && pendingKey !== key)
|
|
361
|
+
droppedByCap++;
|
|
362
|
+
if (!capped)
|
|
363
|
+
firstDroppedFrame = frame;
|
|
364
|
+
capped = true;
|
|
365
|
+
pendingKey = key;
|
|
366
|
+
continue;
|
|
367
|
+
}
|
|
368
|
+
if (outputSec - lastEmittedSec < minSpacingSec - SPACING_EPSILON) {
|
|
369
|
+
// Rate limited: hold, and emit the newest state once spacing allows.
|
|
370
|
+
if (pendingKey !== null && pendingKey !== key)
|
|
371
|
+
coalesced++;
|
|
372
|
+
pendingKey = key;
|
|
373
|
+
continue;
|
|
374
|
+
}
|
|
375
|
+
if (pendingKey !== null && pendingKey !== key)
|
|
376
|
+
coalesced++;
|
|
377
|
+
clipFrames.push({
|
|
378
|
+
sourceFrame: frame,
|
|
379
|
+
clipIndex: index,
|
|
380
|
+
outputStartSec: outputSec,
|
|
381
|
+
outputEndSec: windowEnd,
|
|
382
|
+
state
|
|
383
|
+
});
|
|
384
|
+
lastEmittedKey = key;
|
|
385
|
+
lastEmittedSec = outputSec;
|
|
386
|
+
pendingKey = null;
|
|
387
|
+
}
|
|
388
|
+
// Whatever is still pending when the clip ends is never rendered either.
|
|
389
|
+
if (pendingKey !== null) {
|
|
390
|
+
if (capped)
|
|
391
|
+
droppedByCap++;
|
|
392
|
+
else
|
|
393
|
+
coalesced++;
|
|
394
|
+
}
|
|
395
|
+
for (let i = 0; i < clipFrames.length - 1; i++) {
|
|
396
|
+
clipFrames[i].outputEndSec = clipFrames[i + 1].outputStartSec;
|
|
397
|
+
}
|
|
398
|
+
keyframes.push(...clipFrames);
|
|
399
|
+
if (coalesced > 0) {
|
|
400
|
+
log(`ui: clip ${index} rate-limited to ${maxPerSecond} keyframe(s)/s of output time — ` +
|
|
401
|
+
`${coalesced} intermediate HUD state(s) never rendered`);
|
|
402
|
+
}
|
|
403
|
+
if (droppedByCap > 0) {
|
|
404
|
+
log(`ui: clip ${index} hit the ${maxPerClip}-keyframe cap at source frame ${firstDroppedFrame} — ` +
|
|
405
|
+
`${droppedByCap} later HUD state(s) dropped; the overlay holds its last state`);
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
return keyframes;
|
|
409
|
+
}
|
|
410
|
+
//# sourceMappingURL=hud-state.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hud-state.js","sourceRoot":"","sources":["../../src/trailer/hud-state.ts"],"names":[],"mappings":"AAeA,OAAO,EAAE,kBAAkB,EAAE,sBAAsB,EAAE,MAAM,eAAe,CAAC;AAE3E,OAAO,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AAE/B;;;;GAIG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAAwB,IAAI,GAAG,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC;AAsDhF,8EAA8E;AAC9E,WAAW;AACX,8EAA8E;AAE9E,0DAA0D;AAC1D,MAAM,CAAC,MAAM,eAAe,GAAG,EAAE,CAAC;AAClC,6CAA6C;AAC7C,MAAM,CAAC,MAAM,gBAAgB,GAAG,IAAI,CAAC;AACrC,2EAA2E;AAC3E,MAAM,cAAc,GAAmC;IACrD,QAAQ,EAAE,UAAU;IACpB,OAAO,EAAE,WAAW;IACpB,WAAW,EAAE,aAAa;IAC1B,KAAK,EAAE,YAAY;IACnB,MAAM,EAAE,UAAU;CACnB,CAAC;AACF,gFAAgF;AAChF,MAAM,gBAAgB,GAAG,CAAC,CAAC;AAE3B,8EAA8E;AAC9E,YAAY;AACZ,8EAA8E;AAE9E,SAAS,UAAU,CAAC,MAA+B,EAAE,GAAW;IAC9D,MAAM,KAAK,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC;IAC1B,OAAO,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC;AACvD,CAAC;AAED,SAAS,UAAU,CAAC,MAA+B,EAAE,GAAW;IAC9D,MAAM,KAAK,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC;IAC1B,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC;AACjF,CAAC;AAED,SAAS,WAAW,CAAC,MAA+B,EAAE,GAAW;IAC/D,MAAM,KAAK,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC;IAC1B,OAAO,OAAO,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC;AACxD,CAAC;AAED,SAAS,KAAK,CAAC,KAAa;IAC1B,MAAM,MAAM,GAAG,EAAE,IAAI,gBAAgB,CAAC;IACtC,OAAO,IAAI,CAAC,KAAK,CAAC,KAAK,GAAG,MAAM,CAAC,GAAG,MAAM,CAAC;AAC7C,CAAC;AAsCD;;;;GAIG;AACH,MAAM,UAAU;IACG,GAAG,CAAU;IACb,GAAG,CAAS;IACrB,MAAM,GAAG,CAAC,CAAC;IACX,UAAU,GAAG,IAAI,CAAC;IAClB,MAAM,GAA0B,IAAI,CAAC;IACrC,KAAK,GAAY,IAAI,CAAC;IACb,QAAQ,GAAqB,EAAE,CAAC;IACzC,MAAM,GAAkB,EAAE,CAAC;IAEnC,YAAY,GAAqB,EAAE,GAAW;QAC5C,uEAAuE;QACvE,gDAAgD;QAChD,IAAI,CAAC,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC;QACtD,IAAI,CAAC,GAAG,GAAG,GAAG,CAAC;IACjB,CAAC;IAED,yEAAyE;IACzE,SAAS,CAAC,KAAa;QACrB,OAAO,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,MAAM,IAAI,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,KAAK,IAAI,KAAK,EAAE,CAAC;YAC7E,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC;YAClC,IAAI,CAAC,MAAM,EAAE,CAAC;QAChB,CAAC;IACH,CAAC;IAEO,IAAI,CAAC,EAAU;QACrB,OAAO,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC;IAClD,CAAC;IAEO,KAAK,CAAC,EAAS;QACrB,gEAAgE;QAChE,IAAI,IAAI,IAAI,EAAE,IAAI,kBAAkB,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC;YAAE,OAAO;QACxD,QAAQ,EAAE,CAAC,EAAE,EAAE,CAAC;YACd,KAAK,QAAQ;gBACX,IAAI,CAAC,WAAW,CAAC,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,CAAC;gBACxD,MAAM;YACR,KAAK,QAAQ;gBACX,IAAI,CAAC,WAAW,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,OAAO,CAAC,CAAC;gBACtD,MAAM;YACR,KAAK,aAAa,CAAC,CAAC,CAAC;gBACnB,MAAM,EAAE,GAAG,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;gBAC5B,IAAI,EAAE,KAAK,SAAS;oBAAE,EAAE,CAAC,IAAI,GAAG,EAAE,CAAC,IAAI,CAAC;gBACxC,MAAM;YACR,CAAC;YACD,KAAK,OAAO;gBACV,IAAI,CAAC,UAAU,CAAC,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,MAAM,EAAE,EAAE,CAAC,OAAO,CAAC,CAAC;gBACxD,MAAM;YACR,KAAK,MAAM,CAAC;YACZ,KAAK,MAAM,CAAC,CAAC,CAAC;gBACZ,MAAM,EAAE,GAAG,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;gBAC5B,IAAI,EAAE,KAAK,SAAS;oBAAE,EAAE,CAAC,OAAO,GAAG,EAAE,CAAC,EAAE,KAAK,MAAM,CAAC;gBACpD,MAAM;YACR,CAAC;YACD,KAAK,QAAQ,CAAC,CAAC,CAAC;gBACd,MAAM,KAAK,GAAG,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC,CAAC;gBAC/D,IAAI,KAAK,IAAI,CAAC;oBAAE,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;gBAC/C,MAAM;YACR,CAAC;YACD,KAAK,QAAQ;gBACX,IAAI,CAAC,MAAM,GAAG,EAAE,OAAO,EAAE,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE,EAAE,CAAC,GAAG,EAAE,OAAO,EAAE,IAAI,CAAC,MAAM,EAAE,OAAO,IAAI,KAAK,EAAE,CAAC;gBAC3F,MAAM;YACR,KAAK,gBAAgB;gBACnB,IAAI,CAAC,MAAM,GAAG;oBACZ,OAAO,EAAE,IAAI,CAAC,MAAM,EAAE,OAAO,IAAI,CAAC;oBAClC,GAAG,EAAE,IAAI,CAAC,MAAM,EAAE,GAAG,IAAI,GAAG;oBAC5B,OAAO,EAAE,EAAE,CAAC,OAAO;iBACpB,CAAC;gBACF,MAAM;YACR,KAAK,OAAO,CAAC,CAAC,CAAC;gBACb,MAAM,UAAU,GAAG,EAAE,CAAC,UAAU,IAAI,gBAAgB,CAAC;gBACrD,MAAM,KAAK,GAAgB;oBACzB,OAAO,EAAE,EAAE,CAAC,OAAO;oBACnB,UAAU,EAAE,EAAE,CAAC,KAAK;oBACpB,QAAQ,EAAE,EAAE,CAAC,KAAK,GAAG,CAAC,UAAU,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG;iBACpD,CAAC;gBACF,IAAI,EAAE,CAAC,OAAO,KAAK,SAAS;oBAAE,KAAK,CAAC,OAAO,GAAG,EAAE,CAAC,OAAO,CAAC;gBACzD,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;gBACxB,MAAM;YACR,CAAC;YACD,KAAK,aAAa;gBAChB,IAAI,CAAC,UAAU,GAAG,EAAE,CAAC,OAAO,CAAC;gBAC7B,MAAM;YACR,KAAK,OAAO;gBACV,IAAI,CAAC,KAAK,GAAG,EAAE,CAAC,KAAK,CAAC;gBACtB,MAAM;YACR;gBACE,gEAAgE;gBAChE,MAAM;QACV,CAAC;IACH,CAAC;IAEO,WAAW,CACjB,KAAa,EACb,EAAU,EACV,MAAsB,EACtB,MAA+B;QAE/B,yEAAyE;QACzE,uCAAuC;QACvC,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC;QAC/D,IAAI,QAAQ,IAAI,CAAC;YAAE,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC;QAErD,MAAM,EAAE,GAAmB;YACzB,EAAE;YACF,IAAI,EAAE,MAAM;YACZ,MAAM,EAAE,UAAU,CAAC,MAAM,EAAE,QAAQ,CAAC,IAAI,cAAc,CAAC,MAAM,CAAC,IAAI,UAAU;YAC5E,OAAO,EAAE,IAAI;SACd,CAAC;QACF,MAAM,KAAK,GAAG,UAAU,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QAC1C,MAAM,KAAK,GAAG,UAAU,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QAC1C,MAAM,KAAK,GAAG,UAAU,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QAC1C,MAAM,QAAQ,GAAG,WAAW,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;QACjD,MAAM,OAAO,GAAG,UAAU,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;QAC9C,MAAM,IAAI,GAAG,UAAU,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QACxC,MAAM,IAAI,GAAG,UAAU,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QACxC,MAAM,QAAQ,GAAG,UAAU,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;QAChD,MAAM,SAAS,GAAG,WAAW,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;QACnD,MAAM,MAAM,GAAG,UAAU,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;QAC5C,MAAM,IAAI,GAAG,UAAU,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QACxC,MAAM,GAAG,GAAG,UAAU,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;QACtC,IAAI,KAAK,KAAK,SAAS;YAAE,EAAE,CAAC,KAAK,GAAG,KAAK,CAAC;QAC1C,IAAI,KAAK,KAAK,SAAS;YAAE,EAAE,CAAC,KAAK,GAAG,KAAK,CAAC;QAC1C,IAAI,KAAK,KAAK,SAAS;YAAE,EAAE,CAAC,KAAK,GAAG,KAAK,CAAC;QAC1C,IAAI,QAAQ,KAAK,SAAS;YAAE,EAAE,CAAC,QAAQ,GAAG,QAAQ,CAAC;QACnD,IAAI,OAAO,KAAK,SAAS;YAAE,EAAE,CAAC,OAAO,GAAG,OAAO,CAAC;QAChD,IAAI,IAAI,KAAK,SAAS;YAAE,EAAE,CAAC,IAAI,GAAG,IAAI,CAAC;QACvC,IAAI,IAAI,KAAK,SAAS;YAAE,EAAE,CAAC,IAAI,GAAG,IAAI,CAAC;QACvC,IAAI,QAAQ,KAAK,SAAS;YAAE,EAAE,CAAC,QAAQ,GAAG,QAAQ,CAAC;QACnD,IAAI,SAAS,KAAK,SAAS;YAAE,EAAE,CAAC,SAAS,GAAG,SAAS,CAAC;QACtD,IAAI,MAAM,KAAK,SAAS;YAAE,EAAE,CAAC,MAAM,GAAG,MAAM,CAAC;QAC7C,IAAI,IAAI,KAAK,SAAS;YAAE,EAAE,CAAC,IAAI,GAAG,IAAI,CAAC;QACvC,IAAI,GAAG,KAAK,SAAS;YAAE,EAAE,CAAC,GAAG,GAAG,GAAG,CAAC;QAEpC,IAAI,MAAM,KAAK,OAAO,EAAE,CAAC;YACvB,MAAM,OAAO,GAAG,UAAU,CAAC,MAAM,EAAE,SAAS,CAAC,IAAI,CAAC,CAAC;YACnD,EAAE,CAAC,KAAK,GAAG,EAAE,aAAa,EAAE,OAAO,EAAE,WAAW,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,aAAa,EAAE,OAAO,EAAE,CAAC;QACpG,CAAC;QACD,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACzB,CAAC;IAEO,WAAW,CAAC,EAAU,EAAE,IAAa,EAAE,IAAa,EAAE,OAAgB;QAC5E,MAAM,EAAE,GAAG,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACzB,IAAI,EAAE,KAAK,SAAS;YAAE,OAAO,CAAC,6BAA6B;QAC3D,IAAI,IAAI,KAAK,SAAS;YAAE,EAAE,CAAC,IAAI,GAAG,IAAI,CAAC;QACvC,IAAI,IAAI,KAAK,SAAS;YAAE,EAAE,CAAC,IAAI,GAAG,IAAI,CAAC;QACvC,IAAI,OAAO,KAAK,SAAS;YAAE,EAAE,CAAC,OAAO,GAAG,OAAO,CAAC;IAClD,CAAC;IAEO,UAAU,CAChB,KAAa,EACb,EAAU,EACV,MAAmC,EACnC,OAA2B;QAE3B,MAAM,EAAE,GAAG,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACzB,MAAM,KAAK,GAAG,EAAE,EAAE,KAAK,CAAC;QACxB,IAAI,EAAE,KAAK,SAAS,IAAI,KAAK,KAAK,SAAS;YAAE,OAAO;QACpD,QAAQ,MAAM,EAAE,CAAC;YACf,KAAK,OAAO;gBACV,KAAK,CAAC,aAAa,GAAG,OAAO,IAAI,cAAc,CAAC,KAAK,EAAE,KAAK,EAAE,EAAE,CAAC,SAAS,IAAI,KAAK,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC;gBAC/F,KAAK,CAAC,WAAW,GAAG,KAAK,CAAC;gBAC1B,KAAK,CAAC,OAAO,GAAG,IAAI,CAAC;gBACrB,MAAM;YACR,KAAK,OAAO;gBACV,KAAK,CAAC,aAAa,GAAG,cAAc,CAAC,KAAK,EAAE,KAAK,EAAE,EAAE,CAAC,SAAS,IAAI,KAAK,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC;gBACpF,KAAK,CAAC,WAAW,GAAG,KAAK,CAAC;gBAC1B,KAAK,CAAC,OAAO,GAAG,KAAK,CAAC;gBACtB,MAAM;YACR,KAAK,OAAO;gBACV,KAAK,CAAC,aAAa,GAAG,OAAO,IAAI,KAAK,CAAC,aAAa,CAAC;gBACrD,KAAK,CAAC,WAAW,GAAG,KAAK,CAAC;gBAC1B,KAAK,CAAC,OAAO,GAAG,KAAK,CAAC;gBACtB,MAAM;QACV,CAAC;IACH,CAAC;IAED,yEAAyE;IACzE,QAAQ,CAAC,KAAa;QACpB,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,GAAG,KAAK,CAAC,CAAC;QAC5D,OAAO;YACL,OAAO,EAAE,CAAC;YACV,UAAU,EAAE,IAAI,CAAC,UAAU;YAC3B,MAAM,EAAE,IAAI,CAAC,MAAM,KAAK,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,GAAG,IAAI,CAAC,MAAM,EAAE;YACxD,KAAK,EAAE,IAAI,CAAC,KAAK;YACjB,QAAQ,EAAE,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,WAAW,CAAC,EAAE,EAAE,KAAK,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC;YACrE,MAAM,EAAE,IAAI,CAAC,MAAM;iBAChB,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,UAAU,IAAI,KAAK,CAAC;iBACpC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,OAAO,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC,OAAO,EAAE,OAAO,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC;SAC/G,CAAC;IACJ,CAAC;CACF;AAED,SAAS,cAAc,CAAC,KAAmB,EAAE,KAAa,EAAE,SAAkB,EAAE,GAAW;IACzF,IAAI,CAAC,KAAK,CAAC,OAAO;QAAE,OAAO,KAAK,CAAC,aAAa,CAAC;IAC/C,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,GAAG,KAAK,CAAC,WAAW,CAAC,GAAG,GAAG,CAAC;IAC7D,OAAO,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,CAAC,aAAa,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,aAAa,GAAG,OAAO,CAAC;AAChG,CAAC;AAED,iFAAiF;AACjF,SAAS,WAAW,CAAC,EAAkB,EAAE,KAAa,EAAE,GAAW;IACjE,MAAM,KAAK,GAAoB,EAAE,EAAE,EAAE,EAAE,CAAC,EAAE,EAAE,IAAI,EAAE,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,CAAC,MAAM,EAAE,OAAO,EAAE,EAAE,CAAC,OAAO,EAAE,CAAC;IACpG,IAAI,EAAE,CAAC,KAAK,KAAK,SAAS;QAAE,KAAK,CAAC,KAAK,GAAG,EAAE,CAAC,KAAK,CAAC;IACnD,IAAI,EAAE,CAAC,KAAK,KAAK,SAAS;QAAE,KAAK,CAAC,KAAK,GAAG,EAAE,CAAC,KAAK,CAAC;IACnD,IAAI,EAAE,CAAC,KAAK,KAAK,SAAS;QAAE,KAAK,CAAC,KAAK,GAAG,EAAE,CAAC,KAAK,CAAC;IACnD,IAAI,EAAE,CAAC,QAAQ,KAAK,SAAS;QAAE,KAAK,CAAC,QAAQ,GAAG,EAAE,CAAC,QAAQ,CAAC;IAC5D,IAAI,EAAE,CAAC,OAAO,KAAK,SAAS;QAAE,KAAK,CAAC,OAAO,GAAG,EAAE,CAAC,OAAO,CAAC;IACzD,IAAI,EAAE,CAAC,IAAI,KAAK,SAAS;QAAE,KAAK,CAAC,IAAI,GAAG,EAAE,CAAC,IAAI,CAAC;IAChD,IAAI,EAAE,CAAC,IAAI,KAAK,SAAS;QAAE,KAAK,CAAC,IAAI,GAAG,EAAE,CAAC,IAAI,CAAC;IAChD,IAAI,EAAE,CAAC,QAAQ,KAAK,SAAS;QAAE,KAAK,CAAC,QAAQ,GAAG,EAAE,CAAC,QAAQ,CAAC;IAC5D,IAAI,EAAE,CAAC,KAAK,KAAK,SAAS;QAAE,KAAK,CAAC,OAAO,GAAG,KAAK,CAAC,cAAc,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,EAAE,CAAC,SAAS,IAAI,KAAK,EAAE,GAAG,CAAC,CAAC,CAAC;IAC/G,IAAI,EAAE,CAAC,SAAS,KAAK,SAAS;QAAE,KAAK,CAAC,SAAS,GAAG,EAAE,CAAC,SAAS,CAAC;IAC/D,IAAI,EAAE,CAAC,MAAM,KAAK,SAAS;QAAE,KAAK,CAAC,MAAM,GAAG,EAAE,CAAC,MAAM,CAAC;IACtD,IAAI,EAAE,CAAC,IAAI,KAAK,SAAS;QAAE,KAAK,CAAC,IAAI,GAAG,EAAE,CAAC,IAAI,CAAC;IAChD,IAAI,EAAE,CAAC,GAAG,KAAK,SAAS;QAAE,KAAK,CAAC,GAAG,GAAG,EAAE,CAAC,GAAG,CAAC;IAC7C,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,cAAc,CAC5B,GAAqB,EACrB,KAAa,EACb,MAAc,eAAe;IAE7B,MAAM,OAAO,GAAG,IAAI,UAAU,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;IACzC,OAAO,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;IACzB,OAAO,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;AACjC,CAAC;AAED,sEAAsE;AACtE,MAAM,UAAU,eAAe,CAAC,KAAqB;IACnD,IAAI,CAAC,KAAK,CAAC,UAAU;QAAE,OAAO,IAAI,CAAC;IACnC,IAAI,KAAK,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC;QAAE,OAAO,KAAK,CAAC;IAC1C,IAAI,KAAK,CAAC,MAAM,KAAK,IAAI,IAAI,KAAK,CAAC,MAAM,CAAC,OAAO;QAAE,OAAO,KAAK,CAAC;IAChE,OAAO,CAAC,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC;AAClD,CAAC;AA8BD,MAAM,CAAC,MAAM,gCAAgC,GAAG,EAAE,CAAC;AACnD,MAAM,CAAC,MAAM,8BAA8B,GAAG,GAAG,CAAC;AAClD;;;;GAIG;AACH,MAAM,eAAe,GAAG,IAAI,CAAC;AAE7B;;;;GAIG;AACH,SAAS,QAAQ,CAAC,KAAqB;IACrC,OAAO,IAAI,CAAC,SAAS,CAAC;QACpB,GAAG,KAAK;QACR,QAAQ,EAAE,KAAK,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,CAClC,EAAE,CAAC,OAAO,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,EAAE,OAAO,EAAE,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC;KAC9E,CAAC,CAAC;AACL,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,kBAAkB,CAChC,GAAqB,EACrB,KAA4B,EAC5B,OAAkC,EAAE;IAEpC,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,IAAI,eAAe,CAAC;IACxC,MAAM,YAAY,GAAG,IAAI,CAAC,YAAY,IAAI,gCAAgC,CAAC;IAC3E,MAAM,UAAU,GAAG,IAAI,CAAC,UAAU,IAAI,8BAA8B,CAAC;IACrE,MAAM,WAAW,GAAG,IAAI,CAAC,WAAW,IAAI,CAAC,GAAY,EAAE,CAAC,IAAI,CAAC,CAAC;IAC9D,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,IAAI,IAAI,CAAC;IAC7B,MAAM,aAAa,GAAG,YAAY,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC;IAE9D,MAAM,SAAS,GAAiB,EAAE,CAAC;IACnC,KAAK,IAAI,KAAK,GAAG,CAAC,EAAE,KAAK,GAAG,KAAK,CAAC,MAAM,EAAE,KAAK,EAAE,EAAE,CAAC;QAClD,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC;YAAE,SAAS;QAClC,MAAM,MAAM,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC;QAC5B,MAAM,SAAS,GAAG,kBAAkB,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;QACnD,MAAM,OAAO,GAAG,IAAI,UAAU,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;QAEzC,MAAM,UAAU,GAAiB,EAAE,CAAC;QACpC,IAAI,cAAc,GAAkB,IAAI,CAAC;QACzC,IAAI,cAAc,GAAG,MAAM,CAAC,iBAAiB,CAAC;QAC9C,sEAAsE;QACtE,IAAI,UAAU,GAAkB,IAAI,CAAC;QACrC,IAAI,SAAS,GAAG,CAAC,CAAC;QAClB,IAAI,YAAY,GAAG,CAAC,CAAC;QACrB,IAAI,MAAM,GAAG,KAAK,CAAC;QACnB,IAAI,iBAAiB,GAAG,CAAC,CAAC,CAAC;QAE3B,KAAK,IAAI,KAAK,GAAG,MAAM,CAAC,EAAE,EAAE,KAAK,GAAG,MAAM,CAAC,GAAG,EAAE,KAAK,EAAE,EAAE,CAAC;YACxD,MAAM,SAAS,GAAG,sBAAsB,CAAC,MAAM,EAAE,KAAK,EAAE,GAAG,CAAC,CAAC;YAC7D,IAAI,SAAS,IAAI,SAAS;gBAAE,MAAM;YAClC,OAAO,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;YACzB,MAAM,KAAK,GAAG,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;YACtC,MAAM,GAAG,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;YAC5B,IAAI,GAAG,KAAK,cAAc;gBAAE,SAAS;YAErC,IAAI,UAAU,CAAC,MAAM,IAAI,UAAU,EAAE,CAAC;gBACpC,IAAI,UAAU,KAAK,IAAI,IAAI,UAAU,KAAK,GAAG;oBAAE,YAAY,EAAE,CAAC;gBAC9D,IAAI,CAAC,MAAM;oBAAE,iBAAiB,GAAG,KAAK,CAAC;gBACvC,MAAM,GAAG,IAAI,CAAC;gBACd,UAAU,GAAG,GAAG,CAAC;gBACjB,SAAS;YACX,CAAC;YACD,IAAI,SAAS,GAAG,cAAc,GAAG,aAAa,GAAG,eAAe,EAAE,CAAC;gBACjE,qEAAqE;gBACrE,IAAI,UAAU,KAAK,IAAI,IAAI,UAAU,KAAK,GAAG;oBAAE,SAAS,EAAE,CAAC;gBAC3D,UAAU,GAAG,GAAG,CAAC;gBACjB,SAAS;YACX,CAAC;YAED,IAAI,UAAU,KAAK,IAAI,IAAI,UAAU,KAAK,GAAG;gBAAE,SAAS,EAAE,CAAC;YAC3D,UAAU,CAAC,IAAI,CAAC;gBACd,WAAW,EAAE,KAAK;gBAClB,SAAS,EAAE,KAAK;gBAChB,cAAc,EAAE,SAAS;gBACzB,YAAY,EAAE,SAAS;gBACvB,KAAK;aACN,CAAC,CAAC;YACH,cAAc,GAAG,GAAG,CAAC;YACrB,cAAc,GAAG,SAAS,CAAC;YAC3B,UAAU,GAAG,IAAI,CAAC;QACpB,CAAC;QACD,yEAAyE;QACzE,IAAI,UAAU,KAAK,IAAI,EAAE,CAAC;YACxB,IAAI,MAAM;gBAAE,YAAY,EAAE,CAAC;;gBACtB,SAAS,EAAE,CAAC;QACnB,CAAC;QAED,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,UAAU,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;YAC/C,UAAU,CAAC,CAAC,CAAC,CAAC,YAAY,GAAG,UAAU,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,cAAc,CAAC;QAChE,CAAC;QACD,SAAS,CAAC,IAAI,CAAC,GAAG,UAAU,CAAC,CAAC;QAE9B,IAAI,SAAS,GAAG,CAAC,EAAE,CAAC;YAClB,GAAG,CACD,YAAY,KAAK,oBAAoB,YAAY,kCAAkC;gBACjF,GAAG,SAAS,2CAA2C,CAC1D,CAAC;QACJ,CAAC;QACD,IAAI,YAAY,GAAG,CAAC,EAAE,CAAC;YACrB,GAAG,CACD,YAAY,KAAK,YAAY,UAAU,iCAAiC,iBAAiB,KAAK;gBAC5F,GAAG,YAAY,+DAA+D,CACjF,CAAC;QACJ,CAAC;IACH,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Where the compositor's words go.
|
|
3
|
+
*
|
|
4
|
+
* The trailer modules narrate as they work — windows scored, overlays rasterized, the render
|
|
5
|
+
* summary — and under `--json` every one of those lines must land on stderr, because stdout is
|
|
6
|
+
* reserved for the single result document (`output.ts`). The modules cannot know which mode the
|
|
7
|
+
* command runs in, so the command binds the Output seam here first and everything below it
|
|
8
|
+
* writes through `out`/`warn` without caring.
|
|
9
|
+
*
|
|
10
|
+
* Unbound (a test, or a module used as a library) both go to stderr: never stdout, so nothing here
|
|
11
|
+
* can corrupt a result by accident.
|
|
12
|
+
*/
|
|
13
|
+
export interface TrailerLog {
|
|
14
|
+
info(line: string): void;
|
|
15
|
+
warn(line: string): void;
|
|
16
|
+
}
|
|
17
|
+
/** The command layer calls this once with `createOutput(json)` before running any pipeline step. */
|
|
18
|
+
export declare function bindTrailerLog(log: TrailerLog): void;
|
|
19
|
+
export declare function out(line: string): void;
|
|
20
|
+
export declare function warn(line: string): void;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
let bound = {
|
|
2
|
+
info: (line) => process.stderr.write(`${line}\n`),
|
|
3
|
+
warn: (line) => process.stderr.write(`${line}\n`),
|
|
4
|
+
};
|
|
5
|
+
/** The command layer calls this once with `createOutput(json)` before running any pipeline step. */
|
|
6
|
+
export function bindTrailerLog(log) {
|
|
7
|
+
bound = log;
|
|
8
|
+
}
|
|
9
|
+
export function out(line) {
|
|
10
|
+
bound.info(line);
|
|
11
|
+
}
|
|
12
|
+
export function warn(line) {
|
|
13
|
+
bound.warn(line);
|
|
14
|
+
}
|
|
15
|
+
//# sourceMappingURL=io.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"io.js","sourceRoot":"","sources":["../../src/trailer/io.ts"],"names":[],"mappings":"AAiBA,IAAI,KAAK,GAAe;IACtB,IAAI,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,IAAI,IAAI,CAAC;IACjD,IAAI,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,IAAI,IAAI,CAAC;CAClD,CAAC;AAEF,oGAAoG;AACpG,MAAM,UAAU,cAAc,CAAC,GAAe;IAC5C,KAAK,GAAG,GAAG,CAAC;AACd,CAAC;AAED,MAAM,UAAU,GAAG,CAAC,IAAY;IAC9B,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACnB,CAAC;AAED,MAAM,UAAU,IAAI,CAAC,IAAY;IAC/B,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACnB,CAAC"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
export declare const DEFAULT_TRAILER_SECONDS = 30;
|
|
2
|
+
/** Music runs a little past the cut so the fade-out has material. */
|
|
3
|
+
export declare const MUSIC_TAIL_SEC = 4;
|
|
4
|
+
/** The render's music/SFX balance the make-trailer skill settled on. */
|
|
5
|
+
export declare const MAKE_MUSIC_GAIN_DB = -4;
|
|
6
|
+
export declare const MAKE_SFX_GAIN_DB = -3;
|
|
7
|
+
export interface TrailerPublished {
|
|
8
|
+
publicUrl: string;
|
|
9
|
+
pageUrl?: string;
|
|
10
|
+
attached: boolean;
|
|
11
|
+
}
|
|
12
|
+
export interface MakeOptions {
|
|
13
|
+
root: string;
|
|
14
|
+
/** A finished recording dir (see paths.resolveRecording). */
|
|
15
|
+
recordingDir: string;
|
|
16
|
+
/** A music file to bed under the cut. */
|
|
17
|
+
music?: string;
|
|
18
|
+
/** Generate the bed from this prompt through `generateMusic`. */
|
|
19
|
+
musicPrompt?: string;
|
|
20
|
+
/** Target length including the end card. */
|
|
21
|
+
seconds?: number;
|
|
22
|
+
/** End-card text; defaults to the game's name. */
|
|
23
|
+
title?: string;
|
|
24
|
+
sub?: string;
|
|
25
|
+
/** Draw the HUD replay (needs `harnessUrl`). */
|
|
26
|
+
ui?: boolean;
|
|
27
|
+
/** `/hud-replay.html` on the running dev sidecar. */
|
|
28
|
+
harnessUrl?: string;
|
|
29
|
+
/** Throw away trailer/shots.json and write a fresh auto cut. */
|
|
30
|
+
resetShots?: boolean;
|
|
31
|
+
/** The music lane: write an mp3 of `seconds` for `prompt` at `outPath`. */
|
|
32
|
+
generateMusic?: (prompt: string, seconds: number, outPath: string) => Promise<void>;
|
|
33
|
+
/** The publish lane: upload the render and return where it went. */
|
|
34
|
+
publish?: (mp4: string) => Promise<TrailerPublished>;
|
|
35
|
+
}
|
|
36
|
+
export interface MakeResult {
|
|
37
|
+
recordingDir: string;
|
|
38
|
+
recordingName: string;
|
|
39
|
+
workDir: string;
|
|
40
|
+
analysisPath: string;
|
|
41
|
+
shotsPath: string;
|
|
42
|
+
/** Whether this run wrote the shots file (first cut) or cut an existing one. */
|
|
43
|
+
shotsWritten: boolean;
|
|
44
|
+
edlPath: string;
|
|
45
|
+
musicPath?: string;
|
|
46
|
+
beatsPath?: string;
|
|
47
|
+
mp4: string;
|
|
48
|
+
durationSec: number;
|
|
49
|
+
clipCount: number;
|
|
50
|
+
published?: TrailerPublished;
|
|
51
|
+
}
|
|
52
|
+
/** The game's name as the work copy knows it, for the end card and the file name. */
|
|
53
|
+
export declare function gameNameFor(root: string): string;
|
|
54
|
+
export declare function makeTrailer(options: MakeOptions): Promise<MakeResult>;
|