improve: the effect when two lyrics overlap
This commit is contained in:
parent
f939472329
commit
5988c8335c
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "aquavox",
|
"name": "aquavox",
|
||||||
"version": "2.3.3",
|
"version": "2.5.1",
|
||||||
"private": false,
|
"private": false,
|
||||||
"module": "index.ts",
|
"module": "index.ts",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
|
@ -4,11 +4,16 @@
|
|||||||
import type { LyricPos } from './type';
|
import type { LyricPos } from './type';
|
||||||
import type { Spring } from '@core/graphics/spring/spring';
|
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 line: ScriptItem;
|
||||||
export let index: number;
|
export let index: number;
|
||||||
export let debugMode: Boolean;
|
export let debugMode: Boolean;
|
||||||
export let lyricClick: Function;
|
export let lyricClick: Function;
|
||||||
export let progress: number;
|
export let progress: number;
|
||||||
|
export let currentLyricIndex: number;
|
||||||
|
export let scrolling: boolean;
|
||||||
|
|
||||||
let ref: HTMLDivElement;
|
let ref: HTMLDivElement;
|
||||||
let clickMask: HTMLSpanElement;
|
let clickMask: HTMLSpanElement;
|
||||||
@ -75,9 +80,21 @@
|
|||||||
opacity = isCurrent ? 1 : 0.36;
|
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) => {
|
export const update = (pos: LyricPos, delay: number = 0) => {
|
||||||
if (lastPosX === undefined || lastPosY === undefined) {
|
if (lastPosX === undefined || lastPosY === undefined) {
|
||||||
@ -140,7 +157,7 @@
|
|||||||
<span
|
<span
|
||||||
bind:this={clickMask}
|
bind:this={clickMask}
|
||||||
class="absolute w-[calc(100%-2.5rem)] lg:w-[calc(100%-3rem)] h-full
|
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>
|
</span>
|
||||||
{#if debugMode}
|
{#if debugMode}
|
||||||
@ -148,25 +165,25 @@
|
|||||||
{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}
|
||||||
{#if line.words}
|
{#if line.words !== undefined && line.words.length > 0}
|
||||||
<span
|
<span
|
||||||
class={`text-white text-[2rem] leading-9 lg:text-5xl lg:leading-[4rem] font-semibold mr-4 `}
|
class={`text-white text-[2rem] leading-9 lg:text-5xl lg:leading-[4rem] font-semibold mr-4 `}
|
||||||
>
|
>
|
||||||
{#each line.words as word}
|
{#each line.words as word}
|
||||||
{#if word.word}
|
{#if word.word}
|
||||||
{#each word.word.split("") as chr, i}
|
{#each word.word.split("") as chr, i}
|
||||||
<span
|
<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}
|
{chr}
|
||||||
</span>
|
</span>
|
||||||
{/each}
|
{/each}
|
||||||
{/if}
|
{/if}
|
||||||
{/each}
|
{/each}
|
||||||
</span>
|
</span>
|
||||||
{:else}
|
{:else}
|
||||||
<span
|
<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}
|
{line.text}
|
||||||
</span>
|
</span>
|
||||||
@ -179,3 +196,14 @@
|
|||||||
</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>
|
@ -75,17 +75,15 @@
|
|||||||
const relativeOrigin = lyricTopList[currentLyricIndex] - currentLyricTop;
|
const relativeOrigin = lyricTopList[currentLyricIndex] - currentLyricTop;
|
||||||
for (let i = 0; i < lyricElements.length; i++) {
|
for (let i = 0; i < lyricElements.length; i++) {
|
||||||
const currentLyricComponent = lyricComponents[i];
|
const currentLyricComponent = lyricComponents[i];
|
||||||
|
const lyric = originalLyrics.scripts[i];
|
||||||
let delay = 0;
|
let delay = 0;
|
||||||
if (i < currentLyricIndex) {
|
if (progress > lyric.end) {
|
||||||
delay = 0;
|
delay = 0;
|
||||||
} else if (i == currentLyricIndex) {
|
} else if (lyric.start <= progress && progress <= lyric.end) {
|
||||||
delay = 0.042;
|
delay = 0.042;
|
||||||
} else {
|
} else {
|
||||||
delay = Math.min(Math.min(currentLyricDuration, 0.6), 0.067 * (i - currentLyricIndex + 1.2));
|
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);
|
currentLyricComponent.update({ x: 0, y: lyricTopList[i] - relativeOrigin }, delay);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -107,7 +105,7 @@
|
|||||||
for (let i = 0; i < lyricElements.length; i++) {
|
for (let i = 0; i < lyricElements.length; i++) {
|
||||||
const currentLyricComponent = lyricComponents[i];
|
const currentLyricComponent = lyricComponents[i];
|
||||||
const currentY = currentLyricComponent.getInfo().y;
|
const currentY = currentLyricComponent.getInfo().y;
|
||||||
currentLyricComponent.setBlur(0);
|
scrolling = true;
|
||||||
currentLyricComponent.stop();
|
currentLyricComponent.stop();
|
||||||
currentLyricComponent.setY(currentY - deltaY);
|
currentLyricComponent.setY(currentY - deltaY);
|
||||||
}
|
}
|
||||||
@ -263,7 +261,7 @@
|
|||||||
bind:this={lyricsContainer}
|
bind:this={lyricsContainer}
|
||||||
>
|
>
|
||||||
{#each lyricLines as lyric, i}
|
{#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}
|
{/each}
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
|
@ -16,14 +16,13 @@ import {
|
|||||||
tok,
|
tok,
|
||||||
type Token
|
type Token
|
||||||
} from 'typescript-parsec';
|
} from 'typescript-parsec';
|
||||||
import type { LrcJsonData, ParsedLrc, ScriptItem, ScriptWordsItem } from '../type';
|
import type { LrcJsonData, ParsedLrc, ScriptItem } from '../type';
|
||||||
import type { IDTag } from './type';
|
import type { IDTag } from './type';
|
||||||
|
|
||||||
|
|
||||||
interface ParserScriptItem {
|
interface ParserScriptItem {
|
||||||
start: number;
|
start: number;
|
||||||
text: string;
|
text: string;
|
||||||
words?: ScriptWordsItem[];
|
|
||||||
translation?: string;
|
translation?: string;
|
||||||
singer?: string;
|
singer?: string;
|
||||||
}
|
}
|
||||||
@ -166,25 +165,10 @@ function lrcLine(
|
|||||||
.filter((s) => s.trim().length > 0)
|
.filter((s) => s.trim().length > 0)
|
||||||
.join(wordDiv);
|
.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 singer = singerPart?.text;
|
||||||
const translation = translatePart === undefined ? undefined : joinTokens(translatePart);
|
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(lrcTag, (r) => ['lrc_tag', r as IDTag]),
|
||||||
apply(seq(spaces(), str('#'), unicodeStr), (cmt) => ['comment', cmt[2].join('')] as const),
|
apply(seq(spaces(), str('#'), unicodeStr), (cmt) => ['comment', cmt[2].join('')] as const),
|
||||||
@ -206,8 +190,6 @@ export function parseLRC(
|
|||||||
const tokenizer = buildLexer([
|
const tokenizer = buildLexer([
|
||||||
[true, /^\[/gu, '['],
|
[true, /^\[/gu, '['],
|
||||||
[true, /^\]/gu, ']'],
|
[true, /^\]/gu, ']'],
|
||||||
[true, /^</gu, '<'],
|
|
||||||
[true, /^>/gu, '>'],
|
|
||||||
[true, /^\|/gu, '|'],
|
[true, /^\|/gu, '|'],
|
||||||
[true, /^./gu, 'char']
|
[true, /^./gu, 'char']
|
||||||
]);
|
]);
|
||||||
|
Loading…
Reference in New Issue
Block a user