@subvo/renderer 1.2.1 → 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 +43 -13
- package/dist/renderer.iife.js +43 -13
- 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
|
@@ -345,10 +345,11 @@ var DEFAULT_TRANSITION_MS = 150;
|
|
|
345
345
|
var MIN_TRANSITION_MS = 120;
|
|
346
346
|
var MAX_TRANSITION_MS = 180;
|
|
347
347
|
var TOP_UNSAFE_RATIO = 0.14;
|
|
348
|
-
var BOTTOM_UNSAFE_RATIO = 0.
|
|
348
|
+
var BOTTOM_UNSAFE_RATIO = 0.24;
|
|
349
349
|
var TOP_SAFE_ANCHOR_RATIO = 0.22;
|
|
350
350
|
var CENTER_ANCHOR_RATIO = 0.5;
|
|
351
|
-
var BOTTOM_SAFE_ANCHOR_RATIO = 0.
|
|
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,
|
|
@@ -431,9 +433,8 @@ function resolveTransitionMs(style) {
|
|
|
431
433
|
);
|
|
432
434
|
}
|
|
433
435
|
function computeLineAlpha(line, timeMs, transitionMs) {
|
|
434
|
-
const
|
|
435
|
-
const
|
|
436
|
-
const visibleEnd = line.endMs + padding;
|
|
436
|
+
const visibleStart = line.startMs;
|
|
437
|
+
const visibleEnd = line.endMs;
|
|
437
438
|
if (timeMs < visibleStart || timeMs > visibleEnd) {
|
|
438
439
|
return 0;
|
|
439
440
|
}
|
|
@@ -447,7 +448,36 @@ function isWordVisible(line, word, timeMs) {
|
|
|
447
448
|
}
|
|
448
449
|
return timeMs >= word.startMs;
|
|
449
450
|
}
|
|
450
|
-
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
|
+
}
|
|
451
481
|
if (style.preset === "ghost") {
|
|
452
482
|
return false;
|
|
453
483
|
}
|
|
@@ -481,7 +511,7 @@ function clampBaselineY(baselineY, rowCount, ascent, descent, lineStep, safeTop,
|
|
|
481
511
|
}
|
|
482
512
|
|
|
483
513
|
// src/index.ts
|
|
484
|
-
var injectedVersion = "1.2.
|
|
514
|
+
var injectedVersion = "1.2.2".length > 0 ? "1.2.2" : "dev";
|
|
485
515
|
var VERSION = injectedVersion;
|
|
486
516
|
export {
|
|
487
517
|
VERSION,
|
package/dist/renderer.iife.js
CHANGED
|
@@ -372,10 +372,11 @@ var SubvoRenderer = (() => {
|
|
|
372
372
|
var MIN_TRANSITION_MS = 120;
|
|
373
373
|
var MAX_TRANSITION_MS = 180;
|
|
374
374
|
var TOP_UNSAFE_RATIO = 0.14;
|
|
375
|
-
var BOTTOM_UNSAFE_RATIO = 0.
|
|
375
|
+
var BOTTOM_UNSAFE_RATIO = 0.24;
|
|
376
376
|
var TOP_SAFE_ANCHOR_RATIO = 0.22;
|
|
377
377
|
var CENTER_ANCHOR_RATIO = 0.5;
|
|
378
|
-
var BOTTOM_SAFE_ANCHOR_RATIO = 0.
|
|
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,
|
|
@@ -458,9 +460,8 @@ var SubvoRenderer = (() => {
|
|
|
458
460
|
);
|
|
459
461
|
}
|
|
460
462
|
function computeLineAlpha(line, timeMs, transitionMs) {
|
|
461
|
-
const
|
|
462
|
-
const
|
|
463
|
-
const visibleEnd = line.endMs + padding;
|
|
463
|
+
const visibleStart = line.startMs;
|
|
464
|
+
const visibleEnd = line.endMs;
|
|
464
465
|
if (timeMs < visibleStart || timeMs > visibleEnd) {
|
|
465
466
|
return 0;
|
|
466
467
|
}
|
|
@@ -474,7 +475,36 @@ var SubvoRenderer = (() => {
|
|
|
474
475
|
}
|
|
475
476
|
return timeMs >= word.startMs;
|
|
476
477
|
}
|
|
477
|
-
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
|
+
}
|
|
478
508
|
if (style.preset === "ghost") {
|
|
479
509
|
return false;
|
|
480
510
|
}
|
|
@@ -508,7 +538,7 @@ var SubvoRenderer = (() => {
|
|
|
508
538
|
}
|
|
509
539
|
|
|
510
540
|
// src/index.ts
|
|
511
|
-
var injectedVersion = "1.2.
|
|
541
|
+
var injectedVersion = "1.2.2".length > 0 ? "1.2.2" : "dev";
|
|
512
542
|
var VERSION = injectedVersion;
|
|
513
543
|
return __toCommonJS(src_exports);
|
|
514
544
|
})();
|