@bitmagic/asset-core 0.2.25-dev.0 → 0.2.25-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.
Files changed (89) hide show
  1. package/dist/trailer/analyze.d.ts +24 -0
  2. package/dist/trailer/analyze.d.ts.map +1 -0
  3. package/dist/trailer/analyze.js +186 -0
  4. package/dist/trailer/analyze.js.map +1 -0
  5. package/dist/trailer/auto-edl.d.ts +51 -0
  6. package/dist/trailer/auto-edl.d.ts.map +1 -0
  7. package/dist/trailer/auto-edl.js +266 -0
  8. package/dist/trailer/auto-edl.js.map +1 -0
  9. package/dist/trailer/beat-cut.d.ts +58 -0
  10. package/dist/trailer/beat-cut.d.ts.map +1 -0
  11. package/dist/trailer/beat-cut.js +232 -0
  12. package/dist/trailer/beat-cut.js.map +1 -0
  13. package/dist/trailer/capture.d.ts +102 -0
  14. package/dist/trailer/capture.d.ts.map +1 -0
  15. package/dist/trailer/capture.js +268 -0
  16. package/dist/trailer/capture.js.map +1 -0
  17. package/dist/trailer/edl-time.d.ts +62 -0
  18. package/dist/trailer/edl-time.d.ts.map +1 -0
  19. package/dist/trailer/edl-time.js +105 -0
  20. package/dist/trailer/edl-time.js.map +1 -0
  21. package/dist/trailer/errors.d.ts +15 -0
  22. package/dist/trailer/errors.d.ts.map +1 -0
  23. package/dist/trailer/errors.js +22 -0
  24. package/dist/trailer/errors.js.map +1 -0
  25. package/dist/trailer/ffmpeg.d.ts +19 -0
  26. package/dist/trailer/ffmpeg.d.ts.map +1 -0
  27. package/dist/trailer/ffmpeg.js +100 -0
  28. package/dist/trailer/ffmpeg.js.map +1 -0
  29. package/dist/trailer/hud-state.d.ts +182 -0
  30. package/dist/trailer/hud-state.d.ts.map +1 -0
  31. package/dist/trailer/hud-state.js +523 -0
  32. package/dist/trailer/hud-state.js.map +1 -0
  33. package/dist/trailer/index.d.ts +30 -0
  34. package/dist/trailer/index.d.ts.map +1 -0
  35. package/dist/trailer/index.js +30 -0
  36. package/dist/trailer/index.js.map +1 -0
  37. package/dist/trailer/io.d.ts +23 -0
  38. package/dist/trailer/io.d.ts.map +1 -0
  39. package/dist/trailer/io.js +20 -0
  40. package/dist/trailer/io.js.map +1 -0
  41. package/dist/trailer/link.d.ts +2 -0
  42. package/dist/trailer/link.d.ts.map +1 -0
  43. package/dist/trailer/link.js +15 -0
  44. package/dist/trailer/link.js.map +1 -0
  45. package/dist/trailer/make.d.ts +60 -0
  46. package/dist/trailer/make.d.ts.map +1 -0
  47. package/dist/trailer/make.js +196 -0
  48. package/dist/trailer/make.js.map +1 -0
  49. package/dist/trailer/merge.d.ts +8 -0
  50. package/dist/trailer/merge.d.ts.map +1 -0
  51. package/dist/trailer/merge.js +165 -0
  52. package/dist/trailer/merge.js.map +1 -0
  53. package/dist/trailer/music-beats.d.ts +124 -0
  54. package/dist/trailer/music-beats.d.ts.map +1 -0
  55. package/dist/trailer/music-beats.js +672 -0
  56. package/dist/trailer/music-beats.js.map +1 -0
  57. package/dist/trailer/paths.d.ts +29 -0
  58. package/dist/trailer/paths.d.ts.map +1 -0
  59. package/dist/trailer/paths.js +101 -0
  60. package/dist/trailer/paths.js.map +1 -0
  61. package/dist/trailer/png.d.ts +10 -0
  62. package/dist/trailer/png.d.ts.map +1 -0
  63. package/dist/trailer/png.js +37 -0
  64. package/dist/trailer/png.js.map +1 -0
  65. package/dist/trailer/render.d.ts +93 -0
  66. package/dist/trailer/render.d.ts.map +1 -0
  67. package/dist/trailer/render.js +527 -0
  68. package/dist/trailer/render.js.map +1 -0
  69. package/dist/trailer/revision.d.ts +9 -0
  70. package/dist/trailer/revision.d.ts.map +1 -0
  71. package/dist/trailer/revision.js +31 -0
  72. package/dist/trailer/revision.js.map +1 -0
  73. package/dist/trailer/synth.d.ts +10 -0
  74. package/dist/trailer/synth.d.ts.map +1 -0
  75. package/dist/trailer/synth.js +120 -0
  76. package/dist/trailer/synth.js.map +1 -0
  77. package/dist/trailer/timeline-types.d.ts +196 -0
  78. package/dist/trailer/timeline-types.d.ts.map +1 -0
  79. package/dist/trailer/timeline-types.js +419 -0
  80. package/dist/trailer/timeline-types.js.map +1 -0
  81. package/dist/trailer/titles.d.ts +38 -0
  82. package/dist/trailer/titles.d.ts.map +1 -0
  83. package/dist/trailer/titles.js +110 -0
  84. package/dist/trailer/titles.js.map +1 -0
  85. package/dist/trailer/video-chain.d.ts +130 -0
  86. package/dist/trailer/video-chain.d.ts.map +1 -0
  87. package/dist/trailer/video-chain.js +261 -0
  88. package/dist/trailer/video-chain.js.map +1 -0
  89. package/package.json +5 -1
