@subvo/renderer 1.2.2 → 1.2.3
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/dist/renderer.d.ts +9 -2
- package/dist/renderer.esm.js +38 -7
- package/dist/renderer.iife.js +38 -7
- package/package.json +1 -1
package/dist/renderer.d.ts
CHANGED
|
@@ -18,6 +18,7 @@ type RenderLine = {
|
|
|
18
18
|
startMs: number;
|
|
19
19
|
endMs: number;
|
|
20
20
|
mode?: RenderMode;
|
|
21
|
+
motion?: RenderMotion;
|
|
21
22
|
breakHints?: string[];
|
|
22
23
|
words: RenderWord[];
|
|
23
24
|
};
|
|
@@ -39,7 +40,13 @@ type RenderMetadata = {
|
|
|
39
40
|
};
|
|
40
41
|
type RenderPosition = "top_safe" | "center" | "bottom_safe";
|
|
41
42
|
type RenderPreset = "fire" | "clean" | "luxury" | "pop" | "ghost";
|
|
42
|
-
type RenderMode = "phrase_highlight" | "progressive_build";
|
|
43
|
+
type RenderMode = "karaoke" | "phrase_highlight" | "static" | "progressive_build";
|
|
44
|
+
type RenderMotion = {
|
|
45
|
+
policy?: string;
|
|
46
|
+
resolvedMode?: RenderMode;
|
|
47
|
+
reason?: string;
|
|
48
|
+
metrics?: Record<string, unknown>;
|
|
49
|
+
};
|
|
43
50
|
type RenderStyle = {
|
|
44
51
|
fontFamily: string;
|
|
45
52
|
fontSize: number;
|
|
@@ -70,4 +77,4 @@ declare function renderFrame(ctx: CanvasRenderingContext2D, renderJob: RenderJob
|
|
|
70
77
|
|
|
71
78
|
declare const VERSION: string;
|
|
72
79
|
|
|
73
|
-
export { type RenderJob, type RenderLayoutHints, type RenderLine, type RenderMetadata, type RenderPosition, type RenderPreset, type RenderStyle, type RenderWord, type SchemaVersion, VERSION, renderFrame };
|
|
80
|
+
export { type RenderJob, type RenderLayoutHints, type RenderLine, type RenderMetadata, type RenderMotion, type RenderPosition, type RenderPreset, type RenderStyle, type RenderWord, type SchemaVersion, VERSION, renderFrame };
|
package/dist/renderer.esm.js
CHANGED
|
@@ -349,6 +349,7 @@ var BOTTOM_UNSAFE_RATIO = 0.24;
|
|
|
349
349
|
var TOP_SAFE_ANCHOR_RATIO = 0.22;
|
|
350
350
|
var CENTER_ANCHOR_RATIO = 0.5;
|
|
351
351
|
var BOTTOM_SAFE_ANCHOR_RATIO = 0.68;
|
|
352
|
+
var PHRASE_HIGHLIGHT_MS = 180;
|
|
352
353
|
function renderFrame(ctx, renderJob, timeMs) {
|
|
353
354
|
var _a;
|
|
354
355
|
const { playRes, style } = renderJob;
|
|
@@ -394,14 +395,15 @@ function renderFrame(ctx, renderJob, timeMs) {
|
|
|
394
395
|
let x = centerX - row.width / 2;
|
|
395
396
|
const rowY = baselineY + rowIndex * lineStep;
|
|
396
397
|
for (const { word, text, width } of row.words) {
|
|
398
|
+
const motionMode = resolveLineMotionMode(entry.line);
|
|
397
399
|
const visibleWord = isWordVisible(entry.line, word, timeMs);
|
|
398
400
|
if (visibleWord) {
|
|
399
|
-
const activeWord =
|
|
400
|
-
const emphasis = (_a = word.emphasis) != null ? _a : 0;
|
|
401
|
-
const progress = activeWord ?
|
|
402
|
-
const impactProgress = activeWord ? computeImpactProgress(word, timeMs) : 0;
|
|
403
|
-
const pulseScale = computePulseScale(style, progress);
|
|
404
|
-
const bounceScale = shouldBounceWord(style, emphasis) ? computeImpactScale(impactProgress) : 1;
|
|
401
|
+
const activeWord = isWordActive(entry.line, word, timeMs, motionMode);
|
|
402
|
+
const emphasis = motionMode === "static" ? 0 : (_a = word.emphasis) != null ? _a : 0;
|
|
403
|
+
const progress = activeWord ? computeMotionProgress(entry.line, word, timeMs, motionMode) : 0;
|
|
404
|
+
const impactProgress = activeWord && motionMode === "karaoke" ? computeImpactProgress(word, timeMs) : 0;
|
|
405
|
+
const pulseScale = motionMode === "static" ? 1 : computePulseScale(style, progress);
|
|
406
|
+
const bounceScale = shouldBounceWord(style, emphasis, motionMode) ? computeImpactScale(impactProgress) : 1;
|
|
405
407
|
const scaleFactor = pulseScale * bounceScale;
|
|
406
408
|
drawWord(
|
|
407
409
|
ctx,
|
|
@@ -446,7 +448,36 @@ function isWordVisible(line, word, timeMs) {
|
|
|
446
448
|
}
|
|
447
449
|
return timeMs >= word.startMs;
|
|
448
450
|
}
|
|
449
|
-
function
|
|
451
|
+
function resolveLineMotionMode(line) {
|
|
452
|
+
var _a;
|
|
453
|
+
const motionMode = (_a = line.motion) == null ? void 0 : _a.resolvedMode;
|
|
454
|
+
if (motionMode === "karaoke" || motionMode === "phrase_highlight" || motionMode === "static") {
|
|
455
|
+
return motionMode;
|
|
456
|
+
}
|
|
457
|
+
if (line.mode === "static" || line.mode === "karaoke" || line.mode === "progressive_build") {
|
|
458
|
+
return line.mode;
|
|
459
|
+
}
|
|
460
|
+
return "phrase_highlight";
|
|
461
|
+
}
|
|
462
|
+
function isWordActive(line, word, timeMs, motionMode) {
|
|
463
|
+
if (motionMode === "static") {
|
|
464
|
+
return false;
|
|
465
|
+
}
|
|
466
|
+
if (motionMode === "phrase_highlight") {
|
|
467
|
+
return timeMs >= line.startMs && timeMs <= line.startMs + PHRASE_HIGHLIGHT_MS;
|
|
468
|
+
}
|
|
469
|
+
return timeMs >= word.startMs && timeMs <= word.endMs;
|
|
470
|
+
}
|
|
471
|
+
function computeMotionProgress(line, word, timeMs, motionMode) {
|
|
472
|
+
if (motionMode === "phrase_highlight") {
|
|
473
|
+
return clamp((timeMs - line.startMs) / PHRASE_HIGHLIGHT_MS);
|
|
474
|
+
}
|
|
475
|
+
return computeWordProgress(word, timeMs);
|
|
476
|
+
}
|
|
477
|
+
function shouldBounceWord(style, emphasis, motionMode) {
|
|
478
|
+
if (motionMode !== "karaoke") {
|
|
479
|
+
return false;
|
|
480
|
+
}
|
|
450
481
|
if (style.preset === "ghost") {
|
|
451
482
|
return false;
|
|
452
483
|
}
|
package/dist/renderer.iife.js
CHANGED
|
@@ -376,6 +376,7 @@ var SubvoRenderer = (() => {
|
|
|
376
376
|
var TOP_SAFE_ANCHOR_RATIO = 0.22;
|
|
377
377
|
var CENTER_ANCHOR_RATIO = 0.5;
|
|
378
378
|
var BOTTOM_SAFE_ANCHOR_RATIO = 0.68;
|
|
379
|
+
var PHRASE_HIGHLIGHT_MS = 180;
|
|
379
380
|
function renderFrame(ctx, renderJob, timeMs) {
|
|
380
381
|
var _a;
|
|
381
382
|
const { playRes, style } = renderJob;
|
|
@@ -421,14 +422,15 @@ var SubvoRenderer = (() => {
|
|
|
421
422
|
let x = centerX - row.width / 2;
|
|
422
423
|
const rowY = baselineY + rowIndex * lineStep;
|
|
423
424
|
for (const { word, text, width } of row.words) {
|
|
425
|
+
const motionMode = resolveLineMotionMode(entry.line);
|
|
424
426
|
const visibleWord = isWordVisible(entry.line, word, timeMs);
|
|
425
427
|
if (visibleWord) {
|
|
426
|
-
const activeWord =
|
|
427
|
-
const emphasis = (_a = word.emphasis) != null ? _a : 0;
|
|
428
|
-
const progress = activeWord ?
|
|
429
|
-
const impactProgress = activeWord ? computeImpactProgress(word, timeMs) : 0;
|
|
430
|
-
const pulseScale = computePulseScale(style, progress);
|
|
431
|
-
const bounceScale = shouldBounceWord(style, emphasis) ? computeImpactScale(impactProgress) : 1;
|
|
428
|
+
const activeWord = isWordActive(entry.line, word, timeMs, motionMode);
|
|
429
|
+
const emphasis = motionMode === "static" ? 0 : (_a = word.emphasis) != null ? _a : 0;
|
|
430
|
+
const progress = activeWord ? computeMotionProgress(entry.line, word, timeMs, motionMode) : 0;
|
|
431
|
+
const impactProgress = activeWord && motionMode === "karaoke" ? computeImpactProgress(word, timeMs) : 0;
|
|
432
|
+
const pulseScale = motionMode === "static" ? 1 : computePulseScale(style, progress);
|
|
433
|
+
const bounceScale = shouldBounceWord(style, emphasis, motionMode) ? computeImpactScale(impactProgress) : 1;
|
|
432
434
|
const scaleFactor = pulseScale * bounceScale;
|
|
433
435
|
drawWord(
|
|
434
436
|
ctx,
|
|
@@ -473,7 +475,36 @@ var SubvoRenderer = (() => {
|
|
|
473
475
|
}
|
|
474
476
|
return timeMs >= word.startMs;
|
|
475
477
|
}
|
|
476
|
-
function
|
|
478
|
+
function resolveLineMotionMode(line) {
|
|
479
|
+
var _a;
|
|
480
|
+
const motionMode = (_a = line.motion) == null ? void 0 : _a.resolvedMode;
|
|
481
|
+
if (motionMode === "karaoke" || motionMode === "phrase_highlight" || motionMode === "static") {
|
|
482
|
+
return motionMode;
|
|
483
|
+
}
|
|
484
|
+
if (line.mode === "static" || line.mode === "karaoke" || line.mode === "progressive_build") {
|
|
485
|
+
return line.mode;
|
|
486
|
+
}
|
|
487
|
+
return "phrase_highlight";
|
|
488
|
+
}
|
|
489
|
+
function isWordActive(line, word, timeMs, motionMode) {
|
|
490
|
+
if (motionMode === "static") {
|
|
491
|
+
return false;
|
|
492
|
+
}
|
|
493
|
+
if (motionMode === "phrase_highlight") {
|
|
494
|
+
return timeMs >= line.startMs && timeMs <= line.startMs + PHRASE_HIGHLIGHT_MS;
|
|
495
|
+
}
|
|
496
|
+
return timeMs >= word.startMs && timeMs <= word.endMs;
|
|
497
|
+
}
|
|
498
|
+
function computeMotionProgress(line, word, timeMs, motionMode) {
|
|
499
|
+
if (motionMode === "phrase_highlight") {
|
|
500
|
+
return clamp((timeMs - line.startMs) / PHRASE_HIGHLIGHT_MS);
|
|
501
|
+
}
|
|
502
|
+
return computeWordProgress(word, timeMs);
|
|
503
|
+
}
|
|
504
|
+
function shouldBounceWord(style, emphasis, motionMode) {
|
|
505
|
+
if (motionMode !== "karaoke") {
|
|
506
|
+
return false;
|
|
507
|
+
}
|
|
477
508
|
if (style.preset === "ghost") {
|
|
478
509
|
return false;
|
|
479
510
|
}
|