@braccato/core 1.15.0 → 1.15.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/engine.d.ts +2 -0
- package/dist/engine.js +33 -4
- package/dist/stage.d.ts +2 -0
- package/dist/stage.js +8 -1
- package/package.json +1 -1
package/dist/engine.d.ts
CHANGED
|
@@ -72,6 +72,8 @@ export interface AnimationEngineInstance extends AnimEngineViewState {
|
|
|
72
72
|
animationTimingVisibilityLogUntil: number;
|
|
73
73
|
layout: LyricsLayout;
|
|
74
74
|
stageKey: string;
|
|
75
|
+
stageRemeasured: boolean;
|
|
76
|
+
stageHeight: number;
|
|
75
77
|
stageBox: StageBox | null;
|
|
76
78
|
stageMetrics: Map<HTMLElement, StageMetrics>;
|
|
77
79
|
stageY: Map<HTMLElement, number>;
|
package/dist/engine.js
CHANGED
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
// that never meet. `themeSettings.ts` holds the third thing under that rule.
|
|
19
19
|
import { ANIMATING_CLASS, CREDITS_CLASS, CURRENT_LYRICS_CLASS, FOOTER_CLASS, LINE_CLASS, PAUSED_CLASS, ROMANIZED_LYRICS_CLASS, RTL_CLASS, TRANSLATED_LYRICS_CLASS, USER_SCROLLING_CLASS, WORD_STATE_ACTIVE, WORD_STATE_ATTR, WORD_STATE_PAST, WORD_STATE_UPCOMING, } from "./constants.js";
|
|
20
20
|
import { INSTRUMENTAL_WAVE_PATH_HIGH, INSTRUMENTAL_WAVE_PATH_LOW } from "./instrumental.js";
|
|
21
|
-
import { layoutStage, planStage } from "./stage.js";
|
|
21
|
+
import { layoutStage, planStage, queuedStageY, } from "./stage.js";
|
|
22
22
|
import { registerThemeSetting } from "./themeSettings.js";
|
|
23
23
|
import { clamp, getRelativeLayoutBounds, positiveModulo, roundedMs, toMs } from "./util.js";
|
|
24
24
|
const NO_LYRICS_ELEMENT_LOG = "No lyrics element found on the page, skipping lyrics injection";
|
|
@@ -156,6 +156,8 @@ export function createAnimationEngineInstance(engineDocument, engineWindow, host
|
|
|
156
156
|
animationTimingVisibilityLogUntil: 0,
|
|
157
157
|
layout,
|
|
158
158
|
stageKey: "",
|
|
159
|
+
stageRemeasured: false,
|
|
160
|
+
stageHeight: 0,
|
|
159
161
|
stageBox: null,
|
|
160
162
|
stageMetrics: new Map(),
|
|
161
163
|
stageY: new Map(),
|
|
@@ -316,6 +318,7 @@ function resetStage(engine) {
|
|
|
316
318
|
engine.stageMetrics.clear();
|
|
317
319
|
engine.stageY.clear();
|
|
318
320
|
engine.stageKey = "";
|
|
321
|
+
engine.stageHeight = 0;
|
|
319
322
|
if (engine.stageBox !== null) {
|
|
320
323
|
engine.stageBox = null;
|
|
321
324
|
engine.host.onStageLayout?.(null);
|
|
@@ -1992,12 +1995,18 @@ export function measureStage(engine) {
|
|
|
1992
1995
|
});
|
|
1993
1996
|
}
|
|
1994
1997
|
engine.stageKey = "";
|
|
1998
|
+
engine.stageRemeasured = true;
|
|
1995
1999
|
}
|
|
1996
2000
|
function currentTranslateY(engine, element, fallback) {
|
|
1997
2001
|
const parts = engine.window.getComputedStyle(element).translate.split(" ");
|
|
1998
2002
|
const y = Number.parseFloat(parts[1] ?? "");
|
|
1999
2003
|
return Number.isFinite(y) ? y : fallback;
|
|
2000
2004
|
}
|
|
2005
|
+
function snapStageElement(engine, element, y) {
|
|
2006
|
+
engine.stageMoves.get(element)?.cancel();
|
|
2007
|
+
engine.stageMoves.set(element, element.animate([{ translate: `0 ${y}px` }], { duration: 0, fill: "forwards" }));
|
|
2008
|
+
engine.stageY.set(element, y);
|
|
2009
|
+
}
|
|
2001
2010
|
function placeStageElement(engine, { element, placement, wasVisible, fromY, fromOpacity }, instant, reduced) {
|
|
2002
2011
|
engine.stageMoves.get(element)?.cancel();
|
|
2003
2012
|
engine.stageFades.get(element)?.cancel();
|
|
@@ -2075,12 +2084,21 @@ function applyStage(engine, timeS, instant) {
|
|
|
2075
2084
|
if (key === engine.stageKey && !instant)
|
|
2076
2085
|
return;
|
|
2077
2086
|
engine.stageKey = key;
|
|
2087
|
+
const remeasured = engine.stageRemeasured;
|
|
2088
|
+
engine.stageRemeasured = false;
|
|
2078
2089
|
const metrics = elements.map(element => engine.stageMetrics.get(element) ?? { height: 0, left: 0, width: 0, originX: 0 });
|
|
2079
|
-
const
|
|
2090
|
+
const geometry = {
|
|
2080
2091
|
stageHeight: container.clientHeight,
|
|
2081
2092
|
gap: engine.stageFontSize * STAGE_GAP_EM,
|
|
2082
2093
|
activeScale: getCSSNumber(engine, container, "--blyrics-active-scale", 1),
|
|
2083
|
-
}
|
|
2094
|
+
};
|
|
2095
|
+
// Lines sit on the floor, so a resize moves every place by how far the floor moved.
|
|
2096
|
+
const floorShift = remeasured && engine.stageHeight > 0 ? geometry.stageHeight - engine.stageHeight : 0;
|
|
2097
|
+
engine.stageHeight = geometry.stageHeight;
|
|
2098
|
+
const { placements, box } = layoutStage(roles, items, metrics, elements.map(element => {
|
|
2099
|
+
const y = engine.stageY.get(element);
|
|
2100
|
+
return y === undefined ? null : y + floorShift;
|
|
2101
|
+
}), geometry);
|
|
2084
2102
|
// Only the elements whose place changed move. A line that stays where it is keeps its running
|
|
2085
2103
|
// animations, and one already hidden stays hidden without being animated again.
|
|
2086
2104
|
const moves = [];
|
|
@@ -2089,13 +2107,24 @@ function applyStage(engine, timeS, instant) {
|
|
|
2089
2107
|
const previousY = engine.stageY.get(element);
|
|
2090
2108
|
const wasVisible = element.dataset.stageRole !== undefined && isStageRoleVisible(element.dataset.stageRole);
|
|
2091
2109
|
const unchanged = previousY !== undefined && wasVisible === placement.visible && (!placement.visible || previousY === placement.y);
|
|
2110
|
+
// After a resize a line still on screen, fading out included, jumps to its new place and keeps
|
|
2111
|
+
// the fade and blur it was in the middle of.
|
|
2112
|
+
const onScreen = placement.visible || element.dataset.stageVisible !== undefined;
|
|
2113
|
+
if (remeasured && !instant && onScreen && element.dataset.stageRole === roles[index]) {
|
|
2114
|
+
if (previousY !== placement.y)
|
|
2115
|
+
snapStageElement(engine, element, placement.y);
|
|
2116
|
+
return;
|
|
2117
|
+
}
|
|
2092
2118
|
if (unchanged && !instant)
|
|
2093
2119
|
return;
|
|
2094
2120
|
moves.push({
|
|
2095
2121
|
element,
|
|
2096
2122
|
placement,
|
|
2097
2123
|
wasVisible,
|
|
2098
|
-
|
|
2124
|
+
// A queued line rises from below the floor as it is now, never from where an older size put it.
|
|
2125
|
+
fromY: element.dataset.stageRole === "queued" && placement.visible
|
|
2126
|
+
? queuedStageY(geometry.stageHeight, metrics[index].height, geometry.gap)
|
|
2127
|
+
: currentTranslateY(engine, element, previousY ?? placement.y),
|
|
2099
2128
|
fromOpacity: Number(engine.window.getComputedStyle(element).opacity) || 0,
|
|
2100
2129
|
});
|
|
2101
2130
|
});
|
package/dist/stage.d.ts
CHANGED
|
@@ -35,6 +35,8 @@ export interface StageBox {
|
|
|
35
35
|
width: number;
|
|
36
36
|
height: number;
|
|
37
37
|
}
|
|
38
|
+
/** Where a line waits below the floor, and where it rises from as it enters. */
|
|
39
|
+
export declare function queuedStageY(stageHeight: number, height: number, gap: number): number;
|
|
38
40
|
export declare function layoutStage(roles: readonly StageRole[], items: readonly StageItem[], metrics: readonly StageMetrics[], previousY: readonly (number | null)[], geometry: StageGeometry): {
|
|
39
41
|
placements: StagePlacement[];
|
|
40
42
|
box: StageBox | null;
|
package/dist/stage.js
CHANGED
|
@@ -9,6 +9,9 @@ export function stageEnterTimes(items) {
|
|
|
9
9
|
return items.map((item, index) => {
|
|
10
10
|
const early = item.start - STAGE_LEAD_S;
|
|
11
11
|
const previous = items[index - 1];
|
|
12
|
+
// An outro note would otherwise keep the credits off stage until the song ends.
|
|
13
|
+
if (item.kind === "credits" && previous?.kind === "instrumental")
|
|
14
|
+
return (previous.start + previous.end) / 2;
|
|
12
15
|
if (previous?.kind !== "line" || overlapsPrevious(items, index))
|
|
13
16
|
return early;
|
|
14
17
|
return Math.max(early, Math.min(previous.end, item.start) - STAGE_HANDOFF_S);
|
|
@@ -42,6 +45,10 @@ function unionBox(box, next) {
|
|
|
42
45
|
height: Math.max(box.y + box.height, next.y + next.height) - y,
|
|
43
46
|
};
|
|
44
47
|
}
|
|
48
|
+
/** Where a line waits below the floor, and where it rises from as it enters. */
|
|
49
|
+
export function queuedStageY(stageHeight, height, gap) {
|
|
50
|
+
return stageHeight - height + gap;
|
|
51
|
+
}
|
|
45
52
|
export function layoutStage(roles, items, metrics, previousY, geometry) {
|
|
46
53
|
const { stageHeight, gap } = geometry;
|
|
47
54
|
const current = roles.indexOf("current");
|
|
@@ -54,7 +61,7 @@ export function layoutStage(roles, items, metrics, previousY, geometry) {
|
|
|
54
61
|
case "previous":
|
|
55
62
|
return { y: currentY - gap - height, visible: true };
|
|
56
63
|
case "queued":
|
|
57
|
-
return { y: stageHeight
|
|
64
|
+
return { y: queuedStageY(stageHeight, height, gap), visible: false };
|
|
58
65
|
case "gone":
|
|
59
66
|
return { y: previousY[index] ?? currentY, visible: false };
|
|
60
67
|
}
|