Compare commits
3 Commits
Author | SHA1 | Date | |
---|---|---|---|
93e13f9668 | |||
57fd2f626b | |||
3ee8361669 |
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "aquavox",
|
"name": "aquavox",
|
||||||
"version": "2.3.1",
|
"version": "2.3.2",
|
||||||
"private": false,
|
"private": false,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "vite dev",
|
"dev": "vite dev",
|
||||||
|
@ -5,7 +5,6 @@
|
|||||||
import type { Spring } from '$lib/graphics/spring/spring';
|
import type { Spring } from '$lib/graphics/spring/spring';
|
||||||
|
|
||||||
const viewportWidth = document.documentElement.clientWidth;
|
const viewportWidth = document.documentElement.clientWidth;
|
||||||
const scaleCurrentLine = viewportWidth > 640 ? 1.02 : 1.045 ;
|
|
||||||
|
|
||||||
export let line: ScriptItem;
|
export let line: ScriptItem;
|
||||||
export let index: number;
|
export let index: number;
|
||||||
@ -18,7 +17,6 @@
|
|||||||
let time = 0;
|
let time = 0;
|
||||||
let positionX: number = 0;
|
let positionX: number = 0;
|
||||||
let positionY: number = 0;
|
let positionY: number = 0;
|
||||||
let scale = 1;
|
|
||||||
let opacity = 1;
|
let opacity = 1;
|
||||||
let stopped = false;
|
let stopped = false;
|
||||||
let lastPosX: number | undefined = undefined;
|
let lastPosX: number | undefined = undefined;
|
||||||
@ -76,7 +74,6 @@
|
|||||||
export const setCurrent = (isCurrent: boolean) => {
|
export const setCurrent = (isCurrent: boolean) => {
|
||||||
isCurrentLyric = isCurrent;
|
isCurrentLyric = isCurrent;
|
||||||
opacity = isCurrent ? 1 : 0.36;
|
opacity = isCurrent ? 1 : 0.36;
|
||||||
scale = isCurrent ? scaleCurrentLine : 1;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export const setBlur = (blur: number) => {
|
export const setBlur = (blur: number) => {
|
||||||
@ -112,8 +109,8 @@
|
|||||||
lastPosY = pos.y;
|
lastPosY = pos.y;
|
||||||
positionX = pos.x;
|
positionX = pos.x;
|
||||||
positionY = pos.y;
|
positionY = pos.y;
|
||||||
springX = createSpring(pos.x, pos.x, 0.126, 0.8);
|
springX = createSpring(pos.x, pos.x, 0.114, 0.72);
|
||||||
springY = createSpring(pos.y, pos.y, 0.126, 0.8);
|
springY = createSpring(pos.y, pos.y, 0.114, 0.72);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const stop = () => {
|
export const stop = () => {
|
||||||
@ -126,31 +123,36 @@
|
|||||||
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
||||||
<!-- svelte-ignore a11y-no-static-element-interactions -->
|
<!-- svelte-ignore a11y-no-static-element-interactions -->
|
||||||
<div
|
<div
|
||||||
style="transform: translate3d({positionX}px, {positionY}px, 0); scale: {scale};
|
style="transform: translate3d({positionX}px, {positionY}px, 0); transition-property: opacity, text-shadow;
|
||||||
transition-property: scale, opacity; transition-duration: 0.5s; transition-timing-function: ease-in-out; opacity: {opacity};
|
transition-duration: 0.36s; transition-timing-function: ease-out; opacity: {opacity};
|
||||||
transform-origin: center left;"
|
transform-origin: center left;"
|
||||||
class="absolute z-50 w-full pr-12 lg:pr-16 cursor-default py-5"
|
class="absolute z-50 w-full pr-12 lg:pr-16 cursor-default py-5"
|
||||||
bind:this={ref}
|
bind:this={ref}
|
||||||
on:touchstart={() => {
|
on:touchstart={() => {
|
||||||
clickMask.style.backgroundColor = "rgba(255,255,255,.3)";
|
clickMask.style.backgroundColor = 'rgba(255,255,255,.3)';
|
||||||
}}
|
}}
|
||||||
on:touchend={() => {
|
on:touchend={() => {
|
||||||
clickMask.style.backgroundColor = "transparent";
|
clickMask.style.backgroundColor = 'transparent';
|
||||||
}}
|
}}
|
||||||
on:click={() => {
|
on:click={() => {
|
||||||
lyricClick(index);
|
lyricClick(index);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<span class="absolute w-[calc(100%-2.5rem)] lg:w-[calc(100%-2.75rem)] h-full
|
<span
|
||||||
-translate-x-2 lg:-translate-x-5 -translate-y-5 rounded-lg duration-300 lg:hover:bg-[rgba(255,255,255,.15)]" bind:this={clickMask}>
|
class="absolute w-[calc(100%-2.5rem)] lg:w-[calc(100%-3rem)] h-full
|
||||||
|
-translate-x-2 lg:-translate-x-5 -translate-y-5 rounded-lg duration-300 lg:hover:bg-[rgba(255,255,255,.15)]"
|
||||||
|
bind:this={clickMask}
|
||||||
|
>
|
||||||
</span>
|
</span>
|
||||||
{#if debugMode}
|
{#if debugMode}
|
||||||
<span class="text-lg absolute -translate-y-7">
|
<span class="text-lg absolute -translate-y-7">
|
||||||
{index}: duration: {(line.end - line.start).toFixed(3)}, {line.start.toFixed(3)}~{line.end.toFixed(3)}
|
{index}: duration: {(line.end - line.start).toFixed(3)}, {line.start.toFixed(3)}~{line.end.toFixed(3)}
|
||||||
</span>
|
</span>
|
||||||
{/if}
|
{/if}
|
||||||
<span class={`text-white text-[2rem] leading-9 lg:text-5xl lg:leading-[4rem] font-semibold text-shadow-lg mr-4`}>
|
<span
|
||||||
|
class={`text-white text-[2rem] leading-9 lg:text-5xl lg:leading-[4rem] font-semibold text-shadow-lg mr-4
|
||||||
|
${isCurrentLyric ? 'text-glow' : ''}`}
|
||||||
|
>
|
||||||
{line.text}
|
{line.text}
|
||||||
</span>
|
</span>
|
||||||
{#if line.translation}
|
{#if line.translation}
|
||||||
@ -160,3 +162,13 @@
|
|||||||
</span>
|
</span>
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.text-glow {
|
||||||
|
text-shadow:
|
||||||
|
0 0 3px #ffffff2c,
|
||||||
|
0 0 6px #ffffff2c,
|
||||||
|
0 15px 30px rgba(0, 0, 0, 0.11),
|
||||||
|
0 5px 15px rgba(0, 0, 0, 0.08);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
@ -8,8 +8,9 @@
|
|||||||
// constants
|
// constants
|
||||||
const viewportHeight = document.documentElement.clientHeight;
|
const viewportHeight = document.documentElement.clientHeight;
|
||||||
const viewportWidth = document.documentElement.clientWidth;
|
const viewportWidth = document.documentElement.clientWidth;
|
||||||
const marginY = viewportWidth > 640 ? 36 : 0 ;
|
const marginY = viewportWidth > 640 ? 12 : 0 ;
|
||||||
const currentLyrictTop = viewportHeight * 0.02;
|
const blurRatio = viewportWidth > 640 ? 1 : 1.4;
|
||||||
|
const currentLyrictTop = viewportWidth > 640 ? viewportHeight * 0.12 : viewportHeight * 0.05;
|
||||||
const deceleration = 0.95; // Velocity decay factor for inertia
|
const deceleration = 0.95; // Velocity decay factor for inertia
|
||||||
const minVelocity = 0.1; // Minimum velocity to stop inertia
|
const minVelocity = 0.1; // Minimum velocity to stop inertia
|
||||||
document.body.style.overflow = 'hidden';
|
document.body.style.overflow = 'hidden';
|
||||||
@ -56,7 +57,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
function initLyricTopList() {
|
function initLyricTopList() {
|
||||||
let cumulativeHeight = 0;
|
let cumulativeHeight = currentLyrictTop;
|
||||||
for (let i = 0; i < lyricLines.length; i++) {
|
for (let i = 0; i < lyricLines.length; i++) {
|
||||||
const c = lyricComponents[i];
|
const c = lyricComponents[i];
|
||||||
lyricElements.push(c.getRef());
|
lyricElements.push(c.getRef());
|
||||||
@ -76,13 +77,17 @@
|
|||||||
for (let i = 0; i < lyricElements.length; i++) {
|
for (let i = 0; i < lyricElements.length; i++) {
|
||||||
const currentLyricComponent = lyricComponents[i];
|
const currentLyricComponent = lyricComponents[i];
|
||||||
let delay = 0;
|
let delay = 0;
|
||||||
if (i <= currentLyricIndex) {
|
if (i < currentLyricIndex) {
|
||||||
delay = 0;
|
delay = 0;
|
||||||
} else {
|
}
|
||||||
delay = 0.013 + Math.min(Math.min(currentLyricDuration, 0.1), 0.075 * (i - currentLyricIndex));
|
else if (i == currentLyricIndex) {
|
||||||
|
delay = 0.042;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
delay = Math.min(Math.min(currentLyricDuration, 0.6), 0.067 * (i - currentLyricIndex+1.2));
|
||||||
}
|
}
|
||||||
const offset = Math.abs(i - currentLyricIndex);
|
const offset = Math.abs(i - currentLyricIndex);
|
||||||
let blurRadius = Math.min(offset * 1.7, 16);
|
let blurRadius = Math.min(offset * blurRatio, 16);
|
||||||
currentLyricComponent.setBlur(blurRadius);
|
currentLyricComponent.setBlur(blurRadius);
|
||||||
currentLyricComponent.update({ x: 0, y: lyricTopList[i] - relativeOrigin }, delay);
|
currentLyricComponent.update({ x: 0, y: lyricTopList[i] - relativeOrigin }, delay);
|
||||||
}
|
}
|
||||||
@ -110,7 +115,7 @@
|
|||||||
currentLyricComponent.setY(currentY - deltaY);
|
currentLyricComponent.setY(currentY - deltaY);
|
||||||
}
|
}
|
||||||
scrolling = true;
|
scrolling = true;
|
||||||
//if (scrollingTimeout) clearTimeout(scrollingTimeout);
|
if (scrollingTimeout) clearTimeout(scrollingTimeout);
|
||||||
scrollingTimeout = setTimeout(() => {
|
scrollingTimeout = setTimeout(() => {
|
||||||
scrolling = false;
|
scrolling = false;
|
||||||
}, 5000);
|
}, 5000);
|
||||||
@ -181,7 +186,7 @@
|
|||||||
console.log("computeLayout")
|
console.log("computeLayout")
|
||||||
computeLayout();
|
computeLayout();
|
||||||
}
|
}
|
||||||
if (Math.abs(lastProgress - progress) > 0) {
|
if (Math.abs(lastProgress - progress) > 0.5) {
|
||||||
scrolling = false;
|
scrolling = false;
|
||||||
}
|
}
|
||||||
if (lastProgress - progress > 0) {
|
if (lastProgress - progress > 0) {
|
||||||
|
@ -1,124 +0,0 @@
|
|||||||
<script lang="ts">
|
|
||||||
import { onDestroy } from 'svelte';
|
|
||||||
import {
|
|
||||||
LyricPlayer as CoreLyricPlayer,
|
|
||||||
type LyricLineMouseEvent,
|
|
||||||
type LyricLine,
|
|
||||||
type spring
|
|
||||||
} from '@applemusic-like-lyrics/core';
|
|
||||||
|
|
||||||
export let disabled: boolean = false;
|
|
||||||
export let playing: boolean = true;
|
|
||||||
export let alignAnchor: 'top' | 'bottom' | 'center' = 'center';
|
|
||||||
export let alignPosition: number = 0.5;
|
|
||||||
export let enableSpring: boolean = true;
|
|
||||||
export let enableBlur: boolean = true;
|
|
||||||
export let enableScale: boolean = true;
|
|
||||||
export let hidePassedLines: boolean = false;
|
|
||||||
export let lyricLines: LyricLine[] = [];
|
|
||||||
export let currentTime: number = 0;
|
|
||||||
export let linePosXSpringParams: Partial<spring.SpringParams> = {};
|
|
||||||
export let linePosYSpringParams: Partial<spring.SpringParams> = {};
|
|
||||||
export let lineScaleSpringParams: Partial<spring.SpringParams> = {};
|
|
||||||
export let bottomLine: Node = document.createElement('div');
|
|
||||||
export let onLyricLineClick: (line: LyricLineMouseEvent) => void = () => {};
|
|
||||||
export let onLyricLineContextMenu: (line: LyricLineMouseEvent) => void = () => {};
|
|
||||||
export let lyricPlayer: CoreLyricPlayer;
|
|
||||||
let className;
|
|
||||||
export { className as class };
|
|
||||||
|
|
||||||
let lyricsElement: HTMLDivElement | null;
|
|
||||||
let bottomLineElement: HTMLDivElement | null;
|
|
||||||
|
|
||||||
let animationCanceled = false;
|
|
||||||
let animationLastTime = -1;
|
|
||||||
let lineClickHandler: (e: Event) => void;
|
|
||||||
let contextMenuHandler: (e: Event) => void;
|
|
||||||
|
|
||||||
$: {
|
|
||||||
if (playing) {
|
|
||||||
lyricPlayer.resume();
|
|
||||||
} else {
|
|
||||||
lyricPlayer.pause();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const onFrame = (time: number) => {
|
|
||||||
if (animationCanceled) return;
|
|
||||||
if (animationLastTime === -1) {
|
|
||||||
animationLastTime = time;
|
|
||||||
}
|
|
||||||
lyricPlayer.update(time - animationLastTime);
|
|
||||||
animationLastTime = time;
|
|
||||||
requestAnimationFrame(onFrame);
|
|
||||||
};
|
|
||||||
|
|
||||||
const startAnimation = () => {
|
|
||||||
animationCanceled = false;
|
|
||||||
animationLastTime = -1;
|
|
||||||
requestAnimationFrame(onFrame);
|
|
||||||
};
|
|
||||||
|
|
||||||
const stopAnimation = () => {
|
|
||||||
animationCanceled = true;
|
|
||||||
};
|
|
||||||
|
|
||||||
$: {
|
|
||||||
if (!disabled) {
|
|
||||||
startAnimation();
|
|
||||||
} else {
|
|
||||||
stopAnimation();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$: {
|
|
||||||
if (lyricsElement) {
|
|
||||||
lyricsElement.appendChild(lyricPlayer.getElement());
|
|
||||||
}
|
|
||||||
if (bottomLineElement) {
|
|
||||||
lyricPlayer.getBottomLineElement().appendChild(bottomLine);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$: {
|
|
||||||
lyricPlayer.setAlignAnchor(alignAnchor);
|
|
||||||
lyricPlayer.setAlignPosition(alignPosition);
|
|
||||||
lyricPlayer.setEnableSpring(enableSpring);
|
|
||||||
lyricPlayer.setEnableScale(enableScale);
|
|
||||||
lyricPlayer.setEnableBlur(enableBlur);
|
|
||||||
lyricPlayer.setLinePosXSpringParams(linePosXSpringParams);
|
|
||||||
lyricPlayer.setLinePosYSpringParams(linePosYSpringParams);
|
|
||||||
lyricPlayer.setLineScaleSpringParams(lineScaleSpringParams);
|
|
||||||
lyricPlayer.setHidePassedLines(hidePassedLines);
|
|
||||||
}
|
|
||||||
|
|
||||||
$: {
|
|
||||||
lyricPlayer.setLyricLines(lyricLines);
|
|
||||||
lyricPlayer.update();
|
|
||||||
}
|
|
||||||
|
|
||||||
$: {
|
|
||||||
lyricPlayer.setCurrentTime(currentTime);
|
|
||||||
}
|
|
||||||
|
|
||||||
$: {
|
|
||||||
lineClickHandler = (e: Event) => onLyricLineClick(e as LyricLineMouseEvent);
|
|
||||||
lyricPlayer.addEventListener('line-click', lineClickHandler);
|
|
||||||
}
|
|
||||||
|
|
||||||
$: {
|
|
||||||
contextMenuHandler = (e: Event) => onLyricLineContextMenu(e as LyricLineMouseEvent);
|
|
||||||
lyricPlayer.addEventListener('line-contextmenu', contextMenuHandler);
|
|
||||||
}
|
|
||||||
|
|
||||||
onDestroy(() => {
|
|
||||||
animationCanceled = true;
|
|
||||||
lyricPlayer.dispose();
|
|
||||||
lyricPlayer.removeEventListener('line-contextmenu', contextMenuHandler);
|
|
||||||
lyricPlayer.removeEventListener('line-click', lineClickHandler);
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<div bind:this={lyricsElement} class={className}></div>
|
|
||||||
|
|
||||||
<div bind:this={bottomLineElement}></div>
|
|
Loading…
Reference in New Issue
Block a user