@braccato/core 1.1.0 → 1.2.0
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 +7 -0
- package/dist/README.md +7 -0
- package/dist/engine.d.ts +2 -0
- package/dist/engine.js +15 -7
- package/dist/instrumental.d.ts +2 -0
- package/dist/instrumental.js +3 -2
- package/dist/renderer.js +4 -0
- package/dist/styles/instrumental.css +2 -11
- package/dist/styles/variables.css +2 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -179,6 +179,13 @@ The ones a theme reaches for first. `variables.css` declares the rest.
|
|
|
179
179
|
`line-height`. Every word is given the glow, so a theme that wants it to mean something selects on
|
|
180
180
|
`data-long-word`, which the module sets on any part held past `blyrics-long-word-threshold`.
|
|
181
181
|
|
|
182
|
+
The instrumental ripple is the one place a property carries geometry rather than a value.
|
|
183
|
+
`--blyrics-instrumental-wave-path-high` and `--blyrics-instrumental-wave-path-low` are the two shapes
|
|
184
|
+
it morphs between, each a `path()`, and a theme redrawing them is how the wave changes amplitude or
|
|
185
|
+
frequency. Both must use the same commands in the same order with the same number of arguments: a
|
|
186
|
+
browser only interpolates two paths smoothly when their command sequences match, and a mismatched
|
|
187
|
+
pair snaps at the halfway point instead of flowing.
|
|
188
|
+
|
|
182
189
|
### Class names
|
|
183
190
|
|
|
184
191
|
These are published API rather than implementation. Renaming one costs a migration rather than a
|
package/dist/README.md
CHANGED
|
@@ -179,6 +179,13 @@ The ones a theme reaches for first. `variables.css` declares the rest.
|
|
|
179
179
|
`line-height`. Every word is given the glow, so a theme that wants it to mean something selects on
|
|
180
180
|
`data-long-word`, which the module sets on any part held past `blyrics-long-word-threshold`.
|
|
181
181
|
|
|
182
|
+
The instrumental ripple is the one place a property carries geometry rather than a value.
|
|
183
|
+
`--blyrics-instrumental-wave-path-high` and `--blyrics-instrumental-wave-path-low` are the two shapes
|
|
184
|
+
it morphs between, each a `path()`, and a theme redrawing them is how the wave changes amplitude or
|
|
185
|
+
frequency. Both must use the same commands in the same order with the same number of arguments: a
|
|
186
|
+
browser only interpolates two paths smoothly when their command sequences match, and a mismatched
|
|
187
|
+
pair snaps at the halfway point instead of flowing.
|
|
188
|
+
|
|
182
189
|
### Class names
|
|
183
190
|
|
|
184
191
|
These are published API rather than implementation. Renaming one costs a migration rather than a
|
package/dist/engine.d.ts
CHANGED
package/dist/engine.js
CHANGED
|
@@ -17,6 +17,7 @@
|
|
|
17
17
|
// module is bundled into the isolated world and the page world separately, so those are two clocks
|
|
18
18
|
// that never meet. `themeSettings.ts` holds the third thing under that rule.
|
|
19
19
|
import { ANIMATING_CLASS, CURRENT_LYRICS_CLASS, FOOTER_CLASS, LINE_CLASS, PAUSED_CLASS, USER_SCROLLING_CLASS, } from "./constants.js";
|
|
20
|
+
import { INSTRUMENTAL_WAVE_PATH_HIGH, INSTRUMENTAL_WAVE_PATH_LOW } from "./instrumental.js";
|
|
20
21
|
import { registerThemeSetting } from "./themeSettings.js";
|
|
21
22
|
import { clamp, getRelativeLayoutBounds, positiveModulo, roundedMs, toMs } from "./util.js";
|
|
22
23
|
const NO_LYRICS_ELEMENT_LOG = "No lyrics element found on the page, skipping lyrics injection";
|
|
@@ -326,8 +327,8 @@ const WORD_HIGHLIGHT_SELECTOR = ".blyrics-word-highlight";
|
|
|
326
327
|
const INSTRUMENTAL_FILL_SELECTOR = ".blyrics--instrumental-fill";
|
|
327
328
|
const INSTRUMENTAL_WAVE_CLIP_SELECTOR = ".blyrics--wave-clip";
|
|
328
329
|
const INSTRUMENTAL_WAVE_PATH_SELECTOR = ".blyrics--wave-path";
|
|
329
|
-
const
|
|
330
|
-
const
|
|
330
|
+
const INSTRUMENTAL_WAVE_PATH_HIGH_FALLBACK = `path("${INSTRUMENTAL_WAVE_PATH_HIGH}")`;
|
|
331
|
+
const INSTRUMENTAL_WAVE_PATH_LOW_FALLBACK = `path("${INSTRUMENTAL_WAVE_PATH_LOW}")`;
|
|
331
332
|
const LINE_SCROLL_INDEX_PROPERTY = "--blyrics-line-scroll-index";
|
|
332
333
|
const LINE_SCROLL_ACTIVE_INDEX_PROPERTY = "--blyrics-line-scroll-active-index";
|
|
333
334
|
const LINE_SCROLL_RELATIVE_INDEX_PROPERTY = "--blyrics-line-scroll-relative-index";
|
|
@@ -856,9 +857,9 @@ function startInstrumentalAnimations(engine, lineData, config, currentTime, appl
|
|
|
856
857
|
fill: "both",
|
|
857
858
|
}, { appliedTimingOffsetMs, offsetMs: 0 });
|
|
858
859
|
waveOscillationAnimation = animateInstrumentalChild(engine, lineData, INSTRUMENTAL_WAVE_PATH_SELECTOR, [
|
|
859
|
-
{ d:
|
|
860
|
-
{ d:
|
|
861
|
-
{ d:
|
|
860
|
+
{ d: config.instrumental.wavePathHigh },
|
|
861
|
+
{ d: config.instrumental.wavePathLow, offset: 0.5 },
|
|
862
|
+
{ d: config.instrumental.wavePathHigh },
|
|
862
863
|
], {
|
|
863
864
|
duration: config.instrumental.waveOscillationDurationMs,
|
|
864
865
|
easing: config.instrumental.waveOscillationEasing,
|
|
@@ -1016,6 +1017,8 @@ function readAnimationConfig(engine, lyricsElement) {
|
|
|
1016
1017
|
waveFrom: getCSSValue(engine, lyricsElement, "--blyrics-instrumental-wave-transform-from", "scaleY(1.2)"),
|
|
1017
1018
|
waveTo: getCSSValue(engine, lyricsElement, "--blyrics-instrumental-wave-transform-to", "scaleY(0.0001)"),
|
|
1018
1019
|
waveEasing: getCSSValue(engine, lyricsElement, "--blyrics-instrumental-wave-easing", "ease-in"),
|
|
1020
|
+
wavePathHigh: getCSSValue(engine, lyricsElement, "--blyrics-instrumental-wave-path-high", INSTRUMENTAL_WAVE_PATH_HIGH_FALLBACK),
|
|
1021
|
+
wavePathLow: getCSSValue(engine, lyricsElement, "--blyrics-instrumental-wave-path-low", INSTRUMENTAL_WAVE_PATH_LOW_FALLBACK),
|
|
1019
1022
|
waveOscillationDurationMs: getCSSDurationWithFallback(engine, lyricsElement, "--blyrics-instrumental-wave-oscillation-duration", "1.25s"),
|
|
1020
1023
|
waveOscillationEasing: getCSSValue(engine, lyricsElement, "--blyrics-instrumental-wave-oscillation-easing", "ease-in-out"),
|
|
1021
1024
|
},
|
|
@@ -1560,6 +1563,7 @@ export function tickView(engine, currentTime, options) {
|
|
|
1560
1563
|
}
|
|
1561
1564
|
const tabRendererHeight = engine.cachedTabRendererHeight ?? tabRenderer.getBoundingClientRect().height;
|
|
1562
1565
|
let scrollTop = tabRenderer.scrollTop;
|
|
1566
|
+
const maxScrollTop = Math.max(0, tabRenderer.scrollHeight - tabRenderer.clientHeight);
|
|
1563
1567
|
if (animationConfig.enabled.scroll) {
|
|
1564
1568
|
updateVisibleLyricWillChange(engine, lines, scrollTop, engine.pendingLineScroll?.toScrollTop ?? scrollTop, tabRendererHeight);
|
|
1565
1569
|
}
|
|
@@ -1713,8 +1717,9 @@ export function tickView(engine, currentTime, options) {
|
|
|
1713
1717
|
scrollPos = Math.max(scrollPos, lastActiveLyric.position - tabRendererHeight + lastActiveLyric.height);
|
|
1714
1718
|
// Make sure top of last active lyric is visible.
|
|
1715
1719
|
scrollPos = Math.min(scrollPos, lastActiveLyric.position);
|
|
1716
|
-
//
|
|
1717
|
-
|
|
1720
|
+
// Past either end the browser clamps the write and reports nothing, leaving the view aiming
|
|
1721
|
+
// at a position it never reached and re-aiming once per remaining line.
|
|
1722
|
+
scrollPos = clamp(scrollPos, 0, maxScrollTop);
|
|
1718
1723
|
if (ENABLE_DEBUG_RENDER.getBooleanValue()) {
|
|
1719
1724
|
let transform = engine.window.getComputedStyle(lyricsElement).transform;
|
|
1720
1725
|
const matrix = new engine.window.DOMMatrix(transform);
|
|
@@ -1899,6 +1904,9 @@ function applyScrollPadding(engine) {
|
|
|
1899
1904
|
});
|
|
1900
1905
|
engine.document.documentElement.style.setProperty("--blyrics-padding-top", top + "px");
|
|
1901
1906
|
engine.document.documentElement.style.setProperty("--blyrics-padding-bottom", bottom + "px");
|
|
1907
|
+
// Inline, because a theme's own `.blyrics-container { padding }` is appended after the package's
|
|
1908
|
+
// stylesheet at the same weight and would otherwise take this room away.
|
|
1909
|
+
lyricsElement.style.setProperty("padding-bottom", bottom + "px");
|
|
1902
1910
|
}
|
|
1903
1911
|
/**
|
|
1904
1912
|
* Re-reads the view's layout: the scroll padding first, then the line positions the padding moved.
|
package/dist/instrumental.d.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
export declare const INSTRUMENTAL_WAVE_PATH_HIGH = "M -4 3 Q 1 2 5 3 Q 10 4 14 3 Q 18 2 22 3 Q 26 4 30 3 L 30 4 L -4 4 Z";
|
|
2
|
+
export declare const INSTRUMENTAL_WAVE_PATH_LOW = "M -4 3 Q 1 4 5 3 Q 10 2 14 3 Q 18 4 22 3 Q 26 2 30 3 L 30 4 L -4 4 Z";
|
|
1
3
|
/**
|
|
2
4
|
* Creates an HTML element representing an instrumental break in the lyrics.
|
|
3
5
|
*
|
package/dist/instrumental.js
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
export const INSTRUMENTAL_WAVE_PATH_HIGH = "M -4 3 Q 1 2 5 3 Q 10 4 14 3 Q 18 2 22 3 Q 26 4 30 3 L 30 4 L -4 4 Z";
|
|
2
|
+
export const INSTRUMENTAL_WAVE_PATH_LOW = "M -4 3 Q 1 4 5 3 Q 10 2 14 3 Q 18 4 22 3 Q 26 2 30 3 L 30 4 L -4 4 Z";
|
|
1
3
|
/**
|
|
2
4
|
* Creates an HTML element representing an instrumental break in the lyrics.
|
|
3
5
|
*
|
|
@@ -56,8 +58,7 @@ export function createInstrumentalElement(doc, container, durationMs, lineIndex)
|
|
|
56
58
|
// This only contains the surface water. It closes at y=4.
|
|
57
59
|
const wavePath = doc.createElementNS(svgNS, "path");
|
|
58
60
|
wavePath.classList.add("blyrics--wave-path");
|
|
59
|
-
|
|
60
|
-
wavePath.setAttribute("d", "M -4 3 Q 1 2 5 3 Q 10 4 14 3 Q 18 2 22 3 Q 26 4 30 3 L 30 4 L -4 4 Z");
|
|
61
|
+
wavePath.setAttribute("d", INSTRUMENTAL_WAVE_PATH_HIGH);
|
|
61
62
|
clipPath.appendChild(wavePath);
|
|
62
63
|
defs.appendChild(clipPath);
|
|
63
64
|
svg.appendChild(defs);
|
package/dist/renderer.js
CHANGED
|
@@ -269,6 +269,10 @@ export function createLyricsRenderer(rendererOptions) {
|
|
|
269
269
|
// Everything the engine resolved off the document was resolved against the theme that just
|
|
270
270
|
// went away.
|
|
271
271
|
clearEngineStyleCaches(engine);
|
|
272
|
+
// The target scroll position is one of the settings a theme carries, and the scroll padding is
|
|
273
|
+
// sized against it, so a theme that moves the target moves the layout even when no rule in it
|
|
274
|
+
// does.
|
|
275
|
+
measure();
|
|
272
276
|
return needsLyricRebuild;
|
|
273
277
|
},
|
|
274
278
|
tick(currentTimeS, options) {
|
|
@@ -69,6 +69,8 @@
|
|
|
69
69
|
|
|
70
70
|
/* Prepare the WAAPI flatten transition. */
|
|
71
71
|
transform: scaleY(1.2);
|
|
72
|
+
|
|
73
|
+
d: var(--blyrics-instrumental-wave-path-high);
|
|
72
74
|
}
|
|
73
75
|
|
|
74
76
|
/* Trigger the Flattening */
|
|
@@ -90,14 +92,3 @@
|
|
|
90
92
|
transition-timing-function: ease-out;
|
|
91
93
|
transition-delay: 0s;
|
|
92
94
|
}
|
|
93
|
-
|
|
94
|
-
/* Update Keyframes for the "Split" shape */
|
|
95
|
-
/* These paths must close at 'L 30 4 L -4 4' to match the static rect overlap */
|
|
96
|
-
@keyframes blyrics-wave {
|
|
97
|
-
0%, 100% {
|
|
98
|
-
d: path("M -4 3 Q 1 2 5 3 Q 10 4 14 3 Q 18 2 22 3 Q 26 4 30 3 L 30 4 L -4 4 Z");
|
|
99
|
-
}
|
|
100
|
-
50% {
|
|
101
|
-
d: path("M -4 3 Q 1 4 5 3 Q 10 2 14 3 Q 18 4 22 3 Q 26 2 30 3 L 30 4 L -4 4 Z");
|
|
102
|
-
}
|
|
103
|
-
}
|
|
@@ -117,6 +117,8 @@
|
|
|
117
117
|
--blyrics-instrumental-wave-transform-from: scaleY(1.2);
|
|
118
118
|
--blyrics-instrumental-wave-transform-to: scaleY(0.0001);
|
|
119
119
|
--blyrics-instrumental-wave-easing: ease-in;
|
|
120
|
+
--blyrics-instrumental-wave-path-high: path("M -4 3 Q 1 2 5 3 Q 10 4 14 3 Q 18 2 22 3 Q 26 4 30 3 L 30 4 L -4 4 Z");
|
|
121
|
+
--blyrics-instrumental-wave-path-low: path("M -4 3 Q 1 4 5 3 Q 10 2 14 3 Q 18 4 22 3 Q 26 2 30 3 L 30 4 L -4 4 Z");
|
|
120
122
|
--blyrics-instrumental-wave-oscillation-duration: 1.25s;
|
|
121
123
|
--blyrics-instrumental-wave-oscillation-easing: ease-in-out;
|
|
122
124
|
|