improve: the effect when two lyrics overlap

This commit is contained in:
alikia2x (寒寒) 2024-10-29 02:45:36 +08:00
parent f939472329
commit 5988c8335c
Signed by: alikia2x
GPG Key ID: 56209E0CCD8420C6
4 changed files with 47 additions and 39 deletions

View File

@ -1,6 +1,6 @@
{
"name": "aquavox",
"version": "2.3.3",
"version": "2.5.1",
"private": false,
"module": "index.ts",
"type": "module",

View File

@ -4,11 +4,16 @@
import type { LyricPos } from './type';
import type { Spring } from '@core/graphics/spring/spring';
const viewportWidth = document.documentElement.clientWidth;
const blurRatio = viewportWidth > 640 ? 1 : 1.4;
export let line: ScriptItem;
export let index: number;
export let debugMode: Boolean;
export let lyricClick: Function;
export let progress: number;
export let currentLyricIndex: number;
export let scrolling: boolean;
let ref: HTMLDivElement;
let clickMask: HTMLSpanElement;
@ -75,9 +80,21 @@
opacity = isCurrent ? 1 : 0.36;
};
export const setBlur = (blur: number) => {
ref.style.filter = `blur(${blur}px)`;
};
$: {
if (ref && ref.style) {
let blurRadius = 0;
const offset = Math.abs(index - currentLyricIndex);
if (progress > line.end) {
blurRadius = Math.min(offset * blurRatio, 16);
} else if (line.start <= progress && progress <= line.end) {
blurRadius = 0;
} else {
blurRadius = Math.min(offset * blurRatio, 16);
}
if (scrolling) blurRadius=0;
ref.style.filter = `blur(${blurRadius}px)`;
}
}
export const update = (pos: LyricPos, delay: number = 0) => {
if (lastPosX === undefined || lastPosY === undefined) {
@ -140,7 +157,7 @@
<span
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)]"
-translate-x-2 lg:-translate-x-5 -translate-y-5 rounded-lg duration-300 lg:hover:bg-[rgba(255,255,255,.15)] z-[100] "
>
</span>
{#if debugMode}
@ -148,7 +165,7 @@
{index}: duration: {(line.end - line.start).toFixed(3)}, {line.start.toFixed(3)}~{line.end.toFixed(3)}
</span>
{/if}
{#if line.words}
{#if line.words !== undefined && line.words.length > 0}
<span
class={`text-white text-[2rem] leading-9 lg:text-5xl lg:leading-[4rem] font-semibold mr-4 `}
>
@ -156,7 +173,7 @@
{#if word.word}
{#each word.word.split("") as chr, i}
<span
class={(line.start <= progress && progress <= line.end && progress > (word.endTime - word.startTime) * ((i)/word.word.length) + word.startTime ? "opacity-100" : "opacity-35") + " inline-block duration-300"}
class={(line.start <= progress && progress <= line.end && progress > (word.endTime - word.startTime) * ((i)/word.word.length) + word.startTime ? "opacity-100 text-glow" : "opacity-35") + " inline-block duration-300"}
>
{chr}
</span>
@ -166,7 +183,7 @@
</span>
{:else}
<span
class={`text-white text-[2rem] leading-9 lg:text-5xl lg:leading-[4rem] font-semibold mr-4 duration-200 ${line.start <= progress && progress <= line.end ? "opacity-100" : "opacity-35"}`}
class={`text-white text-[2rem] leading-9 lg:text-5xl lg:leading-[4rem] font-semibold mr-4 duration-200 ${line.start <= progress && progress <= line.end ? "opacity-100 text-glow" : "opacity-35"}`}
>
{line.text}
</span>
@ -179,3 +196,14 @@
</span>
{/if}
</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>

View File

@ -75,17 +75,15 @@
const relativeOrigin = lyricTopList[currentLyricIndex] - currentLyricTop;
for (let i = 0; i < lyricElements.length; i++) {
const currentLyricComponent = lyricComponents[i];
const lyric = originalLyrics.scripts[i];
let delay = 0;
if (i < currentLyricIndex) {
if (progress > lyric.end) {
delay = 0;
} else if (i == currentLyricIndex) {
} else if (lyric.start <= progress && progress <= lyric.end) {
delay = 0.042;
} else {
delay = Math.min(Math.min(currentLyricDuration, 0.6), 0.067 * (i - currentLyricIndex + 1.2));
}
const offset = Math.abs(i - currentLyricIndex);
let blurRadius = Math.min(offset * blurRatio, 16);
currentLyricComponent.setBlur(blurRadius);
currentLyricComponent.update({ x: 0, y: lyricTopList[i] - relativeOrigin }, delay);
}
}
@ -107,7 +105,7 @@
for (let i = 0; i < lyricElements.length; i++) {
const currentLyricComponent = lyricComponents[i];
const currentY = currentLyricComponent.getInfo().y;
currentLyricComponent.setBlur(0);
scrolling = true;
currentLyricComponent.stop();
currentLyricComponent.setY(currentY - deltaY);
}
@ -263,7 +261,7 @@
bind:this={lyricsContainer}
>
{#each lyricLines as lyric, i}
<LyricLine line={lyric} index={i} bind:this={lyricComponents[i]} {debugMode} {lyricClick} {progress} />
<LyricLine line={lyric} index={i} bind:this={lyricComponents[i]} {debugMode} {lyricClick} {progress} {currentLyricIndex} {scrolling}/>
{/each}
</div>
{/if}

View File

@ -16,14 +16,13 @@ import {
tok,
type Token
} from 'typescript-parsec';
import type { LrcJsonData, ParsedLrc, ScriptItem, ScriptWordsItem } from '../type';
import type { LrcJsonData, ParsedLrc, ScriptItem } from '../type';
import type { IDTag } from './type';
interface ParserScriptItem {
start: number;
text: string;
words?: ScriptWordsItem[];
translation?: string;
singer?: string;
}
@ -166,25 +165,10 @@ function lrcLine(
.filter((s) => s.trim().length > 0)
.join(wordDiv);
const words = mainPart
.filter((s) => joinTokens(s[1]).trim().length > 0)
.map((s) => {
const wordBegin = s[0];
const word = s[1];
let ret: Partial<ScriptWordsItem> = { start: wordBegin };
if (word[0]) {
ret.beginIndex = word[0].pos.columnBegin - 1;
}
if (word[word.length - 1]) {
ret.endIndex = word[word.length - 1].pos.columnEnd;
}
return ret as ScriptWordsItem; // TODO: Complete this
});
const singer = singerPart?.text;
const translation = translatePart === undefined ? undefined : joinTokens(translatePart);
return ['script_item', { start, text, words, singer, translation } as ParserScriptItem];
return ['script_item', { start, text, singer, translation } as ParserScriptItem];
}),
apply(lrcTag, (r) => ['lrc_tag', r as IDTag]),
apply(seq(spaces(), str('#'), unicodeStr), (cmt) => ['comment', cmt[2].join('')] as const),
@ -206,8 +190,6 @@ export function parseLRC(
const tokenizer = buildLexer([
[true, /^\[/gu, '['],
[true, /^\]/gu, ']'],
[true, /^</gu, '<'],
[true, /^>/gu, '>'],
[true, /^\|/gu, '|'],
[true, /^./gu, 'char']
]);