@@ -0,0 +1,419 @@
1
+ /**
2
+ * Stable JSON contracts for the trailer pipeline plus validating loaders.
3
+ *
4
+ * timeline.json / edl.json are inputs written by the game engine and an AI
5
+ * editor respectively; analysis.json is our output. Loaders validate with
6
+ * type guards and throw descriptive errors — never silently coerce.
7
+ */
8
+ import * as fs from 'fs';
9
+ import * as path from 'path';
10
+ import { TrailerError } from './errors.js';
11
+ import { warn } from './io.js';
12
+ // ---------------------------------------------------------------------------
13
+ // Frame file naming
14
+ // ---------------------------------------------------------------------------
15
+ export function frameFileName(recordingName, frame) {
16
+ return `${recordingName}_${String(frame).padStart(6, '0')}.png`;
17
+ }
18
+ export function frameFilePath(recordingDir, recordingName, frame) {
19
+ return path.join(recordingDir, frameFileName(recordingName, frame));
20
+ }
21
+ // ---------------------------------------------------------------------------
22
+ // Validation helpers
23
+ // ---------------------------------------------------------------------------
24
+ function isRecord(value) {
25
+ return typeof value === 'object' && value !== null && !Array.isArray(value);
26
+ }
27
+ function asNumber(value, ctx) {
28
+ if (typeof value !== 'number' || !Number.isFinite(value)) {
29
+ throw new Error(`${ctx}: expected a finite number, got ${JSON.stringify(value)}`);
30
+ }
31
+ return value;
32
+ }
33
+ function asString(value, ctx) {
34
+ if (typeof value !== 'string' || value.length === 0) {
35
+ throw new Error(`${ctx}: expected a non-empty string, got ${JSON.stringify(value)}`);
36
+ }
37
+ return value;
38
+ }
39
+ function parseNumOrRamp(value, ctx) {
40
+ if (typeof value === 'number' && Number.isFinite(value))
41
+ return value;
42
+ if (Array.isArray(value) && value.length === 2) {
43
+ const [a, b] = value;
44
+ if (typeof a === 'number' && Number.isFinite(a) && typeof b === 'number' && Number.isFinite(b)) {
45
+ return [a, b];
46
+ }
47
+ }
48
+ throw new Error(`${ctx}: expected a number or a [start, end] pair`);
49
+ }
50
+ function readJson(filePath) {
51
+ if (!fs.existsSync(filePath))
52
+ throw new TrailerError(`File not found: ${filePath}`);
53
+ const text = fs.readFileSync(filePath, 'utf-8');
54
+ try {
55
+ return JSON.parse(text);
56
+ }
57
+ catch (err) {
58
+ throw new TrailerError(`Invalid JSON in ${filePath}: ${err instanceof Error ? err.message : String(err)}`);
59
+ }
60
+ }
61
+ // ---------------------------------------------------------------------------
62
+ // timeline.json parsing
63
+ // ---------------------------------------------------------------------------
64
+ const SYNTH_WAVES = ['sine', 'square', 'sawtooth', 'triangle', 'noise'];
65
+ function isSynthWave(value) {
66
+ return typeof value === 'string' && SYNTH_WAVES.includes(value);
67
+ }
68
+ export function parseRecipe(raw, ctx) {
69
+ if (!isRecord(raw))
70
+ throw new Error(`${ctx}: expected an object`);
71
+ const dur = asNumber(raw.dur, `${ctx}.dur`);
72
+ if (dur <= 0)
73
+ throw new Error(`${ctx}.dur: must be > 0, got ${dur}`);
74
+ if (!Array.isArray(raw.layers) || raw.layers.length === 0) {
75
+ throw new Error(`${ctx}.layers: expected a non-empty array`);
76
+ }
77
+ const layers = raw.layers.map((layerRaw, i) => parseLayer(layerRaw, `${ctx}.layers[${i}]`));
78
+ return { dur, layers };
79
+ }
80
+ function parseLayer(raw, ctx) {
81
+ if (!isRecord(raw))
82
+ throw new Error(`${ctx}: expected an object`);
83
+ if (!isSynthWave(raw.wave)) {
84
+ throw new Error(`${ctx}.wave: expected one of ${SYNTH_WAVES.join(', ')}, got ${JSON.stringify(raw.wave)}`);
85
+ }
86
+ const layer = { wave: raw.wave };
87
+ if (raw.freq !== undefined)
88
+ layer.freq = parseNumOrRamp(raw.freq, `${ctx}.freq`);
89
+ if (raw.gain !== undefined)
90
+ layer.gain = parseNumOrRamp(raw.gain, `${ctx}.gain`);
91
+ return layer;
92
+ }
93
+ function parseEvent(raw, ctx) {
94
+ if (!isRecord(raw))
95
+ throw new Error(`${ctx}: expected an object`);
96
+ const event = {
97
+ frame: asNumber(raw.frame, `${ctx}.frame`),
98
+ type: asString(raw.type, `${ctx}.type`)
99
+ };
100
+ if (raw.intensity !== undefined)
101
+ event.intensity = asNumber(raw.intensity, `${ctx}.intensity`);
102
+ if (Array.isArray(raw.position) && raw.position.every((v) => typeof v === 'number')) {
103
+ event.position = raw.position;
104
+ }
105
+ if (typeof raw.actor === 'string')
106
+ event.actor = raw.actor;
107
+ if (isRecord(raw.data))
108
+ event.data = raw.data;
109
+ return event;
110
+ }
111
+ function parseSound(raw, ctx) {
112
+ if (!isRecord(raw))
113
+ throw new Error(`${ctx}: expected an object`);
114
+ const frame = asNumber(raw.frame, `${ctx}.frame`);
115
+ const volume = raw.volume !== undefined ? asNumber(raw.volume, `${ctx}.volume`) : undefined;
116
+ if (raw.kind === 'asset') {
117
+ const sound = {
118
+ frame,
119
+ kind: 'asset',
120
+ assetId: asString(raw.assetId, `${ctx}.assetId`),
121
+ url: asString(raw.url, `${ctx}.url`)
122
+ };
123
+ if (volume !== undefined)
124
+ sound.volume = volume;
125
+ return sound;
126
+ }
127
+ if (raw.kind === 'synth') {
128
+ const sound = {
129
+ frame,
130
+ kind: 'synth',
131
+ recipe: parseRecipe(raw.recipe, `${ctx}.recipe`)
132
+ };
133
+ if (typeof raw.name === 'string')
134
+ sound.name = raw.name;
135
+ if (volume !== undefined)
136
+ sound.volume = volume;
137
+ return sound;
138
+ }
139
+ throw new Error(`${ctx}.kind: expected "asset" or "synth", got ${JSON.stringify(raw.kind)}`);
140
+ }
141
+ const HUD_ELEMENT_KINDS = ['counter', 'progress', 'icon-text', 'timer', 'custom'];
142
+ function isHudElementKind(value) {
143
+ return typeof value === 'string' && HUD_ELEMENT_KINDS.includes(value);
144
+ }
145
+ function optString(value) {
146
+ return typeof value === 'string' ? value : undefined;
147
+ }
148
+ function optFiniteNumber(value) {
149
+ return typeof value === 'number' && Number.isFinite(value) ? value : undefined;
150
+ }
151
+ /**
152
+ * Parse one hud[] entry. Returns null for a malformed entry or an op name this
153
+ * build predates — the track is forward-compatible by design, so an unknown op
154
+ * is skipped (and counted by the caller), never fatal.
155
+ */
156
+ function parseHudOp(raw) {
157
+ if (!isRecord(raw))
158
+ return null;
159
+ const frame = optFiniteNumber(raw.frame);
160
+ if (frame === undefined)
161
+ return null;
162
+ const id = optString(raw.id);
163
+ switch (raw.op) {
164
+ case 'create': {
165
+ if (id === undefined || !isHudElementKind(raw.elType))
166
+ return null;
167
+ return { frame, op: 'create', id, elType: raw.elType, params: isRecord(raw.params) ? raw.params : {} };
168
+ }
169
+ case 'update': {
170
+ if (id === undefined)
171
+ return null;
172
+ const op = { frame, op: 'update', id };
173
+ const text = optString(raw.text);
174
+ const icon = optString(raw.icon);
175
+ const percent = optFiniteNumber(raw.percent);
176
+ if (text !== undefined)
177
+ op.text = text;
178
+ if (icon !== undefined)
179
+ op.icon = icon;
180
+ if (percent !== undefined)
181
+ op.percent = percent;
182
+ return op;
183
+ }
184
+ case 'custom-html': {
185
+ const html = optString(raw.html);
186
+ if (id === undefined || html === undefined)
187
+ return null;
188
+ const op = { frame, op: 'custom-html', id, html };
189
+ const css = optString(raw.css);
190
+ if (css !== undefined)
191
+ op.css = css;
192
+ return op;
193
+ }
194
+ case 'timer': {
195
+ if (id === undefined)
196
+ return null;
197
+ if (raw.action !== 'start' && raw.action !== 'pause' && raw.action !== 'reset')
198
+ return null;
199
+ const op = { frame, op: 'timer', id, action: raw.action };
200
+ const seconds = optFiniteNumber(raw.seconds);
201
+ if (seconds !== undefined)
202
+ op.seconds = seconds;
203
+ return op;
204
+ }
205
+ case 'show':
206
+ case 'hide':
207
+ case 'remove':
208
+ return id === undefined ? null : { frame, op: raw.op, id };
209
+ case 'health': {
210
+ const current = optFiniteNumber(raw.current);
211
+ const max = optFiniteNumber(raw.max);
212
+ if (current === undefined || max === undefined)
213
+ return null;
214
+ return { frame, op: 'health', current, max };
215
+ }
216
+ case 'health-visible': {
217
+ if (typeof raw.visible !== 'boolean')
218
+ return null;
219
+ const op = { frame, op: 'health-visible', visible: raw.visible };
220
+ const width = optFiniteNumber(raw.width);
221
+ if (width !== undefined)
222
+ op.width = width;
223
+ return op;
224
+ }
225
+ case 'hud-visible':
226
+ return typeof raw.visible === 'boolean' ? { frame, op: raw.op, visible: raw.visible } : null;
227
+ case 'toast': {
228
+ const message = optString(raw.message);
229
+ if (message === undefined)
230
+ return null;
231
+ const op = { frame, op: 'toast', message };
232
+ const variant = optString(raw.variant);
233
+ const durationMs = optFiniteNumber(raw.durationMs);
234
+ const anchor = optString(raw.anchor);
235
+ if (variant !== undefined)
236
+ op.variant = variant;
237
+ if (durationMs !== undefined)
238
+ op.durationMs = durationMs;
239
+ if (anchor !== undefined)
240
+ op.anchor = anchor;
241
+ return op;
242
+ }
243
+ case 'theme':
244
+ return { frame, op: 'theme', theme: raw.theme };
245
+ case 'stylesheet': {
246
+ const css = optString(raw.css);
247
+ if (id === undefined || css === undefined)
248
+ return null;
249
+ return { frame, op: 'stylesheet', id, css };
250
+ }
251
+ default:
252
+ return null;
253
+ }
254
+ }
255
+ /**
256
+ * Parse the hud[] track. Skipped entries are reported (grouped by op name) so
257
+ * a forward-compatible skip is never silent.
258
+ */
259
+ export function parseHudOps(raw, source) {
260
+ if (raw === undefined)
261
+ return [];
262
+ if (!Array.isArray(raw))
263
+ throw new Error(`${source}: "hud" must be an array`);
264
+ const ops = [];
265
+ const skipped = new Map();
266
+ for (const entry of raw) {
267
+ const parsed = parseHudOp(entry);
268
+ if (parsed === null) {
269
+ const name = isRecord(entry) && typeof entry.op === 'string' ? entry.op : '<malformed>';
270
+ skipped.set(name, (skipped.get(name) ?? 0) + 1);
271
+ continue;
272
+ }
273
+ ops.push(parsed);
274
+ }
275
+ if (skipped.size > 0) {
276
+ const detail = [...skipped.entries()].map(([name, count]) => `${name} x${count}`).join(', ');
277
+ warn(`${source}: skipped ${[...skipped.values()].reduce((a, b) => a + b, 0)} unsupported hud op(s): ${detail}`);
278
+ }
279
+ return ops;
280
+ }
281
+ export function parseTimeline(raw, source) {
282
+ if (!isRecord(raw))
283
+ throw new Error(`${source}: expected a JSON object`);
284
+ if (!isRecord(raw.recording))
285
+ throw new Error(`${source}: missing "recording" object`);
286
+ const rec = raw.recording;
287
+ const recording = {
288
+ name: asString(rec.name, `${source}: recording.name`),
289
+ width: asNumber(rec.width, `${source}: recording.width`),
290
+ height: asNumber(rec.height, `${source}: recording.height`),
291
+ fps: asNumber(rec.fps, `${source}: recording.fps`),
292
+ frameCount: asNumber(rec.frameCount, `${source}: recording.frameCount`)
293
+ };
294
+ // Positivity, not just finiteness: the resolution divides into the raster
295
+ // geometry, so a 0 here becomes an Infinity viewport that Playwright rejects
296
+ // with an error naming neither the field nor the file.
297
+ if (recording.width <= 0)
298
+ throw new Error(`${source}: recording.width must be > 0`);
299
+ if (recording.height <= 0)
300
+ throw new Error(`${source}: recording.height must be > 0`);
301
+ if (recording.fps <= 0)
302
+ throw new Error(`${source}: recording.fps must be > 0`);
303
+ if (recording.frameCount <= 0)
304
+ throw new Error(`${source}: recording.frameCount must be > 0`);
305
+ if (typeof rec.gameId === 'string')
306
+ recording.gameId = rec.gameId;
307
+ if (typeof rec.genre === 'string')
308
+ recording.genre = rec.genre;
309
+ if (rec.missingFrames !== undefined) {
310
+ if (!Array.isArray(rec.missingFrames) || !rec.missingFrames.every((v) => Number.isInteger(v))) {
311
+ throw new Error(`${source}: recording.missingFrames must be an array of integers`);
312
+ }
313
+ recording.missingFrames = rec.missingFrames;
314
+ }
315
+ // Tolerant: a malformed window block degrades to the old behavior rather
316
+ // than failing a whole recording over an informational field.
317
+ if (isRecord(rec.window)) {
318
+ const innerWidth = optFiniteNumber(rec.window.innerWidth);
319
+ const innerHeight = optFiniteNumber(rec.window.innerHeight);
320
+ const devicePixelRatio = optFiniteNumber(rec.window.devicePixelRatio);
321
+ if (innerWidth !== undefined && innerWidth > 0 &&
322
+ innerHeight !== undefined && innerHeight > 0 &&
323
+ devicePixelRatio !== undefined && devicePixelRatio > 0) {
324
+ recording.window = { innerWidth, innerHeight, devicePixelRatio };
325
+ }
326
+ }
327
+ const eventsRaw = raw.events ?? [];
328
+ if (!Array.isArray(eventsRaw))
329
+ throw new Error(`${source}: "events" must be an array`);
330
+ const events = eventsRaw.map((e, i) => parseEvent(e, `${source}: events[${i}]`));
331
+ const soundsRaw = raw.sounds ?? [];
332
+ if (!Array.isArray(soundsRaw))
333
+ throw new Error(`${source}: "sounds" must be an array`);
334
+ const sounds = soundsRaw.map((s, i) => parseSound(s, `${source}: sounds[${i}]`));
335
+ return {
336
+ version: typeof raw.version === 'number' ? raw.version : 1,
337
+ recording,
338
+ events,
339
+ sounds,
340
+ hud: parseHudOps(raw.hud, source)
341
+ };
342
+ }
343
+ export function loadTimeline(recordingDir) {
344
+ const filePath = path.join(recordingDir, 'timeline.json');
345
+ return parseTimeline(readJson(filePath), filePath);
346
+ }
347
+ // ---------------------------------------------------------------------------
348
+ // edl.json parsing
349
+ // ---------------------------------------------------------------------------
350
+ function parseClip(raw, ctx) {
351
+ if (!isRecord(raw))
352
+ throw new Error(`${ctx}: expected an object`);
353
+ const clip = {
354
+ in: asNumber(raw.in, `${ctx}.in`),
355
+ out: asNumber(raw.out, `${ctx}.out`)
356
+ };
357
+ if (raw.speed !== undefined)
358
+ clip.speed = asNumber(raw.speed, `${ctx}.speed`);
359
+ if (raw.transition !== undefined) {
360
+ if (raw.transition !== 'cut' && raw.transition !== 'crossfade') {
361
+ throw new Error(`${ctx}.transition: expected "cut" or "crossfade", got ${JSON.stringify(raw.transition)}`);
362
+ }
363
+ clip.transition = raw.transition;
364
+ }
365
+ if (raw.transitionDuration !== undefined) {
366
+ clip.transitionDuration = asNumber(raw.transitionDuration, `${ctx}.transitionDuration`);
367
+ }
368
+ if (typeof raw.label === 'string')
369
+ clip.label = raw.label;
370
+ if (raw.ui !== undefined) {
371
+ if (typeof raw.ui !== 'boolean')
372
+ throw new Error(`${ctx}.ui: expected a boolean, got ${JSON.stringify(raw.ui)}`);
373
+ clip.ui = raw.ui;
374
+ }
375
+ return clip;
376
+ }
377
+ function parseTitle(raw, source) {
378
+ if (!isRecord(raw))
379
+ throw new Error(`${source}: expected an object`);
380
+ if (typeof raw.at !== 'number' || raw.at < 0)
381
+ throw new Error(`${source}: "at" must be a non-negative number of seconds`);
382
+ if (typeof raw.dur !== 'number' || raw.dur <= 0)
383
+ throw new Error(`${source}: "dur" must be a positive number of seconds`);
384
+ if (typeof raw.text !== 'string' || raw.text.length === 0)
385
+ throw new Error(`${source}: "text" must be a non-empty string`);
386
+ const cue = { at: raw.at, dur: raw.dur, text: raw.text };
387
+ if (typeof raw.sub === 'string')
388
+ cue.sub = raw.sub;
389
+ if (typeof raw.note === 'string')
390
+ cue.note = raw.note;
391
+ if (raw.style !== undefined) {
392
+ if (raw.style !== 'title' && raw.style !== 'line' && raw.style !== 'card') {
393
+ throw new Error(`${source}: "style" must be title, line or card`);
394
+ }
395
+ cue.style = raw.style;
396
+ }
397
+ return cue;
398
+ }
399
+ export function parseEdl(raw, source) {
400
+ if (!isRecord(raw))
401
+ throw new Error(`${source}: expected a JSON object`);
402
+ if (!Array.isArray(raw.clips) || raw.clips.length === 0) {
403
+ throw new Error(`${source}: "clips" must be a non-empty array`);
404
+ }
405
+ const clips = raw.clips.map((c, i) => parseClip(c, `${source}: clips[${i}]`));
406
+ const edl = { version: typeof raw.version === 'number' ? raw.version : 1, clips };
407
+ if (typeof raw.targetDuration === 'number')
408
+ edl.targetDuration = raw.targetDuration;
409
+ if (raw.titles !== undefined) {
410
+ if (!Array.isArray(raw.titles))
411
+ throw new Error(`${source}: "titles" must be an array`);
412
+ edl.titles = raw.titles.map((t, i) => parseTitle(t, `${source}: titles[${i}]`));
413
+ }
414
+ return edl;
415
+ }
416
+ export function loadEdl(filePath) {
417
+ return parseEdl(readJson(filePath), filePath);
418
+ }
419
+ //# sourceMappingURL=timeline-types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"timeline-types.js","sourceRoot":"","sources":["../../src/trailer/timeline-types.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,38 @@
1
+ /** How a title is drawn. */
2
+ export type TitleStyle =
3
+ /** Big centred wordmark, optional subtitle beneath. */
4
+ 'title'
5
+ /** Mid-size lower-third line — feature callouts. */
6
+ | 'line'
7
+ /** Dimmed footage + wordmark + subtitle + small note: the end card. */
8
+ | 'card';
9
+ export interface TitleCue {
10
+ /** Output time in seconds when the title appears. */
11
+ at: number;
12
+ /** How long it stays, in seconds. */
13
+ dur: number;
14
+ text: string;
15
+ /** Second line, smaller (styles `title` and `card`). */
16
+ sub?: string;
17
+ /** Small print, e.g. "ACTUAL GAMEPLAY" (style `card`). */
18
+ note?: string;
19
+ style?: TitleStyle;
20
+ }
21
+ /** Fade at each end of a cue, in seconds. */
22
+ export declare const TITLE_FADE_SEC = 0.22;
23
+ /**
24
+ * The page for one cue. Transparent background so `omitBackground` yields real
25
+ * alpha; the `card` style paints its own scrim.
26
+ */
27
+ export declare function titleHtml(cue: TitleCue, width: number, height: number, fontFile: string): string;
28
+ /**
29
+ * Filter lines overlaying pre-rendered title PNGs onto the video.
30
+ *
31
+ * Each PNG is a still input looped for the cue's duration, so `fade` times are
32
+ * relative to the cue itself; `setpts` shifts it to its output slot and
33
+ * `enable` gates it. Returns a passthrough when there is nothing to draw.
34
+ */
35
+ export declare function buildTitleOverlayChain(inLabel: string, outLabel: string, cues: readonly TitleCue[], baseInputIndex: number): string[];
36
+ /** ffmpeg input args for the title PNGs — each looped for its cue duration. */
37
+ export declare function titleInputArgs(cues: readonly TitleCue[], pngPaths: readonly string[]): string[];
38
+ //# sourceMappingURL=titles.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"titles.d.ts","sourceRoot":"","sources":["../../src/trailer/titles.ts"],"names":[],"mappings":"AA2BA,4BAA4B;AAC5B,MAAM,MAAM,UAAU;AACpB,uDAAuD;AACrD,OAAO;AACT,oDAAoD;GAClD,MAAM;AACR,uEAAuE;GACrE,MAAM,CAAC;AAEX,MAAM,WAAW,QAAQ;IACvB,qDAAqD;IACrD,EAAE,EAAE,MAAM,CAAC;IACX,qCAAqC;IACrC,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,wDAAwD;IACxD,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,0DAA0D;IAC1D,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,UAAU,CAAC;CACpB;AAED,6CAA6C;AAC7C,eAAO,MAAM,cAAc,OAAO,CAAC;AAgBnC;;;GAGG;AACH,wBAAgB,SAAS,CAAC,GAAG,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CA2BhG;AAED;;;;;;GAMG;AACH,wBAAgB,sBAAsB,CACpC,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,SAAS,QAAQ,EAAE,EACzB,cAAc,EAAE,MAAM,GACrB,MAAM,EAAE,CAwBV;AAED,+EAA+E;AAC/E,wBAAgB,cAAc,CAAC,IAAI,EAAE,SAAS,QAAQ,EAAE,EAAE,QAAQ,EAAE,SAAS,MAAM,EAAE,GAAG,MAAM,EAAE,CAM/F"}
@@ -0,0 +1,110 @@
1
+ /**
2
+ * Title cards burned into the trailer — the marketing layer.
3
+ *
4
+ * Times are OUTPUT seconds, so a title is placed against the finished cut (and
5
+ * therefore against the music's beat grid) rather than against source frames.
6
+ * Sizes are fractions of the video so one EDL reads correctly at 1080p or 4K,
7
+ * the same rule the watermark follows.
8
+ *
9
+ * Each cue is rasterized to a transparent PNG in headless Chromium (see
10
+ * title-raster.ts) and overlaid, rather than drawn with ffmpeg's `drawtext`.
11
+ * Two reasons: the ffmpeg here is built without libfreetype, so `drawtext`
12
+ * does not exist at all; and CSS gives real typography — letter-spacing,
13
+ * weights, layered shadows — which drawtext cannot. It reuses exactly the
14
+ * overlay path the HUD replay already proved out.
15
+ *
16
+ * Everything in THIS file is pure string building so tests can import it.
17
+ * Drawing the cards (and finding the font) is the host's `titles` rasterizer
18
+ * — the CLI's is cli/src/trailer/title-raster.ts, which owns the bundled
19
+ * font. Nothing in the compositor may use `import.meta`: game-play-agent
20
+ * loads it under a CJS jest transform, where that is a parse-time error.
21
+ *
22
+ * Every style carries a heavy shadow. Gameplay footage is a moving,
23
+ * arbitrarily-bright background — white text alone disappears over snow and
24
+ * sunlit sand, exactly as the white logo did.
25
+ */
26
+ import { fmtNum } from './video-chain.js';
27
+ /** Fade at each end of a cue, in seconds. */
28
+ export const TITLE_FADE_SEC = 0.22;
29
+ /** Type sizes as a fraction of video height, per style. */
30
+ const SIZES = {
31
+ title: { text: 0.115, sub: 0.034, note: 0.021 },
32
+ line: { text: 0.052, sub: 0.028, note: 0.02 },
33
+ card: { text: 0.125, sub: 0.038, note: 0.022 },
34
+ };
35
+ function escapeHtml(text) {
36
+ return text
37
+ .replace(/&/g, '&amp;')
38
+ .replace(/</g, '&lt;')
39
+ .replace(/>/g, '&gt;');
40
+ }
41
+ /**
42
+ * The page for one cue. Transparent background so `omitBackground` yields real
43
+ * alpha; the `card` style paints its own scrim.
44
+ */
45
+ export function titleHtml(cue, width, height, fontFile) {
46
+ const style = cue.style ?? 'line';
47
+ const size = SIZES[style];
48
+ const px = (frac) => Math.round(height * frac);
49
+ const scrim = style === 'card' ? 'background: rgba(0,0,0,0.62);' : '';
50
+ // `line` sits in the lower third; the others centre as a block.
51
+ const justify = style === 'line' ? 'flex-end' : 'center';
52
+ const padBottom = style === 'line' ? `padding-bottom: ${px(0.11)}px;` : '';
53
+ const shadow = `0 ${px(0.004)}px ${px(0.012)}px rgba(0,0,0,0.85), 0 0 ${px(0.03)}px rgba(0,0,0,0.55)`;
54
+ return `<!doctype html><html><head><meta charset="utf-8"><style>
55
+ @font-face { font-family: 'TrailerFont'; src: url('file://${fontFile}'); }
56
+ html,body { margin:0; padding:0; width:${width}px; height:${height}px; background:transparent; }
57
+ .wrap { ${scrim} width:100%; height:100%; display:flex; flex-direction:column;
58
+ align-items:center; justify-content:${justify}; ${padBottom}
59
+ font-family:'TrailerFont', 'Helvetica Neue', Arial, sans-serif; color:#fff;
60
+ text-align:center; text-shadow:${shadow}; }
61
+ .text { font-size:${px(size.text)}px; font-weight:700; letter-spacing:${px(size.text) * 0.04}px;
62
+ line-height:1.02; }
63
+ .sub { font-size:${px(size.sub)}px; font-weight:400; letter-spacing:${px(size.sub) * 0.08}px;
64
+ margin-top:${px(0.022)}px; opacity:0.94; }
65
+ .note { font-size:${px(size.note)}px; font-weight:400; letter-spacing:${px(size.note) * 0.18}px;
66
+ margin-top:${px(0.05)}px; opacity:0.66; text-transform:uppercase; }
67
+ </style></head><body><div class="wrap">
68
+ <div class="text">${escapeHtml(cue.text)}</div>
69
+ ${cue.sub ? `<div class="sub">${escapeHtml(cue.sub)}</div>` : ''}
70
+ ${cue.note ? `<div class="note">${escapeHtml(cue.note)}</div>` : ''}
71
+ </div></body></html>`;
72
+ }
73
+ /**
74
+ * Filter lines overlaying pre-rendered title PNGs onto the video.
75
+ *
76
+ * Each PNG is a still input looped for the cue's duration, so `fade` times are
77
+ * relative to the cue itself; `setpts` shifts it to its output slot and
78
+ * `enable` gates it. Returns a passthrough when there is nothing to draw.
79
+ */
80
+ export function buildTitleOverlayChain(inLabel, outLabel, cues, baseInputIndex) {
81
+ if (cues.length === 0)
82
+ return [`[${inLabel}]null[${outLabel}]`];
83
+ const lines = [];
84
+ cues.forEach((cue, i) => {
85
+ const fade = Math.min(TITLE_FADE_SEC, cue.dur / 2);
86
+ lines.push(`[${baseInputIndex + i}:v]format=yuva420p,` +
87
+ `fade=t=in:st=0:d=${fmtNum(fade)}:alpha=1,` +
88
+ `fade=t=out:st=${fmtNum(cue.dur - fade)}:d=${fmtNum(fade)}:alpha=1,` +
89
+ `setpts=PTS+${fmtNum(cue.at)}/TB[ttl${i}]`);
90
+ const from = i === 0 ? inLabel : `tstage${i}`;
91
+ const to = i === cues.length - 1 ? outLabel : `tstage${i + 1}`;
92
+ // Half-open, matching the HUD suppressor in video-chain.ts: `between()` is
93
+ // inclusive at both ends, so on a frame landing exactly on cue.at+cue.dur
94
+ // the card still composited while the HUD gate had already released — one
95
+ // frame of bright HUD under the scrim. The card's own fade-out reaches
96
+ // alpha 0 at that same instant, so dropping it costs nothing visually.
97
+ lines.push(`[${from}][ttl${i}]overlay=0:0:eof_action=pass:` +
98
+ `enable='gte(t,${fmtNum(cue.at)})*lt(t,${fmtNum(cue.at + cue.dur)})'[${to}]`);
99
+ });
100
+ return lines;
101
+ }
102
+ /** ffmpeg input args for the title PNGs — each looped for its cue duration. */
103
+ export function titleInputArgs(cues, pngPaths) {
104
+ const args = [];
105
+ cues.forEach((cue, i) => {
106
+ args.push('-loop', '1', '-t', fmtNum(cue.dur), '-i', pngPaths[i]);
107
+ });
108
+ return args;
109
+ }
110
+ //# sourceMappingURL=titles.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"titles.js","sourceRoot":"","sources":["../../src/trailer/titles.ts"],"names":[],"mappings":"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"}