@applemusic-like-lyrics/core 0.5.1 → 0.6.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.
@@ -1 +1 @@
1
- {"version":3,"file":"amll-core.mjs","names":["meshVertShader","meshFragShader","styles","styles","styles","styles","styles","styles"],"sources":["../src/bg-render/base.ts","../src/utils/resource.ts","../src/bg-render/img.ts","../src/utils/clamp.ts","../src/bg-render/mesh-renderer/cp-presets.ts","../src/bg-render/mesh-renderer/cp-generate.ts","../src/bg-render/mesh-renderer/index.ts","../src/bg-render/pixi-renderer.ts","../src/bg-render/index.ts","../src/styles/lyric-player.module.css","../src/utils/optimize-lyric.ts","../src/lyric-player/dom/interlude-dots.ts","../src/utils/schedule.ts","../src/utils/derivative.ts","../src/utils/spring.ts","../src/lyric-player/base/bottom-line.ts","../src/lyric-player/base/consts.ts","../src/lyric-player/base/layout.ts","../src/lyric-player/base/scroll.ts","../src/utils/eq-set.ts","../src/lyric-player/base/timeline.ts","../src/lyric-player/base/index.ts","../src/lyric-player/base/group.ts","../src/lyric-player/dom/lyric-group.ts","../src/utils/is-cjk.ts","../src/lyric-player/base/line.ts","../src/utils/lyric-line-break.ts","../src/utils/line-balancer.ts","../src/utils/lyric-split-words.ts","../src/utils/matrix.ts","../src/lyric-player/dom/lyric-line.ts","../src/lyric-player/dom/index.ts"],"sourcesContent":["import type { Disposable, HasElement } from \"../interfaces.ts\";\n\nexport abstract class AbstractBaseRenderer implements Disposable, HasElement {\n\t/**\n\t * 修改背景的流动速度,数字越大越快,默认为 8\n\t * @param speed 背景的流动速度,默认为 8\n\t */\n\tabstract setFlowSpeed(speed: number): void;\n\t/**\n\t * 修改背景的渲染比例,默认是 0.5\n\t *\n\t * 一般情况下这个程度既没有明显瑕疵也不会特别吃性能\n\t * @param scale 背景的渲染比例\n\t */\n\tabstract setRenderScale(scale: number): void;\n\t/**\n\t * 是否启用静态模式,即图片在更换后就会保持静止状态并禁用更新,以节省性能\n\t * @param enable 是否启用静态模式\n\t */\n\tabstract setStaticMode(enable: boolean): void;\n\t/**\n\t * 修改背景动画帧率,默认是 30 FPS\n\t *\n\t * 如果设置成 0 则会停止动画\n\t * @param fps 目标帧率,默认 30 FPS\n\t */\n\tabstract setFPS(fps: number): void;\n\t/**\n\t * 暂停背景动画,画面即便是更新了图片也不会发生变化\n\t */\n\tabstract pause(): void;\n\t/**\n\t * 恢复播放背景动画\n\t */\n\tabstract resume(): void;\n\t/**\n\t * 设置背景专辑资源,纹理加载并设置完成后会返回\n\t * @param albumSource 专辑的资源链接,可以是图片或视频链接,抑或是任意 img/video 元素,如果提供字符串链接且为视频则需要指定第二个参数\n\t */\n\tabstract setAlbum(\n\t\talbumSource: string | HTMLImageElement | HTMLVideoElement,\n\t\tisVideo?: boolean,\n\t): Promise<void>;\n\t/**\n\t * 设置低频的音量大小,范围在 80hz-120hz 之间为宜,取值范围在 [0.0-1.0] 之间\n\t *\n\t * 部分渲染器会根据音量大小调整背景效果(例如根据鼓点跳动)\n\t *\n\t * 如果无法获取到类似的数据,请传入 1.0 作为默认值,或不做任何处理(默认值即 1.0)\n\t * @param volume 低频的音量大小,范围在 50hz-120hz 之间为宜,取值范围在 [0.0-1.0] 之间\n\t */\n\tabstract setLowFreqVolume(volume: number): void;\n\t/**\n\t * 设置背景是否根据“是否有歌词”这个特征调整自身效果,例如有歌词时会变得更加活跃\n\t *\n\t * 部分渲染器会根据这个特征调整自身效果\n\t *\n\t * 如果不确定是否需要赋值或无法知晓是否包含歌词,请传入 true 或不做任何处理(默认值为 true)\n\t *\n\t * @param hasLyric 是否有歌词,如不确定是否需要赋值,请传入 true 或不做任何处理(默认值为 true)\n\t */\n\tabstract setHasLyric(hasLyric: boolean): void;\n\tabstract dispose(): void;\n\tabstract getElement(): HTMLElement;\n}\n\nfunction clamp1(x: number): number {\n\treturn Math.max(1, x);\n}\n\nexport abstract class BaseRenderer extends AbstractBaseRenderer {\n\tprivate observer: ResizeObserver;\n\tprotected flowSpeed = 1;\n\tprotected currerntRenderScale = 0.75;\n\tconstructor(protected canvas: HTMLCanvasElement) {\n\t\tsuper();\n\t\tthis.observer = new ResizeObserver(() => {\n\t\t\tconst width = clamp1(\n\t\t\t\tcanvas.clientWidth * window.devicePixelRatio * this.currerntRenderScale,\n\t\t\t);\n\t\t\tconst height = clamp1(\n\t\t\t\tcanvas.clientHeight *\n\t\t\t\t\twindow.devicePixelRatio *\n\t\t\t\t\tthis.currerntRenderScale,\n\t\t\t);\n\t\t\tthis.onResize(width, height);\n\t\t});\n\t\tthis.observer.observe(canvas);\n\t}\n\tsetRenderScale(scale: number): void {\n\t\tthis.currerntRenderScale = scale;\n\t\tthis.onResize(\n\t\t\tthis.canvas.clientWidth *\n\t\t\t\twindow.devicePixelRatio *\n\t\t\t\tthis.currerntRenderScale,\n\t\t\tthis.canvas.clientHeight *\n\t\t\t\twindow.devicePixelRatio *\n\t\t\t\tthis.currerntRenderScale,\n\t\t);\n\t}\n\t/**\n\t * 当画板元素大小发生变化时此函数会被调用\n\t * 可以在此处重设和渲染器相关的尺寸设置\n\t * 考虑到初始化的时候元素不一定在文档中或出于某些特殊样式状态,尺寸长宽有可能会为 0,请注意进行特判处理\n\t * @param width 画板元素实际的物理像素宽度,有可能为 0\n\t * @param height 画板元素实际的物理像素高度,有可能为 0\n\t */\n\tprotected onResize(width: number, height: number): void {\n\t\tthis.canvas.width = width;\n\t\tthis.canvas.height = height;\n\t}\n\t/**\n\t * 修改背景的流动速度,数字越大越快,默认为 1\n\t * @param speed 背景的流动速度,默认为 1\n\t */\n\tsetFlowSpeed(speed: number): void {\n\t\tthis.flowSpeed = speed;\n\t}\n\t/**\n\t * 是否启用静态模式,即图片在更换后就会保持静止状态并禁用更新,以节省性能\n\t * @param enable 是否启用静态模式\n\t */\n\tabstract override setStaticMode(enable: boolean): void;\n\t/**\n\t * 修改背景动画帧率,默认是 30 FPS\n\t *\n\t * 如果设置成 0 则会停止动画\n\t * @param fps 目标帧率,默认 30 FPS\n\t */\n\tabstract override setFPS(fps: number): void;\n\t/**\n\t * 暂停背景动画,画面即便是更新了图片也不会发生变化\n\t */\n\tabstract override pause(): void;\n\t/**\n\t * 恢复播放背景动画\n\t */\n\tabstract override resume(): void;\n\t/**\n\t * 设置背景专辑资源,纹理加载并设置完成后会返回\n\t * @param albumSource 专辑的资源链接,可以是图片或视频链接,抑或是任意 img/video 元素,如果提供字符串链接且为视频则需要指定第二个参数\n\t */\n\tabstract override setAlbum(\n\t\talbumSource: string | HTMLImageElement | HTMLVideoElement,\n\t\tisVideo?: boolean,\n\t): Promise<void>;\n\tdispose(): void {\n\t\tthis.observer.disconnect();\n\t\tthis.canvas.remove();\n\t}\n\toverride getElement(): HTMLElement {\n\t\treturn this.canvas;\n\t}\n}\n","export function loadImage(imageUrl: string): Promise<HTMLImageElement> {\n\treturn new Promise((resolve, reject) => {\n\t\tconst img = document.createElement(\"img\");\n\t\timg.onload = () => resolve(img);\n\t\timg.onerror = reject;\n\t\timg.src = imageUrl;\n\t\timg.crossOrigin = \"anonymous\";\n\t\timg.loading = \"eager\";\n\t});\n}\n\nexport function loadVideo(videoUrl: string): Promise<HTMLVideoElement> {\n\treturn new Promise((resolve, reject) => {\n\t\tconst video = document.createElement(\"video\");\n\t\tlet playing = false;\n\t\tlet timeupdate = false;\n\t\tlet rejected = false;\n\t\tvideo.addEventListener(\n\t\t\t\"playing\",\n\t\t\t() => {\n\t\t\t\tplaying = true;\n\t\t\t\tcheckReady();\n\t\t\t},\n\t\t\ttrue,\n\t\t);\n\t\tvideo.addEventListener(\n\t\t\t\"timeupdate\",\n\t\t\t() => {\n\t\t\t\ttimeupdate = true;\n\t\t\t\tcheckReady();\n\t\t\t},\n\t\t\ttrue,\n\t\t);\n\t\tvideo.addEventListener(\n\t\t\t\"error\",\n\t\t\t(err) => {\n\t\t\t\trejected = true;\n\t\t\t\treject(err);\n\t\t\t},\n\t\t\ttrue,\n\t\t);\n\t\tfunction checkReady() {\n\t\t\tif (playing && timeupdate && !rejected) {\n\t\t\t\tresolve(video);\n\t\t\t}\n\t\t}\n\t\tvideo.src = videoUrl;\n\t\tvideo.playsInline = true;\n\t\tvideo.crossOrigin = \"anonymous\";\n\t\tvideo.autoplay = true;\n\t\tvideo.loop = true;\n\t\tvideo.muted = true;\n\t\tvideo.play();\n\t});\n}\n\nexport function loadResourceFromUrl(\n\turl: string,\n\tisVideo = false,\n): Promise<HTMLImageElement | HTMLVideoElement> {\n\treturn isVideo ? loadVideo(url) : loadImage(url);\n}\n\nexport function loadResourceFromElement(\n\telement: HTMLImageElement | HTMLVideoElement,\n): Promise<HTMLImageElement | HTMLVideoElement> {\n\treturn new Promise((resolve, reject) => {\n\t\tif (\n\t\t\telement instanceof HTMLImageElement\n\t\t\t\t? element.complete\n\t\t\t\t: element.readyState >= 3\n\t\t) {\n\t\t\tresolve(element);\n\t\t} else {\n\t\t\telement.onload = () => resolve(element);\n\t\t\telement.onerror = reject;\n\t\t}\n\t});\n}\n","export function blurImage(\n\timageData: ImageData,\n\tradius: number,\n\tquality: number,\n): void {\n\tconst pixels = imageData.data;\n\tconst width = imageData.width;\n\tconst height = imageData.height;\n\n\tlet rsum: number;\n\tlet gsum: number;\n\tlet bsum: number;\n\tlet asum: number;\n\tlet x: number;\n\tlet y: number;\n\tlet i: number;\n\tlet p: number;\n\tlet p1: number;\n\tlet p2: number;\n\tlet yp: number;\n\tlet yi: number;\n\tlet yw: number;\n\tconst wm = width - 1;\n\tconst hm = height - 1;\n\tconst rad1x = radius + 1;\n\tconst divx = radius + rad1x;\n\tconst rad1y = radius + 1;\n\tconst divy = radius + rad1y;\n\tconst div2 = 1 / (divx * divy);\n\n\tconst r: number[] = [];\n\tconst g: number[] = [];\n\tconst b: number[] = [];\n\tconst a: number[] = [];\n\n\tconst vmin: number[] = [];\n\tconst vmax: number[] = [];\n\n\twhile (quality-- > 0) {\n\t\tyw = yi = 0;\n\n\t\tfor (y = 0; y < height; y++) {\n\t\t\trsum = pixels[yw] * rad1x;\n\t\t\tgsum = pixels[yw + 1] * rad1x;\n\t\t\tbsum = pixels[yw + 2] * rad1x;\n\t\t\tasum = pixels[yw + 3] * rad1x;\n\n\t\t\tfor (i = 1; i <= radius; i++) {\n\t\t\t\tp = yw + ((i > wm ? wm : i) << 2);\n\t\t\t\trsum += pixels[p++];\n\t\t\t\tgsum += pixels[p++];\n\t\t\t\tbsum += pixels[p++];\n\t\t\t\tasum += pixels[p];\n\t\t\t}\n\n\t\t\tfor (x = 0; x < width; x++) {\n\t\t\t\tr[yi] = rsum;\n\t\t\t\tg[yi] = gsum;\n\t\t\t\tb[yi] = bsum;\n\t\t\t\ta[yi] = asum;\n\n\t\t\t\tif (y === 0) {\n\t\t\t\t\tvmin[x] = Math.min(x + rad1x, wm) << 2;\n\t\t\t\t\tvmax[x] = Math.max(x - radius, 0) << 2;\n\t\t\t\t}\n\n\t\t\t\tp1 = yw + vmin[x];\n\t\t\t\tp2 = yw + vmax[x];\n\n\t\t\t\trsum += pixels[p1++] - pixels[p2++];\n\t\t\t\tgsum += pixels[p1++] - pixels[p2++];\n\t\t\t\tbsum += pixels[p1++] - pixels[p2++];\n\t\t\t\tasum += pixels[p1] - pixels[p2];\n\n\t\t\t\tyi++;\n\t\t\t}\n\t\t\tyw += width << 2;\n\t\t}\n\n\t\tfor (x = 0; x < width; x++) {\n\t\t\typ = x;\n\t\t\trsum = r[yp] * rad1y;\n\t\t\tgsum = g[yp] * rad1y;\n\t\t\tbsum = b[yp] * rad1y;\n\t\t\tasum = a[yp] * rad1y;\n\n\t\t\tfor (i = 1; i <= radius; i++) {\n\t\t\t\typ += i > hm ? 0 : width;\n\t\t\t\trsum += r[yp];\n\t\t\t\tgsum += g[yp];\n\t\t\t\tbsum += b[yp];\n\t\t\t\tasum += a[yp];\n\t\t\t}\n\n\t\t\tyi = x << 2;\n\t\t\tfor (y = 0; y < height; y++) {\n\t\t\t\tpixels[yi] = (rsum * div2 + 0.5) | 0;\n\t\t\t\tpixels[yi + 1] = (gsum * div2 + 0.5) | 0;\n\t\t\t\tpixels[yi + 2] = (bsum * div2 + 0.5) | 0;\n\t\t\t\tpixels[yi + 3] = (asum * div2 + 0.5) | 0;\n\n\t\t\t\tif (x === 0) {\n\t\t\t\t\tvmin[y] = Math.min(y + rad1y, hm) * width;\n\t\t\t\t\tvmax[y] = Math.max(y - radius, 0) * width;\n\t\t\t\t}\n\n\t\t\t\tp1 = x + vmin[y];\n\t\t\t\tp2 = x + vmax[y];\n\n\t\t\t\trsum += r[p1] - r[p2];\n\t\t\t\tgsum += g[p1] - g[p2];\n\t\t\t\tbsum += b[p1] - b[p2];\n\t\t\t\tasum += a[p1] - a[p2];\n\n\t\t\t\tyi += width << 2;\n\t\t\t}\n\t\t}\n\t}\n}\n\nexport function saturateImage(imageData: ImageData, saturation: number): void {\n\tconst pixels = imageData.data;\n\n\tfor (let i = 0; i < pixels.length; i += 4) {\n\t\tconst r = pixels[i];\n\t\tconst g = pixels[i + 1];\n\t\tconst b = pixels[i + 2];\n\t\tconst a = pixels[i + 3];\n\t\tconst gray = r * 0.3 + g * 0.59 + b * 0.11;\n\t\tpixels[i] = gray * (1 - saturation) + r * saturation;\n\t\tpixels[i + 1] = gray * (1 - saturation) + g * saturation;\n\t\tpixels[i + 2] = gray * (1 - saturation) + b * saturation;\n\t\tpixels[i + 3] = a;\n\t}\n}\n\nexport function brightnessImage(\n\timageData: ImageData,\n\tbrightness: number,\n): void {\n\tconst pixels = imageData.data;\n\n\tfor (let i = 0; i < pixels.length; i += 4) {\n\t\tconst r = pixels[i];\n\t\tconst g = pixels[i + 1];\n\t\tconst b = pixels[i + 2];\n\t\tconst a = pixels[i + 3];\n\t\tpixels[i] = r * brightness;\n\t\tpixels[i + 1] = g * brightness;\n\t\tpixels[i + 2] = b * brightness;\n\t\tpixels[i + 3] = a;\n\t}\n}\n\nexport function contrastImage(imageData: ImageData, contrast: number): void {\n\tconst pixels = imageData.data;\n\n\tfor (let i = 0; i < pixels.length; i += 4) {\n\t\tconst r = pixels[i];\n\t\tconst g = pixels[i + 1];\n\t\tconst b = pixels[i + 2];\n\t\tconst a = pixels[i + 3];\n\t\tpixels[i] = (r - 128) * contrast + 128;\n\t\tpixels[i + 1] = (g - 128) * contrast + 128;\n\t\tpixels[i + 2] = (b - 128) * contrast + 128;\n\t\tpixels[i + 3] = a;\n\t}\n}\n","export function clamp(x: number, min: number, max: number): number {\n\treturn Math.min(Math.max(x, min), max);\n}\n\nexport function clamp01(x: number): number {\n\treturn clamp(x, 0, 1);\n}\n\nexport function clampPositive(x: number): number {\n\treturn Math.max(0, x);\n}\n","/** @internal */\nexport interface ControlPointConf {\n\tcx: number;\n\tcy: number;\n\tx: number;\n\ty: number;\n\tur: number;\n\tvr: number;\n\tup: number;\n\tvp: number;\n}\n\n/** @internal */\nexport interface ControlPointPreset {\n\twidth: number;\n\theight: number;\n\tconf: ControlPointConf[];\n}\n\n/** @internal */\nexport const p = (\n\tcx: number,\n\tcy: number,\n\tx: number,\n\ty: number,\n\tur = 0,\n\tvr = 0,\n\tup = 1,\n\tvp = 1,\n) => Object.freeze({ cx, cy, x, y, ur, vr, up, vp }) as ControlPointConf;\n/** @internal */\nexport const preset = (\n\twidth: number,\n\theight: number,\n\tconf: ControlPointConf[],\n) => Object.freeze({ width, height, conf }) as ControlPointPreset;\n\nexport const CONTROL_POINT_PRESETS: ControlPointPreset[] = [\n\t// TODO: 竖屏推荐\n\tpreset(5, 5, [\n\t\tp(0, 0, -1, -1, 0, 0, 1, 1),\n\t\tp(1, 0, -0.5, -1, 0, 0, 1, 1),\n\t\tp(2, 0, 0, -1, 0, 0, 1, 1),\n\t\tp(3, 0, 0.5, -1, 0, 0, 1, 1),\n\t\tp(4, 0, 1, -1, 0, 0, 1, 1),\n\t\tp(0, 1, -1, -0.5, 0, 0, 1, 1),\n\t\tp(1, 1, -0.5, -0.5, 0, 0, 1, 1),\n\t\tp(2, 1, -0.0052029684413368305, -0.6131420587090777, 0, 0, 1, 1),\n\t\tp(3, 1, 0.5884227308309977, -0.3990805107556692, 0, 0, 1, 1),\n\t\tp(4, 1, 1, -0.5, 0, 0, 1, 1),\n\t\tp(0, 2, -1, 0, 0, 0, 1, 1),\n\t\tp(1, 2, -0.4210024670505933, -0.11895058380429502, 0, 0, 1, 1),\n\t\tp(2, 2, -0.1019613423315412, -0.023812118047224606, 0, -47, 0.629, 0.849),\n\t\tp(3, 2, 0.40275125660925437, -0.06345314544600389, 0, 0, 1, 1),\n\t\tp(4, 2, 1, 0, 0, 0, 1, 1),\n\t\tp(0, 3, -1, 0.5, 0, 0, 1, 1),\n\t\tp(1, 3, 0.06801958477287173, 0.5205913248960121, -31, -45, 1, 1),\n\t\tp(2, 3, 0.21446469120128908, 0.29331610114301043, 6, -56, 0.566, 1.321),\n\t\tp(3, 3, 0.5, 0.5, 0, 0, 1, 1),\n\t\tp(4, 3, 1, 0.5, 0, 0, 1, 1),\n\t\tp(0, 4, -1, 1, 0, 0, 1, 1),\n\t\tp(1, 4, -0.31378372841550195, 1, 0, 0, 1, 1),\n\t\tp(2, 4, 0.26153633255328046, 1, 0, 0, 1, 1),\n\t\tp(3, 4, 0.5, 1, 0, 0, 1, 1),\n\t\tp(4, 4, 1, 1, 0, 0, 1, 1),\n\t]),\n\t// TODO: 横屏推荐\n\tpreset(4, 4, [\n\t\tp(0, 0, -1, -1, 0, 0, 1, 1),\n\t\tp(1, 0, -0.33333333333333337, -1, 0, 0, 1, 1),\n\t\tp(2, 0, 0.33333333333333326, -1, 0, 0, 1, 1),\n\t\tp(3, 0, 1, -1, 0, 0, 1, 1),\n\t\tp(0, 1, -1, -0.04495399932657351, 0, 0, 1, 1),\n\t\tp(1, 1, -0.24056117520129328, -0.22465999020104, 0, 0, 1, 1),\n\t\tp(2, 1, 0.334758885767489, -0.00531297192779423, 0, 0, 1, 1),\n\t\tp(3, 1, 0.9989920470678106, -0.3382976020775408, 8, 0, 0.566, 1.792),\n\t\tp(0, 2, -1, 0.33333333333333326, 0, 0, 1, 1),\n\t\tp(1, 2, -0.3425497314639411, -0.000027501607956947893, 0, 0, 1, 1),\n\t\tp(2, 2, 0.3321437945812673, 0.1981776353859399, 0, 0, 1, 1),\n\t\tp(3, 2, 1, 0.0766118180296832, 0, 0, 1, 1),\n\t\tp(0, 3, -1, 1, 0, 0, 1, 1),\n\t\tp(1, 3, -0.33333333333333337, 1, 0, 0, 1, 1),\n\t\tp(2, 3, 0.33333333333333326, 1, 0, 0, 1, 1),\n\t\tp(3, 3, 1, 1, 0, 0, 1, 1),\n\t]),\n\tpreset(4, 4, [\n\t\tp(0, 0, -1, -1, 0, 0, 1, 2.075),\n\t\tp(1, 0, -0.33333333333333337, -1, 0, 0, 1, 1),\n\t\tp(2, 0, 0.33333333333333326, -1, 0, 0, 1, 1),\n\t\tp(3, 0, 1, -1, 0, 0, 1, 1),\n\t\tp(0, 1, -1, -0.4545779491139603, 0, 0, 1, 1),\n\t\tp(1, 1, -0.33333333333333337, -0.33333333333333337, 0, 0, 1, 1),\n\t\tp(2, 1, 0.0889403142626457, -0.6025711180694033, -32, 45, 1, 1),\n\t\tp(3, 1, 1, -0.33333333333333337, 0, 0, 1, 1),\n\t\tp(0, 2, -1, -0.07402408608567845, 1, 0, 1, 0.094),\n\t\tp(1, 2, -0.2719422694359541, 0.09775369930903222, 25, -18, 1.321, 0),\n\t\tp(2, 2, 0.19877414408395877, 0.4307383294587789, 48, -40, 0.755, 0.975),\n\t\tp(3, 2, 1, 0.33333333333333326, -37, 0, 1, 1),\n\t\tp(0, 3, -1, 1, 0, 0, 1, 1),\n\t\tp(1, 3, -0.33333333333333337, 1, 0, 0, 1, 1),\n\t\tp(2, 3, 0.5125850864305672, 1, -20, -18, 0, 1.604),\n\t\tp(3, 3, 1, 1, 0, 0, 1, 1),\n\t]),\n\tpreset(5, 5, [\n\t\tp(0, 0, -1, -1, 0, 0, 1, 1),\n\t\tp(1, 0, -0.4501953125, -1, 0, 55, 1, 2.075),\n\t\tp(2, 0, 0.1953125, -1, 0, 0, 1, 1),\n\t\tp(3, 0, 0.4580078125, -1, 0, -25, 1, 1),\n\t\tp(4, 0, 1, -1, 0, 0, 1, 1),\n\t\tp(0, 1, -1, -0.2514475377525607, -16, 0, 2.327, 0.943),\n\t\tp(1, 1, -0.55859375, -0.6609325945787148, 47, 0, 2.358, 0.377),\n\t\tp(2, 1, 0.232421875, -0.5244375756366635, -66, -25, 1.855, 1.164),\n\t\tp(3, 1, 0.685546875, -0.3753706470552125, 0, 0, 1, 1),\n\t\tp(4, 1, 1, -0.6699125300354287, 0, 0, 1, 1),\n\t\tp(0, 2, -1, 0.035910396862284255, 0, 0, 1, 1),\n\t\tp(1, 2, -0.4921875, 0.005378616309457018, 90, 23, 1, 1.981),\n\t\tp(2, 2, 0.021484375, -0.1365043639066228, 0, 42, 1, 1),\n\t\tp(3, 2, 0.4765625, 0.05925822904974043, -30, 0, 1.95, 0.44),\n\t\tp(4, 2, 1, 0.251428847823418, 0, 0, 1, 1),\n\t\tp(0, 3, -1, 0.6968336464764276, -68, 0, 1, 0.786),\n\t\tp(1, 3, -0.6904296875, 0.5890744209958608, -68, 0, 1, 1),\n\t\tp(2, 3, 0.1845703125, 0.3879238667654693, 61, 0, 1, 1),\n\t\tp(3, 3, 0.60546875, 0.4633553246018661, -47, -59, 0.849, 1.73),\n\t\tp(4, 3, 1, 0.6214021886400309, -33, 0, 0.377, 1.604),\n\t\tp(0, 4, -1, 1, 0, 0, 1, 1),\n\t\tp(1, 4, -0.5, 1, 0, -73, 1, 1),\n\t\tp(2, 4, -0.3271484375, 1, 0, -24, 0.314, 2.704),\n\t\tp(3, 4, 0.5, 1, 0, 0, 1, 1),\n\t\tp(4, 4, 1, 1, 0, 0, 1, 1),\n\t]),\n\tpreset(5, 5, [\n\t\tp(0, 0, -1, -1),\n\t\tp(1, 0, -0.6393, -1, 0, 0, 1, 2.3884),\n\t\tp(2, 0, 0, -1),\n\t\tp(3, 0, 0.5, -1),\n\t\tp(4, 0, 1, -1),\n\t\tp(0, 1, -1, -0.2301),\n\t\tp(1, 1, -0.6934, -0.331, 0, -0.7188, 1, 1.063),\n\t\tp(2, 1, -0.0082, -0.6814, -0.2583, 0, 1.0964, 1),\n\t\tp(3, 1, 0.5836, -0.531, 0.7029, 0, 1.5466, 1),\n\t\tp(4, 1, 1, -0.6407),\n\t\tp(0, 2, -1, 0.2973, 0, 0, 1.8352, 1),\n\t\tp(1, 2, -0.4082, 0.0602),\n\t\tp(2, 2, -0.1803, -0.3646, -0.2998, 0, 1.1513, 1),\n\t\tp(3, 2, 0.477, -0.1027, 0.8903, -0.1882, 1.0807, 0.8551),\n\t\tp(4, 2, 1, -0.2973),\n\t\tp(0, 3, -1, 0.7628, 0, 0, 2.3868, 1),\n\t\tp(1, 3, -0.2525, 0.4814, -0.8406, -1.6199, 1.4093, 1.2215),\n\t\tp(2, 3, 0.3607, 0.2814, -1.0713, -0.0529, 1.0025, 0.7611),\n\t\tp(3, 3, 0.4885, 0.623, 0, 0.8184, 1, 1.2876),\n\t\tp(4, 3, 1, 0.5),\n\t\tp(0, 4, -1, 1),\n\t\tp(1, 4, -0.4033, 1),\n\t\tp(2, 4, 0.2672, 1),\n\t\tp(3, 4, 0.5967, 1),\n\t\tp(4, 4, 1, 1),\n\t]),\n\tpreset(5, 5, [\n\t\tp(0, 0, -1, -1),\n\t\tp(1, 0, -0.2197, -1),\n\t\tp(2, 0, 0.0197, -1),\n\t\tp(3, 0, 0.8033, -1),\n\t\tp(4, 0, 1, -1),\n\t\tp(0, 1, -1, -0.5451),\n\t\tp(1, 1, -0.4885, -0.4035, -1.0246, -0.2268, 1.1936, 0.8005),\n\t\tp(2, 1, -0.1213, -0.2867, 0, -0.6981, 1, 0.809),\n\t\tp(3, 1, 0.3246, -0.5628, 0, -1.2188, 1, 1.044),\n\t\tp(4, 1, 1, -0.3292),\n\t\tp(0, 2, -1, 0.1416),\n\t\tp(1, 2, -0.341, -0.0142, 0, -0.4004, 1, 1.1293),\n\t\tp(2, 2, -0.0393, -0.023, 0.2915, -0.373, 1.044, 0.9879),\n\t\tp(3, 2, 0.3148, -0.0673, -0.7853, -0.8962, 1.4709, 1.0247),\n\t\tp(4, 2, 1, 0.1912),\n\t\tp(0, 3, -1, 0.5),\n\t\tp(1, 3, -0.2689, 0.2743, 0.3404, -0.5248, 1.0184, 0.4391),\n\t\tp(2, 3, 0.0721, 0.269, 0.5302, 0.1244, 0.6723, 0.3225),\n\t\tp(3, 3, 0.4148, 0.3894, -0.6977, -0.6783, 0.8094, 0.9247),\n\t\tp(4, 3, 1, 0.446),\n\t\tp(0, 4, -1, 1),\n\t\tp(1, 4, -0.7311, 1),\n\t\tp(2, 4, 0.323, 1),\n\t\tp(3, 4, 0.6393, 1),\n\t\tp(4, 4, 1, 1),\n\t]),\n] as const;\n","/**\n * @fileoverview\n * 实验性的随机控制点生成函数算法\n * 目的是取代原先大量的预设控制点代码\n */\n\nimport { clamp01 } from \"#utils/clamp.ts\";\nimport {\n\ttype ControlPointConf,\n\ttype ControlPointPreset,\n\tp,\n\tpreset,\n} from \"./cp-presets.ts\";\n\nconst randomRange = (min: number, max: number): number =>\n\tMath.random() * (max - min) + min;\n\nfunction smoothstep(edge0: number, edge1: number, x: number): number {\n\tconst t = clamp01((x - edge0) / (edge1 - edge0));\n\treturn t * t * (3 - 2 * t);\n}\n\nfunction smoothifyControlPoints(\n\tconf: ControlPointConf[],\n\tw: number,\n\th: number,\n\titerations = 2,\n\tfactor = 0.5,\n\tfactorIterationModifier = 0.1,\n): void {\n\tlet grid: ControlPointConf[][] = [];\n\tlet f = factor;\n\n\tfor (let j = 0; j < h; j++) {\n\t\tgrid[j] = [];\n\t\tfor (let i = 0; i < w; i++) {\n\t\t\tgrid[j][i] = conf[j * w + i];\n\t\t}\n\t}\n\n\tconst kernel = [\n\t\t[1, 2, 1],\n\t\t[2, 4, 2],\n\t\t[1, 2, 1],\n\t];\n\tconst kernelSum = 16;\n\n\tfor (let iter = 0; iter < iterations; iter++) {\n\t\tconst newGrid: ControlPointConf[][] = [];\n\t\tfor (let j = 0; j < h; j++) {\n\t\t\tnewGrid[j] = [];\n\t\t\tfor (let i = 0; i < w; i++) {\n\t\t\t\tif (i === 0 || i === w - 1 || j === 0 || j === h - 1) {\n\t\t\t\t\tnewGrid[j][i] = grid[j][i];\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tlet sumX = 0;\n\t\t\t\tlet sumY = 0;\n\t\t\t\tlet sumUR = 0;\n\t\t\t\tlet sumVR = 0;\n\t\t\t\tlet sumUP = 0;\n\t\t\t\tlet sumVP = 0;\n\t\t\t\tfor (let dj = -1; dj <= 1; dj++) {\n\t\t\t\t\tfor (let di = -1; di <= 1; di++) {\n\t\t\t\t\t\tconst weight = kernel[dj + 1][di + 1];\n\t\t\t\t\t\tconst nb = grid[j + dj][i + di];\n\t\t\t\t\t\tsumX += nb.x * weight;\n\t\t\t\t\t\tsumY += nb.y * weight;\n\t\t\t\t\t\tsumUR += nb.ur * weight;\n\t\t\t\t\t\tsumVR += nb.vr * weight;\n\t\t\t\t\t\tsumUP += nb.up * weight;\n\t\t\t\t\t\tsumVP += nb.vp * weight;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tconst avgX = sumX / kernelSum;\n\t\t\t\tconst avgY = sumY / kernelSum;\n\t\t\t\tconst avgUR = sumUR / kernelSum;\n\t\t\t\tconst avgVR = sumVR / kernelSum;\n\t\t\t\tconst avgUP = sumUP / kernelSum;\n\t\t\t\tconst avgVP = sumVP / kernelSum;\n\n\t\t\t\tconst cur = grid[j][i];\n\t\t\t\tconst newX = cur.x * (1 - f) + avgX * f;\n\t\t\t\tconst newY = cur.y * (1 - f) + avgY * f;\n\t\t\t\tconst newUR = cur.ur * (1 - f) + avgUR * f;\n\t\t\t\tconst newVR = cur.vr * (1 - f) + avgVR * f;\n\t\t\t\tconst newUP = cur.up * (1 - f) + avgUP * f;\n\t\t\t\tconst newVP = cur.vp * (1 - f) + avgVP * f;\n\t\t\t\tnewGrid[j][i] = p(i, j, newX, newY, newUR, newVR, newUP, newVP);\n\t\t\t}\n\t\t}\n\t\tgrid = newGrid;\n\t\tf = clamp01(f + factorIterationModifier);\n\t}\n\n\tfor (let j = 0; j < h; j++) {\n\t\tfor (let i = 0; i < w; i++) {\n\t\t\tconf[j * w + i] = grid[j][i];\n\t\t}\n\t}\n}\n\nfunction noise(x: number, y: number): number {\n\treturn fract(Math.sin(x * 12.9898 + y * 78.233) * 43758.5453);\n}\n\nfunction fract(x: number): number {\n\treturn x - Math.floor(x);\n}\n\nfunction smoothNoise(x: number, y: number): number {\n\tconst x0 = Math.floor(x);\n\tconst y0 = Math.floor(y);\n\tconst x1 = x0 + 1;\n\tconst y1 = y0 + 1;\n\n\tconst xf = x - x0;\n\tconst yf = y - y0;\n\n\tconst u = xf * xf * (3 - 2 * xf);\n\tconst v = yf * yf * (3 - 2 * yf);\n\n\tconst n00 = noise(x0, y0);\n\tconst n10 = noise(x1, y0);\n\tconst n01 = noise(x0, y1);\n\tconst n11 = noise(x1, y1);\n\n\tconst nx0 = n00 * (1 - u) + n10 * u;\n\tconst nx1 = n01 * (1 - u) + n11 * u;\n\n\treturn nx0 * (1 - v) + nx1 * v;\n}\n\nfunction computeNoiseGradient(\n\tperlinFn: (x: number, y: number) => number,\n\tx: number,\n\ty: number,\n\tepsilon = 0.001,\n): [number, number] {\n\tconst n1 = perlinFn(x + epsilon, y);\n\tconst n2 = perlinFn(x - epsilon, y);\n\tconst n3 = perlinFn(x, y + epsilon);\n\tconst n4 = perlinFn(x, y - epsilon);\n\tconst dx = (n1 - n2) / (2 * epsilon);\n\tconst dy = (n3 - n4) / (2 * epsilon);\n\tconst len = Math.sqrt(dx * dx + dy * dy) || 1;\n\treturn [dx / len, dy / len];\n}\n\nexport function generateControlPoints(\n\twidth: number,\n\theight: number,\n\tvariationFraction: number = randomRange(0.4, 0.6), // = 0.2,\n\tnormalOffset: number = randomRange(0.3, 0.6), // = 0.3,\n\tblendFactor = 0.8,\n\tsmoothIters: number = Math.floor(randomRange(3, 5)), // = 3,\n\tsmoothFactor: number = randomRange(0.2, 0.3), // = 0.3,\n\tsmoothModifier: number = randomRange(-0.1, -0.05), // = -0.05,\n): ControlPointPreset {\n\tconst w = width ?? Math.floor(randomRange(3, 6));\n\tconst h = height ?? Math.floor(randomRange(3, 6));\n\n\tconst conf: ControlPointConf[] = [];\n\tconst dx = w === 1 ? 0 : 2 / (w - 1);\n\tconst dy = h === 1 ? 0 : 2 / (h - 1);\n\n\tfor (let j = 0; j < h; j++) {\n\t\tfor (let i = 0; i < w; i++) {\n\t\t\tconst baseX = (w === 1 ? 0 : i / (w - 1)) * 2 - 1;\n\t\t\tconst baseY = (h === 1 ? 0 : j / (h - 1)) * 2 - 1;\n\n\t\t\tconst isBorder = i === 0 || i === w - 1 || j === 0 || j === h - 1;\n\t\t\tconst pertX = isBorder\n\t\t\t\t? 0\n\t\t\t\t: randomRange(-variationFraction * dx, variationFraction * dx);\n\t\t\tconst pertY = isBorder\n\t\t\t\t? 0\n\t\t\t\t: randomRange(-variationFraction * dy, variationFraction * dy);\n\t\t\tlet x = baseX + pertX;\n\t\t\tlet y = baseY + pertY;\n\n\t\t\tconst ur = isBorder ? 0 : randomRange(-60, 60);\n\t\t\tconst vr = isBorder ? 0 : randomRange(-60, 60);\n\t\t\tconst up = isBorder ? 1 : randomRange(0.8, 1.2);\n\t\t\tconst vp = isBorder ? 1 : randomRange(0.8, 1.2);\n\n\t\t\tif (!isBorder) {\n\t\t\t\tconst uNorm = (baseX + 1) / 2;\n\t\t\t\tconst vNorm = (baseY + 1) / 2;\n\n\t\t\t\tconst [nx, ny] = computeNoiseGradient(smoothNoise, uNorm, vNorm, 0.001);\n\t\t\t\tlet offsetX = nx * normalOffset;\n\t\t\t\tlet offsetY = ny * normalOffset;\n\n\t\t\t\tconst distToBorder = Math.min(uNorm, 1 - uNorm, vNorm, 1 - vNorm); // in [0,0.5]\n\n\t\t\t\tconst weight = smoothstep(0, 1.0, distToBorder);\n\t\t\t\toffsetX *= weight;\n\t\t\t\toffsetY *= weight;\n\n\t\t\t\tx = x * (1 - blendFactor) + (x + offsetX) * blendFactor;\n\t\t\t\ty = y * (1 - blendFactor) + (y + offsetY) * blendFactor;\n\t\t\t}\n\t\t\tconf.push(p(i, j, x, y, ur, vr, up, vp));\n\t\t}\n\t}\n\n\tsmoothifyControlPoints(conf, w, h, smoothIters, smoothFactor, smoothModifier);\n\n\treturn preset(w, h, conf);\n}\n","/**\n * @fileoverview\n * 基于 Mesh Gradient 渐变渲染的渲染器\n * 此渲染应该是 Apple Music 使用的背景渲染方式了\n * 参考内容 https://movingparts.io/gradient-meshes\n */\n\nimport { Mat4, Vec2, Vec3, Vec4 } from \"gl-matrix\";\nimport type { Disposable } from \"../../interfaces.ts\";\nimport {\n\tloadResourceFromElement,\n\tloadResourceFromUrl,\n} from \"../../utils/resource.ts\";\nimport { BaseRenderer } from \"../base.ts\";\nimport { blurImage } from \"../img.ts\";\nimport { generateControlPoints } from \"./cp-generate.ts\";\nimport { CONTROL_POINT_PRESETS } from \"./cp-presets.ts\";\nimport meshFragShader from \"./mesh.frag.glsl?raw\";\nimport meshVertShader from \"./mesh.vert.glsl?raw\";\nimport { clamp01 } from \"#utils/clamp.ts\";\n\nconst quadVertShader = `\nattribute vec2 a_pos;\nvarying vec2 v_uv;\nvoid main() {\n gl_Position = vec4(a_pos, 0.0, 1.0);\n v_uv = a_pos * 0.5 + 0.5;\n}\n`;\n\nconst quadFragShader = `\nprecision mediump float;\nvarying vec2 v_uv;\nuniform sampler2D u_texture;\nuniform float u_alpha;\nvoid main() {\n vec4 color = texture2D(u_texture, v_uv);\n gl_FragColor = vec4(color.rgb, color.a * u_alpha);\n}\n`;\n\nfunction easeInOutSine(x: number): number {\n\treturn -(Math.cos(Math.PI * x) - 1) / 2;\n}\n\ntype RenderingContext = WebGLRenderingContext;\n\nclass GLProgram implements Disposable {\n\tprivate gl: RenderingContext;\n\tprogram: WebGLProgram;\n\tprivate vertexShader: WebGLShader;\n\tprivate fragmentShader: WebGLShader;\n\treadonly attrs: { [name: string]: number };\n\tconstructor(\n\t\tgl: RenderingContext,\n\t\tvertexShaderSource: string,\n\t\tfragmentShaderSource: string,\n\t\tprivate readonly label = \"unknown\",\n\t) {\n\t\tthis.gl = gl;\n\t\tthis.vertexShader = this.createShader(gl.VERTEX_SHADER, vertexShaderSource);\n\t\tthis.fragmentShader = this.createShader(\n\t\t\tgl.FRAGMENT_SHADER,\n\t\t\tfragmentShaderSource,\n\t\t);\n\t\tthis.program = this.createProgram();\n\n\t\tconst num = gl.getProgramParameter(this.program, gl.ACTIVE_ATTRIBUTES);\n\t\tconst attrs: { [name: string]: number } = {};\n\t\tfor (let i = 0; i < num; i++) {\n\t\t\tconst info = gl.getActiveAttrib(this.program, i);\n\t\t\tif (!info) continue;\n\t\t\tconst location = gl.getAttribLocation(this.program, info.name);\n\t\t\tif (location === -1) continue;\n\t\t\tattrs[info.name] = location;\n\t\t}\n\t\tthis.attrs = attrs;\n\t}\n\tprivate createShader(type: number, source: string) {\n\t\tconst gl = this.gl;\n\t\tconst shader = gl.createShader(type);\n\t\tif (!shader) throw new Error(\"Failed to create shader\");\n\t\tgl.shaderSource(shader, source);\n\t\tgl.compileShader(shader);\n\t\tif (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {\n\t\t\tthrow new Error(\n\t\t\t\t`Failed to compile shader for type ${type} \"${\n\t\t\t\t\tthis.label\n\t\t\t\t}\": ${gl.getShaderInfoLog(shader)}`,\n\t\t\t);\n\t\t}\n\t\treturn shader;\n\t}\n\tprivate createProgram() {\n\t\tconst gl = this.gl;\n\t\tconst program = gl.createProgram();\n\t\tif (!program) throw new Error(\"Failed to create program\");\n\t\tgl.attachShader(program, this.vertexShader);\n\t\tgl.attachShader(program, this.fragmentShader);\n\t\tgl.linkProgram(program);\n\t\tgl.validateProgram(program);\n\t\tif (!gl.getProgramParameter(program, gl.LINK_STATUS)) {\n\t\t\tconst errLog = gl.getProgramInfoLog(program);\n\t\t\tgl.deleteProgram(program);\n\t\t\tthrow new Error(`Failed to link program \"${this.label}\": ${errLog}`);\n\t\t}\n\t\treturn program;\n\t}\n\tuse() {\n\t\tconst gl = this.gl;\n\t\tgl.useProgram(this.program);\n\t}\n\tprivate notFoundUniforms: Set<string> = new Set();\n\tprivate warnUniformNotFound(name: string) {\n\t\tif (this.notFoundUniforms.has(name)) return;\n\t\tthis.notFoundUniforms.add(name);\n\t\tconsole.warn(\n\t\t\t`Failed to get uniform location for program \"${this.label}\": ${name}`,\n\t\t);\n\t}\n\tsetUniform1f(name: string, value: number) {\n\t\tconst gl = this.gl;\n\t\tconst location = gl.getUniformLocation(this.program, name);\n\t\tif (!location) this.warnUniformNotFound(name);\n\t\telse gl.uniform1f(location, value);\n\t}\n\tsetUniform2f(name: string, value1: number, value2: number) {\n\t\tconst gl = this.gl;\n\t\tconst location = gl.getUniformLocation(this.program, name);\n\t\tif (!location) this.warnUniformNotFound(name);\n\t\telse gl.uniform2f(location, value1, value2);\n\t}\n\tsetUniform1i(name: string, value: number) {\n\t\tconst gl = this.gl;\n\t\tconst location = gl.getUniformLocation(this.program, name);\n\t\tif (!location) this.warnUniformNotFound(name);\n\t\telse gl.uniform1i(location, value);\n\t}\n\tdispose() {\n\t\tconst gl = this.gl;\n\t\tgl.deleteShader(this.vertexShader);\n\t\tgl.deleteShader(this.fragmentShader);\n\t\tgl.deleteProgram(this.program);\n\t}\n}\n\nclass Mesh implements Disposable {\n\tprotected vertexWidth = 0;\n\tprotected vertexHeight = 0;\n\tprivate vertexBuffer: WebGLBuffer;\n\tprivate indexBuffer: WebGLBuffer;\n\tprivate vertexData: Float32Array;\n\tprivate indexData: Uint16Array;\n\tprivate vertexIndexLength = 0;\n\t// 调试用途,开启线框模式\n\tprivate wireFrame = false;\n\tconstructor(\n\t\tprivate readonly gl: RenderingContext,\n\t\tprivate readonly attrPos: number | undefined,\n\t\tprivate readonly attrColor: number | undefined,\n\t\tprivate readonly attrUV: number | undefined,\n\t) {\n\t\tconst vertexBuf = gl.createBuffer();\n\t\tif (!vertexBuf) throw new Error(\"Failed to create vertex buffer\");\n\t\tthis.vertexBuffer = vertexBuf;\n\t\tconst indexBuf = gl.createBuffer();\n\t\tif (!indexBuf) throw new Error(\"Failed to create index buffer\");\n\t\tthis.indexBuffer = indexBuf;\n\n\t\tthis.bind();\n\n\t\tthis.vertexData = new Float32Array(0);\n\t\tthis.indexData = new Uint16Array(0);\n\n\t\tthis.resize(2, 2);\n\t\tthis.update();\n\t}\n\n\tsetWireFrame(enable: boolean) {\n\t\tthis.wireFrame = enable;\n\t\tthis.resize(this.vertexWidth, this.vertexHeight);\n\t}\n\n\tsetVertexPos(vx: number, vy: number, x: number, y: number): void {\n\t\tconst idx = (vx + vy * this.vertexWidth) * 7;\n\t\tif (idx >= this.vertexData.length - 1) {\n\t\t\tconsole.warn(\"Vertex position out of range\", idx, this.vertexData.length);\n\t\t\treturn;\n\t\t}\n\t\tthis.vertexData[idx] = x;\n\t\tthis.vertexData[idx + 1] = y;\n\t}\n\n\tsetVertexColor(\n\t\tvx: number,\n\t\tvy: number,\n\t\tr: number,\n\t\tg: number,\n\t\tb: number,\n\t): void {\n\t\tconst idx = (vx + vy * this.vertexWidth) * 7 + 2;\n\t\tif (idx >= this.vertexData.length - 2) {\n\t\t\tconsole.warn(\"Vertex color out of range\", idx, this.vertexData.length);\n\t\t\treturn;\n\t\t}\n\t\tthis.vertexData[idx] = r;\n\t\tthis.vertexData[idx + 1] = g;\n\t\tthis.vertexData[idx + 2] = b;\n\t}\n\n\tsetVertexUV(vx: number, vy: number, x: number, y: number): void {\n\t\tconst idx = (vx + vy * this.vertexWidth) * 7 + 5;\n\t\tif (idx >= this.vertexData.length - 1) {\n\t\t\tconsole.warn(\"Vertex UV out of range\", idx, this.vertexData.length);\n\t\t\treturn;\n\t\t}\n\t\tthis.vertexData[idx] = x;\n\t\tthis.vertexData[idx + 1] = y;\n\t}\n\n\t// 批量设置顶点数据的优化方法\n\tsetVertexData(\n\t\tvx: number,\n\t\tvy: number,\n\t\tx: number,\n\t\ty: number,\n\t\tr: number,\n\t\tg: number,\n\t\tb: number,\n\t\tu: number,\n\t\tv: number,\n\t): void {\n\t\tconst idx = (vx + vy * this.vertexWidth) * 7;\n\t\tif (idx >= this.vertexData.length - 6) {\n\t\t\tconsole.warn(\"Vertex data out of range\", idx, this.vertexData.length);\n\t\t\treturn;\n\t\t}\n\t\tconst data = this.vertexData;\n\t\tdata[idx] = x;\n\t\tdata[idx + 1] = y;\n\t\tdata[idx + 2] = r;\n\t\tdata[idx + 3] = g;\n\t\tdata[idx + 4] = b;\n\t\tdata[idx + 5] = u;\n\t\tdata[idx + 6] = v;\n\t}\n\n\tgetVertexIndexLength(): number {\n\t\treturn this.vertexIndexLength;\n\t}\n\n\tdraw() {\n\t\tconst gl = this.gl;\n\n\t\tif (this.wireFrame) {\n\t\t\tgl.drawElements(gl.LINES, this.vertexIndexLength, gl.UNSIGNED_SHORT, 0);\n\t\t} else {\n\t\t\tgl.drawElements(\n\t\t\t\tgl.TRIANGLES,\n\t\t\t\tthis.vertexIndexLength,\n\t\t\t\tgl.UNSIGNED_SHORT,\n\t\t\t\t0,\n\t\t\t);\n\t\t}\n\t}\n\n\tresize(vertexWidth: number, vertexHeight: number): void {\n\t\tthis.vertexWidth = vertexWidth;\n\t\tthis.vertexHeight = vertexHeight;\n\t\t// 2 个顶点坐标 + 3 个颜色值 + 2 个 UV 坐标\n\t\tthis.vertexIndexLength = vertexWidth * vertexHeight * 6;\n\t\tif (this.wireFrame) {\n\t\t\tthis.vertexIndexLength = vertexWidth * vertexHeight * 10;\n\t\t}\n\t\tconst vertexData = new Float32Array(\n\t\t\tvertexWidth * vertexHeight * (2 + 3 + 2),\n\t\t);\n\t\tconst indexData = new Uint16Array(this.vertexIndexLength);\n\t\tthis.vertexData = vertexData;\n\t\tthis.indexData = indexData;\n\t\tfor (let y = 0; y < vertexHeight; y++) {\n\t\t\tfor (let x = 0; x < vertexWidth; x++) {\n\t\t\t\tconst px = (x / (vertexWidth - 1)) * 2 - 1;\n\t\t\t\tconst py = (y / (vertexHeight - 1)) * 2 - 1;\n\t\t\t\tthis.setVertexPos(x, y, px || 0, py || 0);\n\t\t\t\tthis.setVertexColor(x, y, 1, 1, 1);\n\t\t\t\tthis.setVertexUV(x, y, x / (vertexWidth - 1), y / (vertexHeight - 1));\n\t\t\t}\n\t\t}\n\t\tfor (let y = 0; y < vertexHeight - 1; y++) {\n\t\t\tfor (let x = 0; x < vertexWidth - 1; x++) {\n\t\t\t\tif (this.wireFrame) {\n\t\t\t\t\tconst idx = (y * vertexWidth + x) * 10;\n\n\t\t\t\t\tindexData[idx] = y * vertexWidth + x;\n\t\t\t\t\tindexData[idx + 1] = y * vertexWidth + x + 1;\n\n\t\t\t\t\tindexData[idx + 2] = y * vertexWidth + x + 1;\n\t\t\t\t\tindexData[idx + 3] = (y + 1) * vertexWidth + x;\n\n\t\t\t\t\tindexData[idx + 4] = (y + 1) * vertexWidth + x;\n\t\t\t\t\tindexData[idx + 5] = (y + 1) * vertexWidth + x + 1;\n\n\t\t\t\t\tindexData[idx + 6] = (y + 1) * vertexWidth + x + 1;\n\t\t\t\t\tindexData[idx + 7] = y * vertexWidth + x + 1;\n\n\t\t\t\t\tindexData[idx + 8] = y * vertexWidth + x;\n\t\t\t\t\tindexData[idx + 9] = (y + 1) * vertexWidth + x;\n\t\t\t\t} else {\n\t\t\t\t\tconst idx = (y * vertexWidth + x) * 6;\n\t\t\t\t\tindexData[idx] = y * vertexWidth + x;\n\t\t\t\t\tindexData[idx + 1] = y * vertexWidth + x + 1;\n\t\t\t\t\tindexData[idx + 2] = (y + 1) * vertexWidth + x;\n\t\t\t\t\tindexData[idx + 3] = y * vertexWidth + x + 1;\n\t\t\t\t\tindexData[idx + 4] = (y + 1) * vertexWidth + x + 1;\n\t\t\t\t\tindexData[idx + 5] = (y + 1) * vertexWidth + x;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tconst gl = this.gl;\n\t\tgl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.indexBuffer);\n\t\tgl.bufferData(gl.ELEMENT_ARRAY_BUFFER, this.indexData, gl.STATIC_DRAW);\n\t}\n\n\tbind() {\n\t\tconst gl = this.gl;\n\t\tgl.bindBuffer(gl.ARRAY_BUFFER, this.vertexBuffer);\n\t\tgl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.indexBuffer);\n\n\t\tif (this.attrPos !== undefined) {\n\t\t\tgl.vertexAttribPointer(this.attrPos, 2, gl.FLOAT, false, 4 * 7, 0);\n\t\t\tgl.enableVertexAttribArray(this.attrPos);\n\t\t}\n\t\tif (this.attrColor !== undefined) {\n\t\t\tgl.vertexAttribPointer(this.attrColor, 3, gl.FLOAT, false, 4 * 7, 4 * 2);\n\t\t\tgl.enableVertexAttribArray(this.attrColor);\n\t\t}\n\t\tif (this.attrUV !== undefined) {\n\t\t\tgl.vertexAttribPointer(this.attrUV, 2, gl.FLOAT, false, 4 * 7, 4 * 5);\n\t\t\tgl.enableVertexAttribArray(this.attrUV);\n\t\t}\n\t}\n\n\tupdate() {\n\t\tconst gl = this.gl;\n\t\tgl.bindBuffer(gl.ARRAY_BUFFER, this.vertexBuffer);\n\t\tgl.bufferData(gl.ARRAY_BUFFER, this.vertexData, gl.DYNAMIC_DRAW);\n\t}\n\n\tdispose(): void {\n\t\tthis.gl.deleteBuffer(this.vertexBuffer);\n\t\tthis.gl.deleteBuffer(this.indexBuffer);\n\t}\n}\n\nclass ControlPoint {\n\tcolor: Vec3 = Vec3.fromValues(1, 1, 1);\n\tlocation: Vec2 = Vec2.fromValues(0, 0);\n\tuTangent: Vec2 = Vec2.fromValues(0, 0);\n\tvTangent: Vec2 = Vec2.fromValues(0, 0);\n\tprivate _uRot = 0;\n\tprivate _vRot = 0;\n\tprivate _uScale = 1;\n\tprivate _vScale = 1;\n\n\tconstructor() {\n\t\tObject.seal(this);\n\t}\n\n\tget uRot() {\n\t\treturn this._uRot;\n\t}\n\n\tget vRot() {\n\t\treturn this._vRot;\n\t}\n\n\tset uRot(value: number) {\n\t\tthis._uRot = value;\n\t\tthis.updateUTangent();\n\t}\n\n\tset vRot(value: number) {\n\t\tthis._vRot = value;\n\t\tthis.updateVTangent();\n\t}\n\n\tget uScale() {\n\t\treturn this._uScale;\n\t}\n\n\tget vScale() {\n\t\treturn this._vScale;\n\t}\n\n\tset uScale(value: number) {\n\t\tthis._uScale = value;\n\t\tthis.updateUTangent();\n\t}\n\n\tset vScale(value: number) {\n\t\tthis._vScale = value;\n\t\tthis.updateVTangent();\n\t}\n\n\tprivate updateUTangent() {\n\t\tthis.uTangent[0] = Math.cos(this._uRot) * this._uScale;\n\t\tthis.uTangent[1] = Math.sin(this._uRot) * this._uScale;\n\t}\n\n\tprivate updateVTangent() {\n\t\tthis.vTangent[0] = -Math.sin(this._vRot) * this._vScale;\n\t\tthis.vTangent[1] = Math.cos(this._vRot) * this._vScale;\n\t}\n}\n\nconst H = Mat4.fromValues(2, -2, 1, 1, -3, 3, -2, -1, 0, 0, 1, 0, 1, 0, 0, 0);\nconst H_T = Mat4.clone(H).transpose();\n\nfunction meshCoefficients(\n\tp00: ControlPoint,\n\tp01: ControlPoint,\n\tp10: ControlPoint,\n\tp11: ControlPoint,\n\taxis: \"x\" | \"y\",\n\toutput = Mat4.create(),\n): Mat4 {\n\tconst l = (p: ControlPoint) => p.location[axis];\n\tconst u = (p: ControlPoint) => p.uTangent[axis];\n\tconst v = (p: ControlPoint) => p.vTangent[axis];\n\n\toutput[0] = l(p00);\n\toutput[1] = l(p01);\n\toutput[2] = v(p00);\n\toutput[3] = v(p01);\n\toutput[4] = l(p10);\n\toutput[5] = l(p11);\n\toutput[6] = v(p10);\n\toutput[7] = v(p11);\n\toutput[8] = u(p00);\n\toutput[9] = u(p01);\n\toutput[10] = 0;\n\toutput[11] = 0;\n\toutput[12] = u(p10);\n\toutput[13] = u(p11);\n\toutput[14] = 0;\n\toutput[15] = 0;\n\n\treturn output;\n}\n\nfunction colorCoefficients(\n\tp00: ControlPoint,\n\tp01: ControlPoint,\n\tp10: ControlPoint,\n\tp11: ControlPoint,\n\taxis: \"r\" | \"g\" | \"b\",\n\toutput = Mat4.create(),\n): Mat4 {\n\tconst c = (p: ControlPoint) => p.color[axis];\n\toutput.fill(0);\n\toutput[0] = c(p00);\n\toutput[1] = c(p01);\n\toutput[4] = c(p10);\n\toutput[5] = c(p11);\n\t// return Mat4.fromValues(\n\t// c(p00), c(p01), 0, 0,\n\t// c(p10), c(p11), 0, 0,\n\t// 0, 0, 0, 0,\n\t// 0, 0, 0, 0,\n\t// );\n\treturn output;\n}\n\nclass Map2D<T> {\n\tprivate _width = 0;\n\tprivate _height = 0;\n\tprivate _data: T[] = [];\n\tconstructor(width: number, height: number) {\n\t\tthis.resize(width, height);\n\t\tObject.seal(this);\n\t}\n\tresize(width: number, height: number) {\n\t\tthis._width = width;\n\t\tthis._height = height;\n\t\tthis._data = new Array(width * height).fill(0);\n\t}\n\tset(x: number, y: number, value: T) {\n\t\tthis._data[x + y * this._width] = value;\n\t}\n\tget(x: number, y: number) {\n\t\treturn this._data[x + y * this._width];\n\t}\n\tget width() {\n\t\treturn this._width;\n\t}\n\tget height() {\n\t\treturn this._height;\n\t}\n}\n\n// Bicubic Hermite Patch Mesh\nclass BHPMesh extends Mesh {\n\t/**\n\t * 细分级别,越大曲线越平滑,但是性能消耗也越大\n\t */\n\tprivate _subDivisions = 10;\n\tprivate _controlPoints: Map2D<ControlPoint> = new Map2D(3, 3);\n\n\tconstructor(\n\t\tgl: RenderingContext,\n\t\tattrPos: number,\n\t\tattrColor: number,\n\t\tattrUV: number,\n\t) {\n\t\tsuper(gl, attrPos, attrColor, attrUV);\n\t\tthis.resizeControlPoints(3, 3);\n\t\tObject.seal(this);\n\t}\n\toverride setWireFrame(enable: boolean) {\n\t\tsuper.setWireFrame(enable);\n\t\tthis.updateMesh();\n\t}\n\t/**\n\t * 以当前的控制点矩阵大小和细分级别为参考重新设置细分级别,此操作不会重设控制点数据\n\t * @param subDivisions 细分级别\n\t */\n\tresetSubdivition(subDivisions: number) {\n\t\tthis._subDivisions = subDivisions;\n\t\tsuper.resize(\n\t\t\t(this._controlPoints.width - 1) * subDivisions,\n\t\t\t(this._controlPoints.height - 1) * subDivisions,\n\t\t);\n\t}\n\t/**\n\t * 重设控制点矩阵尺寸,将会重置所有控制点的颜色和坐标数据\n\t * 请在调用此方法后重新设置颜色和坐标,并调用 updateMesh 方法更新网格\n\t * @param width 控制点宽度数量,必须大于等于 2\n\t * @param height 控制点高度数量,必须大于等于 2\n\t */\n\tresizeControlPoints(width: number, height: number) {\n\t\tif (!(width >= 2 && height >= 2)) {\n\t\t\tthrow new Error(\"Control points must be larger than 3x3 or equal\");\n\t\t}\n\t\tthis._controlPoints.resize(width, height);\n\t\tfor (let y = 0; y < height; y++) {\n\t\t\tfor (let x = 0; x < width; x++) {\n\t\t\t\tconst point = new ControlPoint();\n\t\t\t\tpoint.location.x = (x / (width - 1)) * 2 - 1;\n\t\t\t\tpoint.location.y = (y / (height - 1)) * 2 - 1;\n\t\t\t\tpoint.uTangent.x = 2 / (width - 1);\n\t\t\t\tpoint.vTangent.y = 2 / (height - 1);\n\t\t\t\tthis._controlPoints.set(x, y, point);\n\t\t\t}\n\t\t}\n\t\tthis.resetSubdivition(this._subDivisions);\n\t}\n\t/**\n\t * 获取指定位置的控制点,然后可以设置颜色和坐标属性\n\t * 留意颜色属性和坐标属性的值范围均参考 WebGL 的定义\n\t * 即颜色各个组件取值 [0-1],坐标取值 [-1, 1]\n\t * 点的位置以画面左下角为原点 (0,0)\n\t * @param x 需要获取的控制点的 x 坐标\n\t * @param y 需要获取的控制点的 y 坐标\n\t * @returns 控制点对象\n\t */\n\tgetControlPoint(x: number, y: number) {\n\t\treturn this._controlPoints.get(x, y);\n\t}\n\t// 预分配重复使用的矩阵,避免频繁创建\n\tprivate tempX = Mat4.create();\n\tprivate tempY = Mat4.create();\n\tprivate tempR = Mat4.create();\n\tprivate tempG = Mat4.create();\n\tprivate tempB = Mat4.create();\n\n\tprivate tempXAcc = Mat4.create();\n\tprivate tempYAcc = Mat4.create();\n\tprivate tempRAcc = Mat4.create();\n\tprivate tempGAcc = Mat4.create();\n\tprivate tempBAcc = Mat4.create();\n\n\tprivate tempUx = Vec4.create();\n\tprivate tempUy = Vec4.create();\n\tprivate tempUr = Vec4.create();\n\tprivate tempUg = Vec4.create();\n\tprivate tempUb = Vec4.create();\n\n\tprivate precomputeMatrix(M: Mat4, output: Mat4) {\n\t\toutput.copy(M).transpose();\n\t\tMat4.mul(output, output, H);\n\t\tMat4.mul(output, H_T, output);\n\t\treturn output;\n\t}\n\n\t/**\n\t * 更新最终呈现的网格数据,此方法应在所有控制点或细分参数的操作完成后调用\n\t */\n\tupdateMesh() {\n\t\tconst subDivM1 = this._subDivisions - 1;\n\t\tconst tW = subDivM1 * (this._controlPoints.height - 1);\n\t\tconst tH = subDivM1 * (this._controlPoints.width - 1);\n\t\tconst controlPointsWidth = this._controlPoints.width;\n\t\tconst controlPointsHeight = this._controlPoints.height;\n\t\tconst subDivisions = this._subDivisions;\n\n\t\t// 预计算常用值\n\t\tconst invSubDivM1 = 1 / subDivM1;\n\t\tconst invTH = 1 / tH;\n\t\tconst invTW = 1 / tW;\n\n\t\t// 预计算 u 和 v 的幂次\n\t\tconst normPowers = new Float32Array(subDivisions * 4);\n\t\tfor (let i = 0; i < subDivisions; i++) {\n\t\t\tconst norm = i * invSubDivM1;\n\t\t\tconst idx = i * 4;\n\t\t\tnormPowers[idx] = norm ** 3;\n\t\t\tnormPowers[idx + 1] = norm ** 2;\n\t\t\tnormPowers[idx + 2] = norm;\n\t\t\tnormPowers[idx + 3] = 1;\n\t\t}\n\n\t\tfor (let x = 0; x < controlPointsWidth - 1; x++) {\n\t\t\tfor (let y = 0; y < controlPointsHeight - 1; y++) {\n\t\t\t\tconst p00 = this._controlPoints.get(x, y);\n\t\t\t\tconst p01 = this._controlPoints.get(x, y + 1);\n\t\t\t\tconst p10 = this._controlPoints.get(x + 1, y);\n\t\t\t\tconst p11 = this._controlPoints.get(x + 1, y + 1);\n\n\t\t\t\t// 复用预分配的矩阵\n\t\t\t\tmeshCoefficients(p00, p01, p10, p11, \"x\", this.tempX);\n\t\t\t\tmeshCoefficients(p00, p01, p10, p11, \"y\", this.tempY);\n\t\t\t\tcolorCoefficients(p00, p01, p10, p11, \"r\", this.tempR);\n\t\t\t\tcolorCoefficients(p00, p01, p10, p11, \"g\", this.tempG);\n\t\t\t\tcolorCoefficients(p00, p01, p10, p11, \"b\", this.tempB);\n\n\t\t\t\t// 预计算累加矩阵\n\t\t\t\tthis.precomputeMatrix(this.tempX, this.tempXAcc);\n\t\t\t\tthis.precomputeMatrix(this.tempY, this.tempYAcc);\n\t\t\t\tthis.precomputeMatrix(this.tempR, this.tempRAcc);\n\t\t\t\tthis.precomputeMatrix(this.tempG, this.tempGAcc);\n\t\t\t\tthis.precomputeMatrix(this.tempB, this.tempBAcc);\n\n\t\t\t\tconst sX = x / (controlPointsWidth - 1);\n\t\t\t\tconst sY = y / (controlPointsHeight - 1);\n\t\t\t\tconst baseVx = y * subDivisions;\n\t\t\t\tconst baseVy = x * subDivisions;\n\n\t\t\t\tfor (let u = 0; u < subDivisions; u++) {\n\t\t\t\t\tconst vxOffset = baseVx + u;\n\t\t\t\t\tconst uIdx = u * 4;\n\n\t\t\t\t\tthis.tempUx[0] = normPowers[uIdx];\n\t\t\t\t\tthis.tempUx[1] = normPowers[uIdx + 1];\n\t\t\t\t\tthis.tempUx[2] = normPowers[uIdx + 2];\n\t\t\t\t\tthis.tempUx[3] = normPowers[uIdx + 3];\n\t\t\t\t\tVec4.transformMat4(this.tempUx, this.tempUx, this.tempXAcc);\n\n\t\t\t\t\tthis.tempUy[0] = normPowers[uIdx];\n\t\t\t\t\tthis.tempUy[1] = normPowers[uIdx + 1];\n\t\t\t\t\tthis.tempUy[2] = normPowers[uIdx + 2];\n\t\t\t\t\tthis.tempUy[3] = normPowers[uIdx + 3];\n\t\t\t\t\tVec4.transformMat4(this.tempUy, this.tempUy, this.tempYAcc);\n\n\t\t\t\t\tthis.tempUr[0] = normPowers[uIdx];\n\t\t\t\t\tthis.tempUr[1] = normPowers[uIdx + 1];\n\t\t\t\t\tthis.tempUr[2] = normPowers[uIdx + 2];\n\t\t\t\t\tthis.tempUr[3] = normPowers[uIdx + 3];\n\t\t\t\t\tVec4.transformMat4(this.tempUr, this.tempUr, this.tempRAcc);\n\n\t\t\t\t\tthis.tempUg[0] = normPowers[uIdx];\n\t\t\t\t\tthis.tempUg[1] = normPowers[uIdx + 1];\n\t\t\t\t\tthis.tempUg[2] = normPowers[uIdx + 2];\n\t\t\t\t\tthis.tempUg[3] = normPowers[uIdx + 3];\n\t\t\t\t\tVec4.transformMat4(this.tempUg, this.tempUg, this.tempGAcc);\n\n\t\t\t\t\tthis.tempUb[0] = normPowers[uIdx];\n\t\t\t\t\tthis.tempUb[1] = normPowers[uIdx + 1];\n\t\t\t\t\tthis.tempUb[2] = normPowers[uIdx + 2];\n\t\t\t\t\tthis.tempUb[3] = normPowers[uIdx + 3];\n\t\t\t\t\tVec4.transformMat4(this.tempUb, this.tempUb, this.tempBAcc);\n\n\t\t\t\t\tfor (let v = 0; v < subDivisions; v++) {\n\t\t\t\t\t\tconst vy = baseVy + v;\n\t\t\t\t\t\tconst vIdx = v * 4;\n\n\t\t\t\t\t\tconst v0 = normPowers[vIdx];\n\t\t\t\t\t\tconst v1 = normPowers[vIdx + 1];\n\t\t\t\t\t\tconst v2 = normPowers[vIdx + 2];\n\t\t\t\t\t\tconst v3 = normPowers[vIdx + 3];\n\n\t\t\t\t\t\tconst px =\n\t\t\t\t\t\t\tv0 * this.tempUx[0] +\n\t\t\t\t\t\t\tv1 * this.tempUx[1] +\n\t\t\t\t\t\t\tv2 * this.tempUx[2] +\n\t\t\t\t\t\t\tv3 * this.tempUx[3];\n\t\t\t\t\t\tconst py =\n\t\t\t\t\t\t\tv0 * this.tempUy[0] +\n\t\t\t\t\t\t\tv1 * this.tempUy[1] +\n\t\t\t\t\t\t\tv2 * this.tempUy[2] +\n\t\t\t\t\t\t\tv3 * this.tempUy[3];\n\t\t\t\t\t\tconst pr =\n\t\t\t\t\t\t\tv0 * this.tempUr[0] +\n\t\t\t\t\t\t\tv1 * this.tempUr[1] +\n\t\t\t\t\t\t\tv2 * this.tempUr[2] +\n\t\t\t\t\t\t\tv3 * this.tempUr[3];\n\t\t\t\t\t\tconst pg =\n\t\t\t\t\t\t\tv0 * this.tempUg[0] +\n\t\t\t\t\t\t\tv1 * this.tempUg[1] +\n\t\t\t\t\t\t\tv2 * this.tempUg[2] +\n\t\t\t\t\t\t\tv3 * this.tempUg[3];\n\t\t\t\t\t\tconst pb =\n\t\t\t\t\t\t\tv0 * this.tempUb[0] +\n\t\t\t\t\t\t\tv1 * this.tempUb[1] +\n\t\t\t\t\t\t\tv2 * this.tempUb[2] +\n\t\t\t\t\t\t\tv3 * this.tempUb[3];\n\n\t\t\t\t\t\tconst uvX = sX + v * invTH;\n\t\t\t\t\t\tconst uvY = 1 - sY - u * invTW;\n\n\t\t\t\t\t\t// 使用批量设置方法减少数组访问次数\n\t\t\t\t\t\tthis.setVertexData(vxOffset, vy, px, py, pr, pg, pb, uvX, uvY);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tthis.update();\n\t}\n}\n\nclass GLTexture implements Disposable {\n\treadonly tex: WebGLTexture;\n\n\tconstructor(\n\t\tprivate gl: WebGLRenderingContext,\n\t\talbumImageData: ImageData,\n\t) {\n\t\tconst albumTexture = gl.createTexture();\n\t\tif (!albumTexture) throw new Error(\"Failed to create texture\");\n\t\tthis.tex = albumTexture;\n\t\tgl.activeTexture(gl.TEXTURE0);\n\t\tgl.bindTexture(gl.TEXTURE_2D, albumTexture);\n\t\tgl.texImage2D(\n\t\t\tgl.TEXTURE_2D,\n\t\t\t0,\n\t\t\tgl.RGBA,\n\t\t\tgl.RGBA,\n\t\t\tgl.UNSIGNED_BYTE,\n\t\t\talbumImageData,\n\t\t);\n\t\tgl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);\n\t\tgl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);\n\t\tgl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.MIRRORED_REPEAT);\n\t\tgl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.MIRRORED_REPEAT);\n\t}\n\n\tbind() {\n\t\tthis.gl.bindTexture(this.gl.TEXTURE_2D, this.tex);\n\t}\n\n\tdispose(): void {\n\t\tthis.gl.deleteTexture(this.tex);\n\t}\n}\n\nfunction createOffscreenCanvas(width: number, height: number) {\n\tif (\"OffscreenCanvas\" in window) return new OffscreenCanvas(width, height);\n\tconst canvas = document.createElement(\"canvas\");\n\tcanvas.width = width;\n\tcanvas.height = height;\n\treturn canvas;\n}\n\ninterface MeshState {\n\tmesh: BHPMesh;\n\ttexture: GLTexture;\n\talpha: number;\n}\n\nexport class MeshGradientRenderer extends BaseRenderer {\n\tprivate gl: RenderingContext;\n\tprivate lastFrameTime = 0;\n\tprivate frameTime = 0;\n\t// private currentImageData?: ImageData;\n\tprivate lastTickTime = 0;\n\tprivate smoothedVolume = 0;\n\tprivate volume = 0;\n\tprivate tickHandle = 0;\n\tprivate maxFPS = 60;\n\tprivate paused = false;\n\tprivate staticMode = false;\n\tprivate mainProgram: GLProgram;\n\tprivate quadProgram: GLProgram;\n\tprivate quadBuffer: WebGLBuffer;\n\tprivate fbo: WebGLFramebuffer | null = null;\n\tprivate fboTexture: WebGLTexture | null = null;\n\tprivate manualControl = false;\n\tprivate reduceImageSizeCanvas = createOffscreenCanvas(\n\t\t32,\n\t\t32,\n\t) as HTMLCanvasElement;\n\tprivate targetSize = Vec2.fromValues(0, 0);\n\tprivate currentSize = Vec2.fromValues(0, 0);\n\tprivate isNoCover = true;\n\tprivate meshStates: MeshState[] = [];\n\tprivate _disposed = false;\n\t// 性能监控\n\tprivate frameCount = 0;\n\tprivate lastFPSUpdate = 0;\n\tprivate currentFPS = 0;\n\tprivate enablePerformanceMonitoring = false;\n\n\tsetManualControl(enable: boolean): void {\n\t\tthis.manualControl = enable;\n\t}\n\n\tsetWireFrame(enable: boolean): void {\n\t\tfor (const state of this.meshStates) {\n\t\t\tstate.mesh.setWireFrame(enable);\n\t\t}\n\t}\n\n\tgetControlPoint(x: number, y: number): ControlPoint | undefined {\n\t\treturn this.meshStates[this.meshStates.length - 1]?.mesh?.getControlPoint(\n\t\t\tx,\n\t\t\ty,\n\t\t);\n\t}\n\n\tresizeControlPoints(width: number, height: number): void {\n\t\tthis.meshStates[this.meshStates.length - 1]?.mesh?.resizeControlPoints(\n\t\t\twidth,\n\t\t\theight,\n\t\t);\n\t}\n\n\tresetSubdivition(subDivisions: number): void {\n\t\tthis.meshStates[this.meshStates.length - 1]?.mesh?.resetSubdivition(\n\t\t\tsubDivisions,\n\t\t);\n\t}\n\n\tprivate onTick(tickTime: number) {\n\t\tthis.tickHandle = 0;\n\t\tif (this.paused) return;\n\t\tif (this._disposed) return;\n\n\t\t// 更新性能统计\n\t\tthis.updatePerformanceStats(tickTime);\n\n\t\tconst interval = 1000 / this.maxFPS;\n\t\tconst delta = tickTime - this.lastTickTime;\n\t\tif (delta < interval) {\n\t\t\tthis.requestTick();\n\t\t\treturn;\n\t\t}\n\n\t\tif (Number.isNaN(this.lastFrameTime)) {\n\t\t\tthis.lastFrameTime = tickTime;\n\t\t}\n\t\tconst frameDelta = tickTime - this.lastFrameTime;\n\t\tthis.lastFrameTime = tickTime;\n\t\t// 减去多余的时间,避免帧率漂移(例如高刷显示器限制低帧率时)\n\t\tthis.lastTickTime = tickTime - (delta % interval);\n\n\t\tthis.frameTime += frameDelta * this.flowSpeed;\n\n\t\tif (!(this.onRedraw(this.frameTime, frameDelta) && this.staticMode)) {\n\t\t\tthis.requestTick();\n\t\t} else if (this.staticMode) {\n\t\t\tthis.lastFrameTime = Number.NaN;\n\t\t}\n\t}\n\n\tprivate checkIfResize() {\n\t\tconst [tW, tH] = [this.targetSize.x, this.targetSize.y];\n\t\tconst [cW, cH] = [this.currentSize.x, this.currentSize.y];\n\t\tif (tW !== cW || tH !== cH) {\n\t\t\tsuper.onResize(tW, tH);\n\t\t\tconst gl = this.gl;\n\t\t\tgl.bindFramebuffer(gl.FRAMEBUFFER, null);\n\t\t\tgl.viewport(0, 0, tW, tH);\n\t\t\tthis.currentSize.x = tW;\n\t\t\tthis.currentSize.y = tH;\n\t\t\tif (tW > 0 && tH > 0) {\n\t\t\t\tthis.updateFBO(tW, tH);\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate updateFBO(width: number, height: number) {\n\t\tconst gl = this.gl;\n\t\tif (this.fbo) gl.deleteFramebuffer(this.fbo);\n\t\tif (this.fboTexture) gl.deleteTexture(this.fboTexture);\n\n\t\tthis.fboTexture = gl.createTexture();\n\t\tgl.bindTexture(gl.TEXTURE_2D, this.fboTexture);\n\t\tgl.texImage2D(\n\t\t\tgl.TEXTURE_2D,\n\t\t\t0,\n\t\t\tgl.RGBA,\n\t\t\twidth,\n\t\t\theight,\n\t\t\t0,\n\t\t\tgl.RGBA,\n\t\t\tgl.UNSIGNED_BYTE,\n\t\t\tnull,\n\t\t);\n\t\tgl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);\n\t\tgl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);\n\t\tgl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);\n\t\tgl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);\n\n\t\tthis.fbo = gl.createFramebuffer();\n\t\tgl.bindFramebuffer(gl.FRAMEBUFFER, this.fbo);\n\t\tgl.framebufferTexture2D(\n\t\t\tgl.FRAMEBUFFER,\n\t\t\tgl.COLOR_ATTACHMENT0,\n\t\t\tgl.TEXTURE_2D,\n\t\t\tthis.fboTexture,\n\t\t\t0,\n\t\t);\n\n\t\tgl.bindFramebuffer(gl.FRAMEBUFFER, null);\n\t}\n\n\tprivate onRedraw(tickTime: number, delta: number) {\n\t\tconst latestMeshState = this.meshStates[this.meshStates.length - 1];\n\t\tlet canBeStatic = false;\n\n\t\t// 预计算常用值\n\t\tconst deltaFactor = delta / 500;\n\n\t\tif (latestMeshState) {\n\t\t\tlatestMeshState.mesh.bind();\n\t\t\t// 考虑到我们并不逐帧更新网格控制点,因此也不需要重复调用 updateMesh\n\t\t\tif (this.manualControl) latestMeshState.mesh.updateMesh();\n\n\t\t\tif (this.isNoCover) {\n\t\t\t\t// 批量处理alpha更新,减少循环开销\n\t\t\t\tlet hasActiveStates = false;\n\t\t\t\tfor (let i = this.meshStates.length - 1; i >= 0; i--) {\n\t\t\t\t\tconst state = this.meshStates[i];\n\t\t\t\t\t// 增加一个小的容错范围,避免浮点误差导致的过早删除\n\t\t\t\t\tif (state.alpha <= -0.1) {\n\t\t\t\t\t\t// 立即释放资源\n\t\t\t\t\t\tstate.mesh.dispose();\n\t\t\t\t\t\tstate.texture.dispose();\n\t\t\t\t\t\tthis.meshStates.splice(i, 1);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tstate.alpha = Math.max(-0.1, state.alpha - deltaFactor);\n\t\t\t\t\t\thasActiveStates = true;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tcanBeStatic = !hasActiveStates;\n\t\t\t} else {\n\t\t\t\t// 同样增加容错范围,允许稍微超过1以确保完全过渡完成\n\t\t\t\tif (latestMeshState.alpha >= 1.1) {\n\t\t\t\t\t// 批量清理旧状态\n\t\t\t\t\tconst deleted = this.meshStates.splice(0, this.meshStates.length - 1);\n\t\t\t\t\tfor (const state of deleted) {\n\t\t\t\t\t\tstate.mesh.dispose();\n\t\t\t\t\t\tstate.texture.dispose();\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tlatestMeshState.alpha = Math.min(\n\t\t\t\t\t\t1.1,\n\t\t\t\t\t\tlatestMeshState.alpha + deltaFactor,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tcanBeStatic =\n\t\t\t\t\tthis.meshStates.length === 1 && latestMeshState.alpha >= 1.1;\n\t\t\t}\n\t\t}\n\n\t\tconst gl = this.gl;\n\t\tthis.checkIfResize();\n\n\t\tif (!this.fbo) return canBeStatic;\n\n\t\tgl.bindFramebuffer(gl.FRAMEBUFFER, null);\n\t\tgl.clearColor(0, 0, 0, 0);\n\t\tgl.clear(gl.COLOR_BUFFER_BIT);\n\n\t\tconst lerpFactor = Math.min(1.0, delta / 100.0);\n\t\tthis.smoothedVolume += (this.volume - this.smoothedVolume) * lerpFactor;\n\n\t\t// 渲染所有网格状态\n\t\tfor (const state of this.meshStates) {\n\t\t\t// 1. 渲染到 FBO\n\t\t\tgl.bindFramebuffer(gl.FRAMEBUFFER, this.fbo);\n\t\t\tgl.disable(gl.BLEND);\n\t\t\tgl.clearColor(0, 0, 0, 0);\n\t\t\tgl.clear(gl.COLOR_BUFFER_BIT);\n\n\t\t\tthis.mainProgram.use();\n\t\t\tgl.activeTexture(gl.TEXTURE0);\n\t\t\tthis.mainProgram.setUniform1f(\"u_time\", tickTime / 10000);\n\t\t\tthis.mainProgram.setUniform1f(\n\t\t\t\t\"u_aspect\",\n\t\t\t\tthis.manualControl ? 1 : this.canvas.width / this.canvas.height,\n\t\t\t);\n\t\t\tthis.mainProgram.setUniform1i(\"u_texture\", 0);\n\t\t\tthis.mainProgram.setUniform1f(\"u_volume\", this.volume);\n\t\t\tthis.mainProgram.setUniform1f(\"u_alpha\", 1.0);\n\n\t\t\tstate.texture.bind();\n\t\t\tstate.mesh.bind();\n\t\t\tstate.mesh.draw();\n\n\t\t\t// 2. 渲染 FBO 到屏幕\n\t\t\tgl.bindFramebuffer(gl.FRAMEBUFFER, null);\n\t\t\tgl.enable(gl.BLEND);\n\t\t\tgl.blendFuncSeparate(\n\t\t\t\tgl.SRC_ALPHA,\n\t\t\t\tgl.ONE_MINUS_SRC_ALPHA,\n\t\t\t\tgl.ONE,\n\t\t\t\tgl.ONE_MINUS_SRC_ALPHA,\n\t\t\t);\n\t\t\tthis.quadProgram.use();\n\t\t\tthis.quadProgram.setUniform1i(\"u_texture\", 0);\n\t\t\tthis.quadProgram.setUniform1f(\n\t\t\t\t\"u_alpha\",\n\t\t\t\teaseInOutSine(clamp01(state.alpha)),\n\t\t\t);\n\n\t\t\tgl.activeTexture(gl.TEXTURE0);\n\t\t\tgl.bindTexture(gl.TEXTURE_2D, this.fboTexture);\n\n\t\t\tgl.bindBuffer(gl.ARRAY_BUFFER, this.quadBuffer);\n\t\t\tconst a_pos = this.quadProgram.attrs.a_pos;\n\t\t\tgl.vertexAttribPointer(a_pos, 2, gl.FLOAT, false, 0, 0);\n\t\t\tgl.enableVertexAttribArray(a_pos);\n\n\t\t\tgl.drawArrays(gl.TRIANGLES, 0, 6);\n\t\t\tgl.disableVertexAttribArray(a_pos);\n\t\t}\n\n\t\tgl.flush();\n\n\t\treturn canBeStatic;\n\t}\n\n\tprivate onTickBinded = this.onTick.bind(this);\n\n\tprivate requestTick() {\n\t\tif (this._disposed) return;\n\t\tif (this.tickHandle === 0)\n\t\t\tthis.tickHandle = requestAnimationFrame(this.onTickBinded);\n\t}\n\n\t// private supportTextureFloat = true;\n\n\tconstructor(canvas: HTMLCanvasElement) {\n\t\tsuper(canvas);\n\n\t\tconst gl = canvas.getContext(\"webgl\", { antialias: true });\n\t\tif (!gl) throw new Error(\"WebGL not supported\");\n\t\tif (!gl.getExtension(\"EXT_color_buffer_float\"))\n\t\t\tconsole.warn(\"EXT_color_buffer_float not supported\");\n\t\tif (!gl.getExtension(\"EXT_float_blend\")) {\n\t\t\tconsole.warn(\"EXT_float_blend not supported\");\n\t\t\t// this.supportTextureFloat = false;\n\t\t}\n\t\tif (!gl.getExtension(\"OES_texture_float_linear\"))\n\t\t\tconsole.warn(\"OES_texture_float_linear not supported\");\n\t\tif (!gl.getExtension(\"OES_texture_float\")) {\n\t\t\t// this.supportTextureFloat = false;\n\t\t\tconsole.warn(\"OES_texture_float not supported\");\n\t\t}\n\n\t\tthis.gl = gl;\n\t\tgl.enable(gl.BLEND);\n\t\tgl.blendFuncSeparate(\n\t\t\tgl.SRC_ALPHA,\n\t\t\tgl.ONE_MINUS_SRC_ALPHA,\n\t\t\tgl.ONE,\n\t\t\tgl.ONE_MINUS_SRC_ALPHA,\n\t\t);\n\t\tgl.enable(gl.DEPTH_TEST);\n\t\tgl.depthFunc(gl.ALWAYS);\n\n\t\tthis.mainProgram = new GLProgram(\n\t\t\tgl,\n\t\t\tmeshVertShader,\n\t\t\tmeshFragShader,\n\t\t\t\"main-program-mg\",\n\t\t);\n\n\t\tthis.quadProgram = new GLProgram(\n\t\t\tgl,\n\t\t\tquadVertShader,\n\t\t\tquadFragShader,\n\t\t\t\"quad-program\",\n\t\t);\n\t\tconst quadBuffer = gl.createBuffer();\n\t\tif (!quadBuffer) throw new Error(\"Failed to create quad buffer\");\n\t\tthis.quadBuffer = quadBuffer;\n\t\tgl.bindBuffer(gl.ARRAY_BUFFER, this.quadBuffer);\n\t\tgl.bufferData(\n\t\t\tgl.ARRAY_BUFFER,\n\t\t\tnew Float32Array([-1, -1, 1, -1, -1, 1, -1, 1, 1, -1, 1, 1]),\n\t\t\tgl.STATIC_DRAW,\n\t\t);\n\n\t\tthis.requestTick();\n\t}\n\n\tprotected override onResize(width: number, height: number): void {\n\t\tthis.targetSize.x = Math.ceil(width);\n\t\tthis.targetSize.y = Math.ceil(height);\n\t\tthis.requestTick();\n\t}\n\n\toverride setStaticMode(enable: boolean): void {\n\t\tthis.staticMode = enable;\n\t\tthis.lastFrameTime = performance.now();\n\t\tthis.requestTick();\n\t}\n\toverride setFPS(fps: number): void {\n\t\tthis.maxFPS = fps;\n\t}\n\toverride pause(): void {\n\t\tif (this.tickHandle) {\n\t\t\tcancelAnimationFrame(this.tickHandle);\n\t\t\tthis.tickHandle = 0;\n\t\t}\n\t\tthis.paused = true;\n\t}\n\toverride resume(): void {\n\t\tthis.paused = false;\n\t\tthis.requestTick();\n\t}\n\toverride async setAlbum(\n\t\talbumSource?: string | HTMLImageElement | HTMLVideoElement,\n\t\tisVideo?: boolean,\n\t): Promise<void> {\n\t\tif (\n\t\t\talbumSource === undefined ||\n\t\t\t(typeof albumSource === \"string\" && albumSource.trim().length === 0)\n\t\t) {\n\t\t\tthis.isNoCover = true;\n\t\t\treturn;\n\t\t}\n\t\tlet res: HTMLImageElement | HTMLVideoElement | null = null;\n\t\tlet blob: Blob | null = null;\n\t\tlet remainRetryTimes = 5;\n\t\twhile (!res && remainRetryTimes > 0) {\n\t\t\ttry {\n\t\t\t\tif (typeof albumSource === \"string\") {\n\t\t\t\t\tif (!isVideo && \"createImageBitmap\" in window) {\n\t\t\t\t\t\t// 如果支持 createImageBitmap 且是图片,直接 fetch blob\n\t\t\t\t\t\tconst response = await fetch(albumSource);\n\t\t\t\t\t\tblob = await response.blob();\n\t\t\t\t\t\t// 仍然需要一个 HTMLImageElement 来获取原始宽高(如果后续需要)\n\t\t\t\t\t\t// 但这里我们主要依赖 blob 来创建 bitmap\n\t\t\t\t\t\tres = await loadResourceFromUrl(URL.createObjectURL(blob), false);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tres = await loadResourceFromUrl(albumSource, isVideo);\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tres = await loadResourceFromElement(albumSource);\n\t\t\t\t}\n\t\t\t} catch (error) {\n\t\t\t\tconsole.warn(\n\t\t\t\t\t`failed on loading album resource, retrying (${remainRetryTimes})`,\n\t\t\t\t\t{\n\t\t\t\t\t\talbumSource,\n\t\t\t\t\t\terror,\n\t\t\t\t\t},\n\t\t\t\t);\n\t\t\t\tremainRetryTimes--;\n\t\t\t}\n\t\t}\n\t\tif (!res) {\n\t\t\tconsole.error(\"Failed to load album resource\", albumSource);\n\t\t\tthis.isNoCover = true;\n\t\t\treturn;\n\t\t}\n\t\tthis.isNoCover = false;\n\t\t// resize image\n\t\tconst c = this.reduceImageSizeCanvas;\n\t\tconst ctx = c.getContext(\"2d\", {\n\t\t\twillReadFrequently: true,\n\t\t});\n\t\tif (!ctx) throw new Error(\"Failed to create canvas context\");\n\t\tctx.clearRect(0, 0, c.width, c.height);\n\t\t// Safari 不支持 filter\n\t\t// ctx.filter = baseFilter;\n\t\tconst imgw =\n\t\t\tres instanceof HTMLVideoElement ? res.videoWidth : res.naturalWidth;\n\t\tconst imgh =\n\t\t\tres instanceof HTMLVideoElement ? res.videoHeight : res.naturalHeight;\n\t\tif (imgw * imgh === 0) throw new Error(\"Invalid image size\");\n\n\t\tlet bitmap: ImageBitmap | null = null;\n\t\ttry {\n\t\t\tif (\"createImageBitmap\" in window) {\n\t\t\t\t// 避免在主线程进行同步解码,使用 fetch 获取 blob 后再创建 ImageBitmap\n\t\t\t\tif (blob) {\n\t\t\t\t\tbitmap = await createImageBitmap(blob, {\n\t\t\t\t\t\tresizeWidth: c.width,\n\t\t\t\t\t\tresizeHeight: c.height,\n\t\t\t\t\t\tresizeQuality: \"low\",\n\t\t\t\t\t});\n\t\t\t\t\tURL.revokeObjectURL(res.src); // 释放 object URL\n\t\t\t\t} else {\n\t\t\t\t\tbitmap = await createImageBitmap(res, {\n\t\t\t\t\t\tresizeWidth: c.width,\n\t\t\t\t\t\tresizeHeight: c.height,\n\t\t\t\t\t\tresizeQuality: \"low\",\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\t\t} catch (e) {\n\t\t\tconsole.warn(\"createImageBitmap failed\", e);\n\t\t}\n\n\t\tif (bitmap) {\n\t\t\tctx.drawImage(bitmap, 0, 0);\n\t\t\tbitmap.close();\n\t\t} else {\n\t\t\tctx.drawImage(res, 0, 0, imgw, imgh, 0, 0, c.width, c.height);\n\t\t}\n\n\t\tconst imageData = ctx.getImageData(0, 0, c.width, c.height);\n\n\t\t// 合并对比度、饱和度、亮度的处理,减少循环次数\n\t\tconst pixels = imageData.data;\n\t\tfor (let i = 0; i < pixels.length; i += 4) {\n\t\t\tlet r = pixels[i];\n\t\t\tlet g = pixels[i + 1];\n\t\t\tlet b = pixels[i + 2];\n\n\t\t\t// contrast 0.4\n\t\t\tr = (r - 128) * 0.4 + 128;\n\t\t\tg = (g - 128) * 0.4 + 128;\n\t\t\tb = (b - 128) * 0.4 + 128;\n\n\t\t\t// saturate 3.0\n\t\t\tconst gray = r * 0.3 + g * 0.59 + b * 0.11;\n\t\t\tr = gray * -2.0 + r * 3.0;\n\t\t\tg = gray * -2.0 + g * 3.0;\n\t\t\tb = gray * -2.0 + b * 3.0;\n\n\t\t\t// contrast 1.7\n\t\t\tr = (r - 128) * 1.7 + 128;\n\t\t\tg = (g - 128) * 1.7 + 128;\n\t\t\tb = (b - 128) * 1.7 + 128;\n\n\t\t\t// brightness 0.75\n\t\t\tpixels[i] = r * 0.75;\n\t\t\tpixels[i + 1] = g * 0.75;\n\t\t\tpixels[i + 2] = b * 0.75;\n\t\t}\n\n\t\tblurImage(imageData, 2, 4);\n\n\t\tif (this.manualControl && this.meshStates.length > 0) {\n\t\t\tthis.meshStates[0].texture.dispose();\n\t\t\tthis.meshStates[0].texture = new GLTexture(this.gl, imageData);\n\t\t} else {\n\t\t\tconst newMesh = new BHPMesh(\n\t\t\t\tthis.gl,\n\t\t\t\tthis.mainProgram.attrs.a_pos,\n\t\t\t\tthis.mainProgram.attrs.a_color,\n\t\t\t\tthis.mainProgram.attrs.a_uv,\n\t\t\t);\n\t\t\tnewMesh.resetSubdivition(50);\n\n\t\t\tconst chosenPreset =\n\t\t\t\tMath.random() > 0.8\n\t\t\t\t\t? generateControlPoints(6, 6)\n\t\t\t\t\t: CONTROL_POINT_PRESETS[\n\t\t\t\t\t\t\tMath.floor(Math.random() * CONTROL_POINT_PRESETS.length)\n\t\t\t\t\t\t];\n\n\t\t\tnewMesh.resizeControlPoints(chosenPreset.width, chosenPreset.height);\n\t\t\tconst uPower = 2 / (chosenPreset.width - 1);\n\t\t\tconst vPower = 2 / (chosenPreset.height - 1);\n\t\t\tfor (const cp of chosenPreset.conf) {\n\t\t\t\tconst p = newMesh.getControlPoint(cp.cx, cp.cy);\n\t\t\t\tp.location.x = cp.x;\n\t\t\t\tp.location.y = cp.y;\n\t\t\t\tp.uRot = (cp.ur * Math.PI) / 180;\n\t\t\t\tp.vRot = (cp.vr * Math.PI) / 180;\n\t\t\t\tp.uScale = uPower * cp.up;\n\t\t\t\tp.vScale = vPower * cp.vp;\n\t\t\t}\n\n\t\t\tnewMesh.updateMesh();\n\t\t\t// this.currentImageData = imageData;\n\n\t\t\tconst albumTexture = new GLTexture(this.gl, imageData);\n\t\t\tconst newState: MeshState = {\n\t\t\t\tmesh: newMesh,\n\t\t\t\ttexture: albumTexture,\n\t\t\t\talpha: 0,\n\t\t\t};\n\t\t\tthis.meshStates.push(newState);\n\t\t}\n\n\t\tthis.requestTick();\n\t}\n\toverride setLowFreqVolume(volume: number): void {\n\t\tthis.volume = volume / 10;\n\t}\n\toverride setHasLyric(_hasLyric: boolean): void {\n\t\t// 不再考虑实现\n\t}\n\n\toverride dispose(): void {\n\t\tsuper.dispose();\n\t\tif (this.tickHandle) {\n\t\t\tcancelAnimationFrame(this.tickHandle);\n\t\t\tthis.tickHandle = 0;\n\t\t}\n\t\tthis._disposed = true;\n\t\tthis.mainProgram.dispose();\n\t\tthis.quadProgram.dispose();\n\t\tthis.gl.deleteBuffer(this.quadBuffer);\n\t\tif (this.fbo) this.gl.deleteFramebuffer(this.fbo);\n\t\tif (this.fboTexture) this.gl.deleteTexture(this.fboTexture);\n\t\tfor (const state of this.meshStates) {\n\t\t\tstate.mesh.dispose();\n\t\t\tstate.texture.dispose();\n\t\t}\n\t}\n\n\tenablePerformanceMonitor(enable: boolean): void {\n\t\tthis.enablePerformanceMonitoring = enable;\n\t\tif (enable) {\n\t\t\tthis.frameCount = 0;\n\t\t\tthis.lastFPSUpdate = performance.now();\n\t\t}\n\t}\n\n\tgetCurrentFPS(): number {\n\t\treturn this.currentFPS;\n\t}\n\n\tprivate updatePerformanceStats(tickTime: number) {\n\t\tif (!this.enablePerformanceMonitoring) return;\n\n\t\tthis.frameCount++;\n\t\tif (tickTime - this.lastFPSUpdate > 1000) {\n\t\t\tthis.currentFPS = this.frameCount;\n\t\t\tthis.frameCount = 0;\n\t\t\tthis.lastFPSUpdate = tickTime;\n\t\t}\n\t}\n}\n","import { Application } from \"@pixi/app\";\nimport { Texture } from \"@pixi/core\";\nimport { Container } from \"@pixi/display\";\nimport { BlurFilter } from \"@pixi/filter-blur\";\nimport { BulgePinchFilter } from \"@pixi/filter-bulge-pinch\";\nimport { ColorMatrixFilter } from \"@pixi/filter-color-matrix\";\nimport { Sprite } from \"@pixi/sprite\";\nimport {\n\tloadResourceFromElement,\n\tloadResourceFromUrl,\n} from \"../utils/resource\";\nimport { BaseRenderer } from \"./base\";\nimport { clampPositive } from \"#utils/clamp.ts\";\n\nclass TimedContainer extends Container {\n\tpublic time = 0;\n}\n\nexport class PixiRenderer extends BaseRenderer {\n\tprivate app: Application;\n\tprivate curContainer?: TimedContainer;\n\tprivate staticMode = false;\n\tprivate lastContainer: Set<TimedContainer> = new Set();\n\tprivate onTick = (delta: number): void => {\n\t\tfor (const lastContainer of this.lastContainer) {\n\t\t\tlastContainer.alpha = clampPositive(lastContainer.alpha - delta / 60);\n\t\t\tif (lastContainer.alpha <= 0) {\n\t\t\t\tthis.app.stage.removeChild(lastContainer);\n\t\t\t\tthis.lastContainer.delete(lastContainer);\n\t\t\t\tlastContainer.destroy(true);\n\t\t\t}\n\t\t}\n\n\t\tif (this.curContainer) {\n\t\t\tthis.curContainer.alpha = Math.min(\n\t\t\t\t1,\n\t\t\t\tthis.curContainer.alpha + delta / 60,\n\t\t\t);\n\t\t\tconst [s1, s2, s3, s4] = this.curContainer.children as Sprite[];\n\t\t\tconst maxSize = Math.max(this.app.screen.width, this.app.screen.height);\n\t\t\ts1.position.set(this.app.screen.width / 2, this.app.screen.height / 2);\n\t\t\ts2.position.set(\n\t\t\t\tthis.app.screen.width / 2.5,\n\t\t\t\tthis.app.screen.height / 2.5,\n\t\t\t);\n\t\t\ts3.position.set(this.app.screen.width / 2, this.app.screen.height / 2);\n\t\t\ts4.position.set(this.app.screen.width / 2, this.app.screen.height / 2);\n\t\t\ts1.width = maxSize * Math.sqrt(2);\n\t\t\ts1.height = s1.width;\n\t\t\ts2.width = maxSize * 0.8;\n\t\t\ts2.height = s2.width;\n\t\t\ts3.width = maxSize * 0.5;\n\t\t\ts3.height = s3.width;\n\t\t\ts4.width = maxSize * 0.25;\n\t\t\ts4.height = s4.width;\n\n\t\t\tthis.curContainer.time += delta * this.flowSpeed;\n\n\t\t\ts1.rotation += (delta / 1000) * this.flowSpeed;\n\t\t\ts2.rotation -= (delta / 500) * this.flowSpeed;\n\t\t\ts3.rotation += (delta / 1000) * this.flowSpeed;\n\t\t\ts4.rotation -= (delta / 750) * this.flowSpeed;\n\n\t\t\ts3.x =\n\t\t\t\tthis.app.screen.width / 2 +\n\t\t\t\t(this.app.screen.width / 4) *\n\t\t\t\t\tMath.cos((this.curContainer.time / 1000) * 0.75);\n\t\t\ts3.y =\n\t\t\t\tthis.app.screen.height / 2 +\n\t\t\t\t(this.app.screen.width / 4) *\n\t\t\t\t\tMath.cos((this.curContainer.time / 1000) * 0.75);\n\n\t\t\ts4.x =\n\t\t\t\tthis.app.screen.width / 2 +\n\t\t\t\t(this.app.screen.width / 4) * 0.1 +\n\t\t\t\tMath.cos(this.curContainer.time * 0.006 * 0.75);\n\t\t\ts4.y =\n\t\t\t\tthis.app.screen.height / 2 +\n\t\t\t\t(this.app.screen.width / 4) * 0.1 +\n\t\t\t\tMath.cos(this.curContainer.time * 0.006 * 0.75);\n\n\t\t\tif (\n\t\t\t\tthis.curContainer.alpha >= 1 &&\n\t\t\t\tthis.lastContainer.size === 0 &&\n\t\t\t\tthis.staticMode\n\t\t\t) {\n\t\t\t\tthis.app.ticker.stop();\n\t\t\t}\n\t\t}\n\t};\n\tconstructor(protected override canvas: HTMLCanvasElement) {\n\t\tsuper(canvas);\n\t\tthis.app = new Application({\n\t\t\tview: canvas,\n\t\t\tresizeTo: this.canvas,\n\t\t\tpowerPreference: \"low-power\",\n\t\t\tbackgroundAlpha: 1,\n\t\t});\n\t\tthis.rebuildFilters();\n\t\tthis.app.ticker.maxFPS = 30;\n\t\tthis.app.ticker.add(this.onTick);\n\t\tthis.app.ticker.start();\n\t}\n\n\tprotected override onResize(width: number, height: number): void {\n\t\tsuper.onResize(width, height);\n\t\tthis.app.resize();\n\t\tthis.rebuildFilters();\n\t}\n\n\toverride setRenderScale(scale: number): void {\n\t\tsuper.setRenderScale(scale);\n\t\tthis.rebuildFilters();\n\t}\n\tprivate rebuildFilters() {\n\t\tconst minBorder = Math.min(this.canvas.width, this.canvas.height);\n\t\tconst maxBorder = Math.max(this.canvas.width, this.canvas.height);\n\t\tconst c0 = new ColorMatrixFilter();\n\t\tc0.saturate(1.2, false);\n\t\tconst c1 = new ColorMatrixFilter();\n\t\tc1.brightness(0.6, false);\n\t\tconst c2 = new ColorMatrixFilter();\n\t\tc2.contrast(0.3, true);\n\t\tfor (const filter of this.app.stage.filters ?? []) {\n\t\t\tfilter.destroy();\n\t\t}\n\t\tthis.app.stage.filters = [];\n\t\tthis.app.stage.filters.push(new BlurFilter(5, 1));\n\t\tthis.app.stage.filters.push(new BlurFilter(10, 1));\n\t\tthis.app.stage.filters.push(new BlurFilter(20, 2));\n\t\tthis.app.stage.filters.push(new BlurFilter(40, 2));\n\t\tthis.app.stage.filters.push(new BlurFilter(80, 2));\n\t\tif (minBorder > 768) this.app.stage.filters.push(new BlurFilter(160, 4));\n\t\tif (minBorder > 768 * 2)\n\t\t\tthis.app.stage.filters.push(new BlurFilter(320, 4));\n\n\t\tthis.app.stage.filters.push(c0, c1, c2);\n\t\tthis.app.stage.filters.push(new BlurFilter(5, 1));\n\t\tif (Math.random() > 0.5) {\n\t\t\tthis.app.stage.filters.push(\n\t\t\t\tnew BulgePinchFilter({\n\t\t\t\t\tradius: (maxBorder + minBorder) / 2,\n\t\t\t\t\tstrength: 1,\n\t\t\t\t\tcenter: [0.25, 1],\n\t\t\t\t}),\n\t\t\t);\n\t\t\tthis.app.stage.filters.push(\n\t\t\t\tnew BulgePinchFilter({\n\t\t\t\t\tradius: (maxBorder + minBorder) / 2,\n\t\t\t\t\tstrength: 1,\n\t\t\t\t\tcenter: [0.75, 0],\n\t\t\t\t}),\n\t\t\t);\n\t\t} else {\n\t\t\tthis.app.stage.filters.push(\n\t\t\t\tnew BulgePinchFilter({\n\t\t\t\t\tradius: (maxBorder + minBorder) / 2,\n\t\t\t\t\tstrength: 1,\n\t\t\t\t\tcenter: [0.75, 1],\n\t\t\t\t}),\n\t\t\t);\n\t\t\tthis.app.stage.filters.push(\n\t\t\t\tnew BulgePinchFilter({\n\t\t\t\t\tradius: (maxBorder + minBorder) / 2,\n\t\t\t\t\tstrength: 1,\n\t\t\t\t\tcenter: [0.25, 0],\n\t\t\t\t}),\n\t\t\t);\n\t\t}\n\t}\n\n\toverride setStaticMode(enable = false): void {\n\t\tthis.staticMode = enable;\n\t\tthis.app.ticker.start();\n\t}\n\n\toverride setFPS(fps: number): void {\n\t\tthis.app.ticker.maxFPS = fps;\n\t}\n\n\toverride pause(): void {\n\t\tthis.app.ticker.stop();\n\t\tthis.app.render();\n\t}\n\n\toverride resume(): void {\n\t\tthis.app.ticker.start();\n\t}\n\n\toverride setLowFreqVolume(_volume: number): void {\n\t\t// NOOP\n\t}\n\n\toverride setHasLyric(_hasLyric: boolean): void {\n\t\t// NOOP\n\t}\n\n\toverride async setAlbum(\n\t\talbumSource?: string | HTMLImageElement | HTMLVideoElement,\n\t\tisVideo?: boolean,\n\t): Promise<void> {\n\t\tif (\n\t\t\t!albumSource ||\n\t\t\t(typeof albumSource === \"string\" && albumSource.trim().length === 0)\n\t\t)\n\t\t\treturn;\n\t\tlet res: HTMLImageElement | HTMLVideoElement | null = null;\n\t\tlet remainRetryTimes = 5;\n\t\tlet tex: Texture | null = null;\n\t\twhile (!tex?.baseTexture?.resource?.valid && remainRetryTimes > 0) {\n\t\t\ttry {\n\t\t\t\tif (typeof albumSource === \"string\") {\n\t\t\t\t\tres = await loadResourceFromUrl(albumSource, isVideo);\n\t\t\t\t} else {\n\t\t\t\t\tres = await loadResourceFromElement(albumSource);\n\t\t\t\t}\n\t\t\t\ttex = Texture.from(res, {\n\t\t\t\t\tresourceOptions: {\n\t\t\t\t\t\tautoLoad: false,\n\t\t\t\t\t},\n\t\t\t\t});\n\t\t\t\tawait tex.baseTexture.resource.load();\n\t\t\t} catch (error) {\n\t\t\t\tconsole.warn(\n\t\t\t\t\t`failed on loading album image, retrying (${remainRetryTimes})`,\n\t\t\t\t\talbumSource,\n\t\t\t\t\terror,\n\t\t\t\t);\n\t\t\t\ttex = null;\n\t\t\t\tremainRetryTimes--;\n\t\t\t}\n\t\t}\n\t\tif (!tex) return;\n\t\tconst container = new TimedContainer();\n\t\tconst s1 = new Sprite(tex);\n\t\tconst s2 = new Sprite(tex);\n\t\tconst s3 = new Sprite(tex);\n\t\tconst s4 = new Sprite(tex);\n\t\ts1.anchor.set(0.5, 0.5);\n\t\ts2.anchor.set(0.5, 0.5);\n\t\ts3.anchor.set(0.5, 0.5);\n\t\ts4.anchor.set(0.5, 0.5);\n\t\ts1.rotation = Math.random() * Math.PI * 2;\n\t\ts2.rotation = Math.random() * Math.PI * 2;\n\t\ts3.rotation = Math.random() * Math.PI * 2;\n\t\ts4.rotation = Math.random() * Math.PI * 2;\n\t\tcontainer.addChild(s1, s2, s3, s4);\n\t\tif (this.curContainer) this.lastContainer.add(this.curContainer);\n\t\tthis.curContainer = container;\n\t\tthis.app.stage.addChild(container);\n\t\tthis.curContainer.alpha = 0;\n\t\tthis.app.ticker.start();\n\t}\n\n\toverride dispose(): void {\n\t\tsuper.dispose();\n\t\tthis.app.ticker.remove(this.onTick);\n\t\tthis.app.destroy(true);\n\t}\n\n\toverride getElement(): HTMLElement {\n\t\treturn this.canvas;\n\t}\n}\n","/**\n * @fileoverview\n * 一个播放歌词的组件\n * @author SteveXMH\n */\n\nexport { AbstractBaseRenderer, BaseRenderer } from \"./base.ts\";\nexport { MeshGradientRenderer } from \"./mesh-renderer/index.ts\";\nexport { PixiRenderer } from \"./pixi-renderer.ts\";\nimport type { AbstractBaseRenderer, BaseRenderer } from \"./base.ts\";\n\nexport class BackgroundRender<Renderer extends BaseRenderer>\n\timplements AbstractBaseRenderer\n{\n\tprivate element: HTMLCanvasElement;\n\tprivate renderer: Renderer;\n\tconstructor(renderer: Renderer, canvas: HTMLCanvasElement) {\n\t\tthis.renderer = renderer;\n\n\t\tthis.element = canvas;\n\t\tcanvas.style.pointerEvents = \"none\";\n\t\tcanvas.style.zIndex = \"-1\";\n\t\tcanvas.style.contain = \"strict\";\n\t}\n\n\tstatic new<Renderer extends BaseRenderer>(type: {\n\t\tnew (canvas: HTMLCanvasElement): Renderer;\n\t}): BackgroundRender<Renderer> {\n\t\tconst newCanvas = document.createElement(\"canvas\");\n\t\treturn new BackgroundRender(new type(newCanvas), newCanvas);\n\t}\n\n\tsetRenderScale(scale: number): void {\n\t\tthis.renderer.setRenderScale(scale);\n\t}\n\n\tsetFlowSpeed(speed: number): void {\n\t\tthis.renderer.setFlowSpeed(speed);\n\t}\n\tsetStaticMode(enable: boolean): void {\n\t\tthis.renderer.setStaticMode(enable);\n\t}\n\tsetFPS(fps: number): void {\n\t\tthis.renderer.setFPS(fps);\n\t}\n\tpause(): void {\n\t\tthis.renderer.pause();\n\t}\n\tresume(): void {\n\t\tthis.renderer.resume();\n\t}\n\tsetLowFreqVolume(volume: number): void {\n\t\tthis.renderer.setLowFreqVolume(volume);\n\t}\n\tsetHasLyric(hasLyric: boolean): void {\n\t\tthis.renderer.setHasLyric(hasLyric);\n\t}\n\tsetAlbum(\n\t\talbumSource: string | HTMLImageElement | HTMLVideoElement,\n\t\tisVideo?: boolean,\n\t): Promise<void> {\n\t\treturn this.renderer.setAlbum(albumSource, isVideo);\n\t}\n\tgetElement(): HTMLCanvasElement {\n\t\treturn this.element;\n\t}\n\tdispose(): void {\n\t\tthis.renderer.dispose();\n\t\tthis.element.remove();\n\t}\n}\n",".lyricLineWrapper {\n\tposition: absolute;\n\ttop: 0;\n\tleft: 0;\n\tdisplay: flex;\n\tflex-direction: column;\n\talign-items: flex-start;\n\twidth: 100%;\n\n\twill-change: transform, opacity, filter;\n\ttransition:\n\t\topacity 0.4s ease,\n\t\tfilter 0.4s ease;\n}\n\n.lyricLine {\n\tposition: relative;\n\tbox-sizing: border-box;\n\twidth: var(--amll-lp-width, 100%);\n\tmin-width: var(--amll-lp-width, 100%);\n\tmax-width: var(--amll-lp-width, 100%);\n\theight: fit-content;\n\tpadding: 0.5em 1em;\n\tpadding-left: 1em;\n\tpadding-right: 1em;\n\tborder-radius: 0.25em;\n\n\tcontain: content;\n\tbackface-visibility: hidden;\n\ttransform-origin: left;\n\twill-change: transform;\n\n\ttransition:\n\t\tbackground-color 0.25s,\n\t\tbox-shadow 0.25s;\n\n\t@media screen and (max-width: 500px) {\n\t\tpadding-left: 20px;\n\t\tpadding-right: 20px;\n\t}\n\n\t&.dirty {\n\t\topacity: 0;\n\t\tvisibility: hidden;\n\t}\n\n\t&:has(> *):hover {\n\t\tbackground-color: var(--amll-lp-hover-bg-color, #fff1);\n\t}\n\n\t&:has(> *):active {\n\t\tbackground-color: var(--amll-lp-hover-bg-color, #ffffff05);\n\t}\n}\n\n.lyricDuetLine {\n\ttext-align: right;\n\ttransform-origin: right;\n}\n\n.lyricMainLine {\n\tmargin: -1em;\n\tpadding: 1em;\n\ttransition: opacity 0.3s 0.1s;\n\n\t& span {\n\t\tdisplay: inline-block;\n\t\ttext-align: start;\n\t\tvertical-align: bottom;\n\t}\n\n\t.romanWord {\n\t\tdisplay: flex;\n\t\tpadding-inline-end: 0.3em;\n\t\tfont-size: 0.5em;\n\t\tline-height: 1em;\n\t}\n\n\t.rubyWord {\n\t\tdisplay: flex;\n\t\tjustify-content: center;\n\t\tmin-height: 1em;\n\t\tfont-size: 0.5em;\n\t\tline-height: 1em;\n\t}\n\n\t.wordWithRuby {\n\t\tdisplay: inline-flex;\n\t\tflex-direction: column;\n\t\talign-items: center;\n\t\tvertical-align: bottom;\n\t}\n\n\t.wordBody {\n\t\tdisplay: flex;\n\t\tflex-direction: column;\n\t\talign-items: center;\n\t}\n\n\t& > span,\n\tspan.emphasizeWrapper {\n\t\tdisplay: inline-block;\n\t\tmargin: -1em;\n\t\tpadding: 1em;\n\t\twhite-space: pre-wrap;\n\t\tvertical-align: bottom;\n\t\twill-change: transform;\n\n\t\t&.emphasize,\n\t\tspan.emphasize {\n\t\t\tmargin: -1em;\n\t\t\tpadding: 1em;\n\t\t\tbackface-visibility: hidden;\n\n\t\t\t& > span {\n\t\t\t\tmargin: -1em;\n\t\t\t\tpadding: 1em;\n\t\t\t\twill-change: transform;\n\t\t\t\tbackface-visibility: hidden;\n\t\t\t}\n\t\t}\n\t}\n}\n\n.lyricBgLine {\n\topacity: 0.4;\n\t/* 因为字体大小缩小了,故内边距要和主行字体大小统一,行边距计算公式为 100% / font-size 转 em 单位 */\n\tpadding: 1vh\n\t\tcalc(var(--amll-lp-line-padding-x, 1em) / var(--amll-lp-bg-line-scale, 0.7));\n\tfont-size: max(calc(1em * var(--amll-lp-bg-line-scale, 0.7)), 10px);\n\ttransition:\n\t\tbackground-color 0.25s,\n\t\tbox-shadow 0.25s;\n\n\t.lyricMainLine {\n\t\tpadding: 1.2em 1em;\n\t}\n\n\t&.active {\n\t\topacity: 0.4;\n\t\ttransition:\n\t\t\tbackground-color 0.25s,\n\t\t\tbox-shadow 0.25s;\n\t}\n}\n\n.lyricSubLine {\n\topacity: 0.3;\n\tfont-size: max(0.5em, 10px);\n\tline-height: 1.5em;\n\ttransition: opacity 0.2s 0.25s;\n\n\t@supports (mix-blend-mode: plus-lighter) {\n\t\topacity: 0.3;\n\t}\n}\n\n.bottomLine {\n\tpadding-top: 0;\n\tpadding-bottom: 0;\n\tline-height: 1.8em;\n\tcursor: default;\n\n\t&:empty {\n\t\tdisplay: none;\n\t\theight: 0;\n\t\tmargin: 0;\n\t\tpadding: 0;\n\t}\n}\n\n.bgWrapper {\n\tposition: absolute;\n\ttop: 100%;\n\tleft: 0;\n\tz-index: -1;\n\tdisplay: flex;\n\tflex-direction: column;\n\talign-items: inherit;\n\twidth: 100%;\n\n\tvisibility: visible;\n\tpointer-events: auto;\n\topacity: 0;\n\ttransform-origin: var(--lyric-line-padding-x) top;\n\ttransition: opacity 0.3s ease;\n}\n\n.bgWrapperTop {\n\tposition: relative;\n\ttop: auto;\n\tbottom: auto;\n\tmargin-top: -999px;\n\ttransform-origin: var(--lyric-line-padding-x) bottom;\n}\n\n.bgWrapperActive {\n\tposition: relative;\n\ttop: auto;\n\tbottom: auto;\n\topacity: 1;\n}\n\n.bgWrapperHidden {\n\tvisibility: hidden;\n\tpointer-events: none;\n}\n\n.interludeDots {\n\tposition: absolute;\n\tleft: 0;\n\tdisplay: flex;\n\tgap: 0.25em;\n\twidth: fit-content;\n\theight: clamp(0.5em, 1vh, 3em);\n\tpadding: 2.5% 0.75em;\n\n\topacity: 0;\n\ttransform-origin: center;\n\ttransition: opacity 0.25s;\n\n\t&.enabled {\n\t\topacity: 1;\n\t}\n\n\t& > * {\n\t\tdisplay: inline-block;\n\t\twidth: clamp(0.5em, 1vh, 3em);\n\t\theight: clamp(0.5em, 1vh, 3em);\n\t\tmargin-right: 4px;\n\t\tborder-radius: 50%;\n\t\tbackground-color: var(--amll-lp-color, white);\n\t\taspect-ratio: 1 / 1;\n\t}\n\n\t&.duet {\n\t\tright: 0;\n\t\ttransform-origin: center;\n\t}\n}\n\n.disableSpring > *,\n.disableSpring .lyricLine {\n\ttransition:\n\t\tfilter 0.25s,\n\t\ttransform 0.5s,\n\t\tbackground-color 0.25s,\n\t\tbox-shadow 0.25s;\n}\n\n.tmpDisableTransition {\n\t/* biome-ignore lint/complexity/noImportantStyles: 覆盖内联样式 */\n\ttransition: none !important;\n}\n\n:global(.amll-lyric-player) {\n\t--lyric-line-padding-x: 1em;\n\n\t@media screen and (max-width: 500px) {\n\t\t--lyric-line-padding-x: 20px;\n\t}\n\n\t&:hover .lyricLine,\n\t&:hover .lyricLineWrapper {\n\t\t/* biome-ignore lint/complexity/noImportantStyles: 覆盖内联样式 */\n\t\tfilter: unset !important;\n\t}\n\n\t&.hasDuetLine {\n\t\t.lyricLine:not(.lyricDuetLine) {\n\t\t\tpadding-right: 15%;\n\t\t}\n\n\t\t.lyricDuetLine {\n\t\t\tpadding-left: 15%;\n\t\t}\n\n\t\t.lyricLineWrapper:has(.lyricDuetLine) {\n\t\t\talign-items: flex-end;\n\n\t\t\t.bgWrapper {\n\t\t\t\ttransform-origin: calc(100% - var(--lyric-line-padding-x)) top;\n\t\t\t}\n\n\t\t\t.bgWrapperTop {\n\t\t\t\ttransform-origin: calc(100% - var(--lyric-line-padding-x)) bottom;\n\t\t\t}\n\t\t}\n\t}\n\n\t&:not(.playing) .bgWrapper {\n\t\tposition: relative;\n\t\ttop: auto;\n\t\tbottom: auto;\n\t\topacity: 1;\n\t}\n}\n","import type { LyricLine, OptimizeLyricOptions } from \"../interfaces.ts\";\n\nconst DEFAULT_OPTIMIZE_OPTIONS: OptimizeLyricOptions = {\n\tnormalizeSpaces: true,\n\tresetLineTimestamps: true,\n\tconvertExcessiveBackgroundLines: true,\n\tsyncMainAndBackgroundLines: true,\n\tcleanUnintentionalOverlaps: true,\n\ttryAdvanceStartTime: true,\n};\n\n/**\n * 规范化歌词中的空格,将多个连续空格替换为一个空格\n */\nfunction normalizeSpaces(lines: LyricLine[]) {\n\tfor (const line of lines) {\n\t\tfor (const word of line.words) {\n\t\t\tword.word = word.word.replace(/\\s+/g, \" \");\n\t\t}\n\t}\n}\n\n/**\n * 将行级时间戳强行设为字级时间戳\n */\nfunction resetLineTimestamps(lines: LyricLine[]) {\n\tfor (const line of lines) {\n\t\t// 主要是给 TTML 解析器打补丁,其解析逐行歌词时获得的词时间戳均为0\n\t\t// 如果只有一个词,且该词的起止时间均为0,且行时间戳不全为0,则将行时间戳同步给词时间戳\n\t\tif (\n\t\t\tline.words.length === 1 &&\n\t\t\tline.words[0].startTime === 0 &&\n\t\t\tline.words[0].endTime === 0 &&\n\t\t\t(line.startTime !== 0 || line.endTime !== 0)\n\t\t) {\n\t\t\tline.words[0].startTime = line.startTime;\n\t\t\tline.words[0].endTime = line.endTime;\n\t\t} else if (line.words.length > 0) {\n\t\t\tconst firstWord = line.words[0];\n\t\t\tconst lastWord = line.words[line.words.length - 1];\n\n\t\t\tline.startTime = firstWord.startTime;\n\t\t\tline.endTime = lastWord.endTime;\n\t\t}\n\t}\n}\n\n/**\n * 把多行背景人声转换为单行背景人声 + 主歌词行的形式\n */\nfunction convertExcessiveBackgroundLines(lines: LyricLine[]) {\n\tlet consecutiveBgCount = 0;\n\n\tfor (const line of lines) {\n\t\tif (line.isBG) {\n\t\t\tconsecutiveBgCount++;\n\t\t\tif (consecutiveBgCount > 1) {\n\t\t\t\tline.isBG = false;\n\t\t\t}\n\t\t} else {\n\t\t\tconsecutiveBgCount = 0;\n\t\t}\n\t}\n}\n\n/**\n * 同步主歌词与背景人声的时间\n *\n * 取两者中最早的开始时间和最晚的结束时间,应用给双方\n */\nfunction syncMainAndBackgroundLines(lines: LyricLine[]) {\n\tfor (let i = lines.length - 1; i >= 0; i--) {\n\t\tconst line = lines[i];\n\t\tif (line.isBG) continue;\n\n\t\tconst nextLine = lines[i + 1];\n\t\tif (nextLine?.isBG) {\n\t\t\tconst allWords = [...line.words, ...nextLine.words].filter(\n\t\t\t\t(w) => w.word.trim().length > 0,\n\t\t\t);\n\n\t\t\tif (allWords.length > 0) {\n\t\t\t\tconst minStart = Math.min(...allWords.map((w) => w.startTime));\n\t\t\t\tconst maxEnd = Math.max(...allWords.map((w) => w.endTime));\n\n\t\t\t\tconst finalStart = Math.min(\n\t\t\t\t\tminStart,\n\t\t\t\t\tline.startTime,\n\t\t\t\t\tnextLine.startTime,\n\t\t\t\t);\n\t\t\t\tconst finalEnd = Math.max(maxEnd, line.endTime, nextLine.endTime);\n\n\t\t\t\tline.startTime = finalStart;\n\t\t\t\tline.endTime = finalEnd;\n\t\t\t\tnextLine.startTime = finalStart;\n\t\t\t\tnextLine.endTime = finalEnd;\n\t\t\t}\n\t\t}\n\t}\n}\n\n/**\n * 清洗非刻意的重叠\n *\n * 如果重叠大于100ms 且 重叠超过下一行时长的10%,则视为刻意重叠,否则将结束时间设为下一行的开始时间\n */\nfunction cleanUnintentionalOverlaps(lines: LyricLine[]) {\n\tfor (let i = 0; i < lines.length - 1; i++) {\n\t\tconst line = lines[i];\n\t\tif (line.isBG) continue;\n\n\t\tlet nextMainIndex = i + 1;\n\t\twhile (nextMainIndex < lines.length && lines[nextMainIndex].isBG) {\n\t\t\tnextMainIndex++;\n\t\t}\n\n\t\tif (nextMainIndex < lines.length) {\n\t\t\tconst nextLine = lines[nextMainIndex];\n\t\t\tconst overlap = line.endTime - nextLine.startTime;\n\n\t\t\tif (overlap > 0) {\n\t\t\t\tconst nextDuration = nextLine.endTime - nextLine.startTime;\n\t\t\t\tconst percentageThreshold = nextDuration * 0.1;\n\n\t\t\t\t// 重叠大于100ms 且 重叠超过下一行时长的10%\n\t\t\t\tconst isIntentionalOverlap =\n\t\t\t\t\toverlap > 100 && overlap > percentageThreshold;\n\n\t\t\t\tif (!isIntentionalOverlap) {\n\t\t\t\t\tline.endTime = nextLine.startTime;\n\n\t\t\t\t\tconst attachedBgLine = lines[i + 1];\n\t\t\t\t\tif (attachedBgLine?.isBG) {\n\t\t\t\t\t\tattachedBgLine.endTime = nextLine.startTime;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\n/**\n * 尝试让歌词提前最多 600ms 开始,如果有重叠则尝试最多提前 400ms 或上一行时长的 30%\n */\nfunction tryAdvanceStartTime(lines: LyricLine[]) {\n\tconst defaultAdvanceAmount = 600;\n\tconst fallbackAdvanceAmount = 400;\n\tconst fallbackAdvanceRatio = 0.3;\n\n\tlet prevLineStartTime = 0;\n\tlet prevLineEndTime = 0;\n\tlet prevMainGroupStartTime = 0;\n\tlet prevMainGroupEndTime = 0;\n\tlet hasPrevLine = false;\n\n\tfor (let i = 0; i < lines.length; i++) {\n\t\tconst line = lines[i];\n\t\tif (line.isBG) continue;\n\n\t\tconst originalStartTime = line.startTime;\n\t\tconst originalEndTime = line.endTime;\n\n\t\tlet targetAdvanceAmount = 0;\n\t\tlet safeBoundary = 0;\n\n\t\tif (hasPrevLine) {\n\t\t\tconst originallyHadGap = originalStartTime >= prevLineEndTime;\n\n\t\t\tif (originallyHadGap) {\n\t\t\t\ttargetAdvanceAmount = defaultAdvanceAmount;\n\t\t\t\tsafeBoundary = prevMainGroupEndTime;\n\t\t\t} else {\n\t\t\t\ttargetAdvanceAmount = fallbackAdvanceAmount;\n\t\t\t\tconst prevDuration = prevLineEndTime - prevLineStartTime;\n\t\t\t\tsafeBoundary = prevLineStartTime + prevDuration * fallbackAdvanceRatio;\n\t\t\t}\n\t\t} else {\n\t\t\ttargetAdvanceAmount = defaultAdvanceAmount;\n\t\t\tsafeBoundary = 0;\n\t\t}\n\n\t\tconst targetTime = line.startTime - targetAdvanceAmount;\n\t\tconst newStartTime = Math.max(safeBoundary, targetTime);\n\n\t\tif (newStartTime < line.startTime) {\n\t\t\tline.startTime = newStartTime;\n\t\t}\n\n\t\tconst nextLine = lines[i + 1];\n\t\tif (nextLine?.isBG) {\n\t\t\tnextLine.startTime = line.startTime;\n\t\t}\n\n\t\tif (hasPrevLine) {\n\t\t\tconst overlapsPrevGroup =\n\t\t\t\toriginalStartTime < prevMainGroupEndTime &&\n\t\t\t\toriginalEndTime > prevMainGroupStartTime;\n\n\t\t\tif (overlapsPrevGroup) {\n\t\t\t\tprevMainGroupStartTime = Math.min(\n\t\t\t\t\tprevMainGroupStartTime,\n\t\t\t\t\toriginalStartTime,\n\t\t\t\t);\n\t\t\t\tprevMainGroupEndTime = Math.max(prevMainGroupEndTime, originalEndTime);\n\t\t\t} else {\n\t\t\t\tprevMainGroupStartTime = originalStartTime;\n\t\t\t\tprevMainGroupEndTime = originalEndTime;\n\t\t\t}\n\t\t} else {\n\t\t\tprevMainGroupStartTime = originalStartTime;\n\t\t\tprevMainGroupEndTime = originalEndTime;\n\t\t}\n\n\t\tprevLineStartTime = originalStartTime;\n\t\tprevLineEndTime = originalEndTime;\n\t\thasPrevLine = true;\n\t}\n}\n\n/**\n * 优化歌词行的展示效果\n *\n * 注意会直接原地修改入参,确保你已经提前深克隆了歌词行数组\n * @param lines 歌词行数组\n * @param options 优化的可选配置,默认全部开启\n */\nexport function optimizeLyricLines(\n\tlines: LyricLine[],\n\toptions?: OptimizeLyricOptions,\n): void {\n\tconst config = { ...DEFAULT_OPTIMIZE_OPTIONS, ...options };\n\n\tif (config.normalizeSpaces) {\n\t\tnormalizeSpaces(lines);\n\t}\n\tif (config.resetLineTimestamps) {\n\t\tresetLineTimestamps(lines);\n\t}\n\tif (config.convertExcessiveBackgroundLines) {\n\t\tconvertExcessiveBackgroundLines(lines);\n\t}\n\tif (config.syncMainAndBackgroundLines) {\n\t\tsyncMainAndBackgroundLines(lines);\n\t}\n\tif (config.cleanUnintentionalOverlaps) {\n\t\tcleanUnintentionalOverlaps(lines);\n\t}\n\tif (config.tryAdvanceStartTime) {\n\t\ttryAdvanceStartTime(lines);\n\t}\n}\n","import type { Disposable, HasElement } from \"#interfaces\";\nimport styles from \"#styles/lyric-player.module.css\";\nimport { clamp, clamp01, clampPositive } from \"#utils/clamp.ts\";\n\nfunction easeInOutBack(x: number): number {\n\tconst c1 = 1.70158;\n\tconst c2 = c1 * 1.525;\n\n\treturn x < 0.5\n\t\t? ((2 * x) ** 2 * ((c2 + 1) * 2 * x - c2)) / 2\n\t\t: ((2 * x - 2) ** 2 * ((c2 + 1) * (x * 2 - 2) + c2) + 2) / 2;\n}\n\nfunction easeOutExpo(x: number): number {\n\treturn x === 1 ? 1 : 1 - 2 ** (-10 * x);\n}\n\nexport class InterludeDots implements HasElement, Disposable {\n\tprivate element: HTMLElement = document.createElement(\"div\");\n\tprivate dot0: HTMLElement = document.createElement(\"span\");\n\tprivate dot1: HTMLElement = document.createElement(\"span\");\n\tprivate dot2: HTMLElement = document.createElement(\"span\");\n\tprivate left = 0;\n\tprivate top = 0;\n\tprivate playing = true;\n\tprivate lastStyle = \"\";\n\tprivate currentInterlude?: [number, number];\n\tprivate currentTime = 0;\n\tprivate targetBreatheDuration = 1500;\n\tconstructor() {\n\t\tthis.element.className = styles.interludeDots;\n\t\tthis.element.appendChild(this.dot0);\n\t\tthis.element.appendChild(this.dot1);\n\t\tthis.element.appendChild(this.dot2);\n\t}\n\tgetElement(): HTMLElement {\n\t\treturn this.element;\n\t}\n\tsetTransform(left: number = this.left, top: number = this.top): void {\n\t\tthis.left = left;\n\t\tthis.top = top;\n\t\tthis.update();\n\t}\n\tsetInterlude(interlude?: [number, number]): void {\n\t\tthis.currentInterlude = interlude;\n\t\tthis.currentTime = interlude?.[0] ?? 0;\n\t\tif (interlude) {\n\t\t\tthis.element.classList.add(styles.enabled);\n\t\t} else {\n\t\t\tthis.element.classList.remove(styles.enabled);\n\t\t}\n\t}\n\tpause(): void {\n\t\tthis.playing = false;\n\t\tthis.element.classList.remove(styles.playing);\n\t}\n\tresume(): void {\n\t\tthis.playing = true;\n\t\tthis.element.classList.add(styles.playing);\n\t}\n\tupdate(delta = 0): void {\n\t\tif (!this.playing) return;\n\t\tthis.currentTime += delta;\n\t\tlet curStyle = \"\";\n\n\t\tcurStyle += `transform:translate(${this.left.toFixed(\n\t\t\t2,\n\t\t)}px, ${this.top.toFixed(2)}px)`;\n\n\t\t// 计算缩放大小\n\n\t\tif (this.currentInterlude) {\n\t\t\tconst interludeDuration =\n\t\t\t\tthis.currentInterlude[1] - this.currentInterlude[0];\n\t\t\tconst currentDuration = this.currentTime - this.currentInterlude[0];\n\t\t\tif (currentDuration <= interludeDuration) {\n\t\t\t\tconst breatheDuration =\n\t\t\t\t\tinterludeDuration /\n\t\t\t\t\tMath.ceil(interludeDuration / this.targetBreatheDuration);\n\t\t\t\tlet scale = 1;\n\t\t\t\tlet globalOpacity = 1;\n\n\t\t\t\tscale *=\n\t\t\t\t\tMath.sin(1.5 * Math.PI - (currentDuration / breatheDuration) * 2) /\n\t\t\t\t\t\t20 +\n\t\t\t\t\t1;\n\n\t\t\t\tif (currentDuration < 2000) {\n\t\t\t\t\tscale *= easeOutExpo(currentDuration / 2000);\n\t\t\t\t}\n\n\t\t\t\tif (currentDuration < 500) {\n\t\t\t\t\tglobalOpacity = 0;\n\t\t\t\t} else if (currentDuration < 1000) {\n\t\t\t\t\tglobalOpacity *= (currentDuration - 500) / 500;\n\t\t\t\t}\n\n\t\t\t\tif (interludeDuration - currentDuration < 750) {\n\t\t\t\t\tscale *=\n\t\t\t\t\t\t1 -\n\t\t\t\t\t\teaseInOutBack(\n\t\t\t\t\t\t\t(750 - (interludeDuration - currentDuration)) / 750 / 2,\n\t\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tif (interludeDuration - currentDuration < 375) {\n\t\t\t\t\tglobalOpacity *= clamp01((interludeDuration - currentDuration) / 375);\n\t\t\t\t}\n\n\t\t\t\tconst dotsDuration = clampPositive(interludeDuration - 750);\n\n\t\t\t\tscale = clampPositive(scale) * 0.7;\n\n\t\t\t\tcurStyle += ` scale(${scale})`;\n\n\t\t\t\tconst dot0Opacity = clamp(\n\t\t\t\t\t0.25,\n\t\t\t\t\t((currentDuration * 3) / dotsDuration) * 0.75,\n\t\t\t\t\t1,\n\t\t\t\t);\n\t\t\t\tconst dot1Opacity = clamp(\n\t\t\t\t\t0.25,\n\t\t\t\t\t(((currentDuration - dotsDuration / 3) * 3) / dotsDuration) * 0.75,\n\t\t\t\t\t1,\n\t\t\t\t);\n\t\t\t\tconst dot2Opacity = clamp(\n\t\t\t\t\t0.25,\n\t\t\t\t\t(((currentDuration - (dotsDuration / 3) * 2) * 3) / dotsDuration) *\n\t\t\t\t\t\t0.75,\n\t\t\t\t\t1,\n\t\t\t\t);\n\n\t\t\t\tthis.dot0.style.opacity = `${clamp01(globalOpacity * dot0Opacity)}`;\n\t\t\t\tthis.dot1.style.opacity = `${clamp01(globalOpacity * dot1Opacity)}`;\n\t\t\t\tthis.dot2.style.opacity = `${clamp01(globalOpacity * dot2Opacity)}`;\n\t\t\t} else {\n\t\t\t\tcurStyle += \" scale(0)\";\n\t\t\t\tthis.dot0.style.opacity = \"0\";\n\t\t\t\tthis.dot1.style.opacity = \"0\";\n\t\t\t\tthis.dot2.style.opacity = \"0\";\n\t\t\t}\n\n\t\t\tcurStyle += \";\";\n\n\t\t\tif (this.lastStyle !== curStyle) {\n\t\t\t\tthis.element.setAttribute(\"style\", curStyle);\n\t\t\t\tthis.lastStyle = curStyle;\n\t\t\t}\n\t\t}\n\t}\n\tdispose(): void {\n\t\tthis.element.remove();\n\t}\n}\n","/**\n * @fileoverview\n * @see https://github.com/wilsonpage/fastdom/blob/master/fastdom.js\n */\n\ninterface Task<T> {\n\ttask: () => T;\n\tresolve: (value: T) => void;\n\treject: (reason?: unknown) => void;\n}\n\n// biome-ignore lint/suspicious/noExplicitAny: util functions\nconst measureTasks: Task<any>[] = [];\n// biome-ignore lint/suspicious/noExplicitAny: util functions\nconst mutateTasks: Task<any>[] = [];\nlet scheduled = false;\n\nfunction onFlush() {\n\tlet tmp = mutateTasks.shift();\n\twhile (tmp) {\n\t\ttry {\n\t\t\ttmp.resolve(tmp.task());\n\t\t} catch (error) {\n\t\t\ttmp.reject(error);\n\t\t}\n\t\ttmp = mutateTasks.shift();\n\t}\n\ttmp = measureTasks.shift();\n\twhile (tmp) {\n\t\ttry {\n\t\t\ttmp.resolve(tmp.task());\n\t\t} catch (error) {\n\t\t\ttmp.reject(error);\n\t\t}\n\t\ttmp = measureTasks.shift();\n\t}\n\tscheduled = false;\n}\n\nfunction scheduleFlush() {\n\tif (!scheduled) {\n\t\tscheduled = true;\n\t\trequestAnimationFrame(onFlush);\n\t}\n}\n\nexport function measure<T>(callback: () => T): Promise<T> {\n\tconst task: Task<T> = {\n\t\ttask: callback,\n\t\tresolve: () => {},\n\t\treject: () => {},\n\t};\n\tconst promise = new Promise<T>((resolve, reject) => {\n\t\ttask.resolve = resolve;\n\t\ttask.reject = reject;\n\t});\n\tmeasureTasks.push(task);\n\tscheduleFlush();\n\treturn promise;\n}\n\nexport function mutate(callback: () => void): Promise<unknown> {\n\tconst task: Task<void> = {\n\t\ttask: callback,\n\t\tresolve: () => {},\n\t\treject: () => {},\n\t};\n\tconst promise = new Promise((resolve, reject) => {\n\t\ttask.resolve = resolve;\n\t\ttask.reject = reject;\n\t});\n\tmutateTasks.push(task);\n\tscheduleFlush();\n\treturn promise;\n}\n","export function derivative(f: (x: number) => number) {\n\tconst h = 0.001;\n\treturn (x: number): number => (f(x + h) - f(x - h)) / (2 * h);\n}\n\nexport function getVelocity(f: (t: number) => number): (t: number) => number {\n\treturn derivative(f);\n}\n","import { getVelocity } from \"./derivative.ts\";\n\n/** MIT License github.com/pushkine/ */\nexport interface SpringParams {\n\tmass: number; // = 1.0\n\tdamping: number; // = 10.0\n\tstiffness: number; // = 100.0\n\tsoft: boolean; // = false\n}\n\ntype seconds = number;\n\nexport class Spring {\n\tprivate currentPosition = 0;\n\tprivate targetPosition = 0;\n\tprivate currentTime = 0;\n\tprivate params: Partial<SpringParams> = {};\n\tprivate currentSolver: (t: seconds) => number;\n\tprivate getV: (t: seconds) => number;\n\tprivate getV2: (t: seconds) => number;\n\tprivate queueParams:\n\t\t| (Partial<SpringParams> & {\n\t\t\t\ttime: number;\n\t\t })\n\t\t| undefined;\n\tprivate queuePosition:\n\t\t| {\n\t\t\t\ttime: number;\n\t\t\t\tposition: number;\n\t\t }\n\t\t| undefined;\n\tconstructor(currentPosition = 0) {\n\t\tthis.targetPosition = currentPosition;\n\t\tthis.currentPosition = this.targetPosition;\n\t\tthis.currentSolver = () => this.targetPosition;\n\t\tthis.getV = () => 0;\n\t\tthis.getV2 = () => 0;\n\t}\n\tprivate resetSolver() {\n\t\tconst curV = this.getV(this.currentTime);\n\t\tthis.currentTime = 0;\n\t\tthis.currentSolver = solveSpring(\n\t\t\tthis.currentPosition,\n\t\t\tcurV,\n\t\t\tthis.targetPosition,\n\t\t\t0,\n\t\t\tthis.params,\n\t\t);\n\t\tthis.getV = getVelocity(this.currentSolver);\n\t\tthis.getV2 = getVelocity(this.getV);\n\t}\n\tarrived(): boolean {\n\t\treturn (\n\t\t\tMath.abs(this.targetPosition - this.currentPosition) < 0.01 &&\n\t\t\tthis.getV(this.currentTime) < 0.01 &&\n\t\t\tthis.getV2(this.currentTime) < 0.01 &&\n\t\t\tthis.queueParams === undefined &&\n\t\t\tthis.queuePosition === undefined\n\t\t);\n\t}\n\tsetPosition(targetPosition: number): void {\n\t\tthis.targetPosition = targetPosition;\n\t\tthis.currentPosition = targetPosition;\n\t\tthis.currentSolver = () => this.targetPosition;\n\t\tthis.getV = () => 0;\n\t\tthis.getV2 = () => 0;\n\t}\n\tupdate(delta = 0): void {\n\t\tthis.currentTime += delta;\n\t\tthis.currentPosition = this.currentSolver(this.currentTime);\n\t\tif (this.queueParams) {\n\t\t\tthis.queueParams.time -= delta;\n\t\t\tif (this.queueParams.time <= 0) {\n\t\t\t\tthis.updateParams({\n\t\t\t\t\t...this.queueParams,\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t\tif (this.queuePosition) {\n\t\t\tthis.queuePosition.time -= delta;\n\t\t\tif (this.queuePosition.time <= 0) {\n\t\t\t\tthis.setTargetPosition(this.queuePosition.position);\n\t\t\t}\n\t\t}\n\t\tif (this.arrived()) {\n\t\t\tthis.setPosition(this.targetPosition);\n\t\t}\n\t}\n\tupdateParams(params: Partial<SpringParams>, delay = 0): void {\n\t\tif (delay > 0) {\n\t\t\tthis.queueParams = {\n\t\t\t\t...(this.queuePosition ?? {}),\n\t\t\t\t...params,\n\t\t\t\ttime: delay,\n\t\t\t};\n\t\t} else {\n\t\t\tthis.queuePosition = undefined;\n\t\t\tthis.params = {\n\t\t\t\t...this.params,\n\t\t\t\t...params,\n\t\t\t};\n\t\t\tthis.resetSolver();\n\t\t}\n\t}\n\tsetTargetPosition(targetPosition: number, delay = 0): void {\n\t\tif (delay > 0) {\n\t\t\tthis.queuePosition = {\n\t\t\t\t...(this.queuePosition ?? {}),\n\t\t\t\tposition: targetPosition,\n\t\t\t\ttime: delay,\n\t\t\t};\n\t\t} else {\n\t\t\tthis.queuePosition = undefined;\n\t\t\tthis.targetPosition = targetPosition;\n\t\t\tthis.resetSolver();\n\t\t}\n\t}\n\tgetCurrentPosition(): number {\n\t\treturn this.currentPosition;\n\t}\n}\n\nfunction solveSpring(\n\tfrom: number,\n\tvelocity: number,\n\tto: number,\n\tdelay: seconds = 0,\n\tparams?: Partial<SpringParams>,\n): (t: seconds) => number {\n\tconst soft = params?.soft ?? false;\n\tconst stiffness = params?.stiffness ?? 100;\n\tconst damping = params?.damping ?? 10;\n\tconst mass = params?.mass ?? 1;\n\tconst delta = to - from;\n\tif (soft || 1.0 <= damping / (2.0 * Math.sqrt(stiffness * mass))) {\n\t\tconst angular_frequency = -Math.sqrt(stiffness / mass);\n\t\tconst leftover = -angular_frequency * delta - velocity;\n\t\treturn (t: seconds) => {\n\t\t\tt -= delay;\n\t\t\tif (t < 0) return from;\n\t\t\treturn to - (delta + t * leftover) * Math.E ** (t * angular_frequency);\n\t\t};\n\t}\n\tconst damping_frequency = Math.sqrt(4.0 * mass * stiffness - damping ** 2.0);\n\tconst leftover =\n\t\t(damping * delta - 2.0 * mass * velocity) / damping_frequency;\n\tconst dfm = (0.5 * damping_frequency) / mass;\n\tconst dm = -(0.5 * damping) / mass;\n\treturn (t: seconds) => {\n\t\tt -= delay;\n\t\tif (t < 0) return from;\n\t\treturn (\n\t\t\tto -\n\t\t\t(Math.cos(t * dfm) * delta + Math.sin(t * dfm) * leftover) *\n\t\t\t\tMath.E ** (t * dm)\n\t\t);\n\t};\n}\n","import type { Disposable, HasElement } from \"#interfaces\";\nimport styles from \"#styles/lyric-player.module.css\";\nimport { measure } from \"#utils/schedule.ts\";\nimport { Spring } from \"#utils/spring.ts\";\nimport type { LyricPlayerBase } from \".\";\n\ninterface LineTransforms {\n\tposX: Spring;\n\tposY: Spring;\n}\n\nexport class BottomLineEl implements HasElement, Disposable {\n\tprivate element: HTMLElement = document.createElement(\"div\");\n\tprivate left = 0;\n\tprivate top = 0;\n\tprivate delay = 0;\n\t// 由 LyricPlayer 来设置\n\tlineSize: [number, number] = [0, 0];\n\treadonly lineTransforms: LineTransforms = {\n\t\tposX: new Spring(0),\n\t\tposY: new Spring(0),\n\t};\n\tprivate isFocused = false;\n\tprivate blur = 0;\n\tconstructor(private lyricPlayer: LyricPlayerBase) {\n\t\tthis.element.setAttribute(\n\t\t\t\"class\",\n\t\t\t`${styles.lyricLine} ${styles.bottomLine}`,\n\t\t);\n\t\tthis.element.dataset.bottomLine = \"true\";\n\t\tthis.rebuildStyle();\n\t}\n\tasync measureSize(): Promise<[number, number]> {\n\t\tconst size: [number, number] = await measure(() => [\n\t\t\tthis.element.clientWidth,\n\t\t\tthis.element.clientHeight,\n\t\t]);\n\t\treturn size;\n\t}\n\tprivate lastStyle = \"\";\n\tshow(): void {\n\t\tthis.rebuildStyle();\n\t}\n\thide(): void {\n\t\tthis.rebuildStyle();\n\t}\n\tsetFocused(focused: boolean): void {\n\t\tif (this.isFocused !== focused) {\n\t\t\tthis.isFocused = focused;\n\t\t\tif (focused) {\n\t\t\t\tthis.element.dataset.focused = \"true\";\n\t\t\t} else {\n\t\t\t\tdelete this.element.dataset.focused;\n\t\t\t}\n\t\t}\n\t}\n\tprivate rebuildStyle() {\n\t\tlet style = `transform:translate(${this.lineTransforms.posX\n\t\t\t.getCurrentPosition()\n\t\t\t.toFixed(2)}px,${this.lineTransforms.posY\n\t\t\t.getCurrentPosition()\n\t\t\t.toFixed(2)}px);`;\n\n\t\tif (!this.lyricPlayer.getEnableSpring() && this.isInSight) {\n\t\t\tstyle += `transition-delay:${this.delay}ms;`;\n\t\t}\n\n\t\tstyle += `filter:blur(${Math.min(5, this.blur)}px);`;\n\n\t\tif (style !== this.lastStyle) {\n\t\t\tthis.lastStyle = style;\n\t\t\tthis.element.setAttribute(\"style\", style);\n\t\t}\n\t}\n\tgetElement(): HTMLElement {\n\t\treturn this.element;\n\t}\n\tsetTransform(\n\t\tleft: number = this.left,\n\t\ttop: number = this.top,\n\t\tblur = 0,\n\t\tforce = false,\n\t\tdelay = 0,\n\t): void {\n\t\tthis.left = left;\n\t\tthis.top = top;\n\t\tthis.delay = (delay * 1000) | 0;\n\n\t\tif (force || !this.lyricPlayer.getEnableSpring()) {\n\t\t\tthis.blur = Math.min(32, blur);\n\t\t\tif (force) this.element.classList.add(styles.tmpDisableTransition);\n\t\t\tthis.lineTransforms.posX.setPosition(left);\n\t\t\tthis.lineTransforms.posY.setPosition(top);\n\t\t\tif (!this.lyricPlayer.getEnableSpring()) this.show();\n\t\t\telse this.rebuildStyle();\n\t\t\tif (force)\n\t\t\t\trequestAnimationFrame(() => {\n\t\t\t\t\tthis.element.classList.remove(styles.tmpDisableTransition);\n\t\t\t\t});\n\t\t} else {\n\t\t\tthis.blur = Math.min(5, blur);\n\t\t\tthis.lineTransforms.posX.setTargetPosition(left, delay);\n\t\t\tthis.lineTransforms.posY.setTargetPosition(top, delay);\n\t\t}\n\t}\n\tupdate(delta = 0): void {\n\t\tif (!this.lyricPlayer.getEnableSpring()) return;\n\t\tthis.lineTransforms.posX.update(delta);\n\t\tthis.lineTransforms.posY.update(delta);\n\t\tif (this.isInSight) {\n\t\t\tthis.show();\n\t\t} else {\n\t\t\tthis.hide();\n\t\t}\n\t}\n\tget isInSight(): boolean {\n\t\tconst l = this.lineTransforms.posX.getCurrentPosition();\n\t\tconst t = this.lineTransforms.posY.getCurrentPosition();\n\t\tconst r = l + this.lineSize[0];\n\t\tconst b = t + this.lineSize[1];\n\t\tconst pr = this.lyricPlayer.size[0];\n\t\tconst pb = this.lyricPlayer.size[1];\n\t\treturn !(l > pr || t > pb || r < 0 || b < 0);\n\t}\n\tdispose(): void {\n\t\tthis.element.remove();\n\t}\n}\n","type ValueOf<T extends Record<PropertyKey, unknown>> = T[keyof T];\n\n/** 歌词中不雅用语的掩码模式 */\nexport const MaskObsceneWordsMode = {\n\t/** 禁用任何不雅用语掩码 */\n\tDisabled: \"\",\n\t/** 完全掩码所有不雅用语 */\n\tFullMask: \"full-mask\",\n\t/** 保留首尾字符,屏蔽中间字符 */\n\tPartialMask: \"partial-mask\",\n} as const;\n\n/** 歌词中不雅用语的掩码模式枚举类型,见 {@link MaskObsceneWordsMode} */\nexport type MaskObsceneWordsMode = ValueOf<typeof MaskObsceneWordsMode>;\n\n/**\n * 歌词行的渲染模式\n * @internal\n */\nexport const LyricLineRenderMode = {\n\tSOLID: 0,\n\tGRADIENT: 1,\n} as const;\n\n/**\n * 歌词行的渲染模式枚举类型,见 {@link LyricLineRenderMode}\n * @internal\n */\nexport type LyricLineRenderMode = ValueOf<typeof LyricLineRenderMode>;\n\n/** 布局对齐锚点 */\nexport const LayoutAlignAnchor = {\n\tTop: \"top\",\n\tCenter: \"center\",\n\tBottom: \"bottom\",\n} as const;\n\n/** 布局对齐锚点枚举类型,见 {@link LayoutAlignAnchor} */\nexport type LayoutAlignAnchor = ValueOf<typeof LayoutAlignAnchor>;\n","import { clamp } from \"#utils/clamp.ts\";\nimport type { SpringParams } from \"#utils/spring.ts\";\nimport type { LayoutAlignAnchor } from \"./consts.ts\";\nimport type { LyricLineGroupBase } from \"./group.ts\";\nimport type { PlayerTimelineState } from \"./timeline.ts\";\n\n/**\n * 播放器布局状态。\n *\n * 这部分状态保存布局计算阶段所需的配置项与缓存值,\n * 例如对齐方式、间奏点尺寸、上一轮布局命中的目标行等。\n * 不描述播放时间线或用户滚动交互,仅记录当前歌词排布。\n */\nexport interface PlayerLayoutState {\n\t/** 间奏点元素当前测量得到的尺寸 */\n\tinterludeDotsSize: [number, number];\n\t/** 上一轮布局实际对齐的目标歌词行索引 */\n\ttargetAlignIndex: number;\n\t/** 上一轮布局时是否处于间奏区间 */\n\tlastInterludeState: boolean;\n\t/** 当前歌词目标行的对齐锚点 */\n\talignAnchor: LayoutAlignAnchor;\n\t/** 当前歌词目标行在播放器高度中的相对对齐位置 */\n\talignPosition: number;\n\t/** 视口上下额外保留的预渲染距离,单位为像素 */\n\toverscanPx: number;\n}\n\n/**\n * 当前命中的间奏区间信息。\n *\n * 当播放器检测到当前时间处于两句歌词之间的较长空档期时,\n * 会生成该结构,用于驱动间奏点动画的显示位置与时间范围。\n */\nexport interface PlayerInterlude {\n\t/** 间奏动画的开始时间 */\n\tstartTime: number;\n\t/** 间奏动画的结束时间 */\n\tendTime: number;\n\t/** 间奏点应插入到哪一行之后;`-1` 表示位于第一行之前 */\n\tanchorLineIndex: number;\n\t/** 间奏结束后的下一句是否为对唱歌词 */\n\tisNextDuet: boolean;\n}\n\n/** {@link computeCurrentInterlude} 的参数类型 */\nexport interface ComputeCurrentInterludeInput {\n\tcurrentTime: number;\n\tscrollToIndex: number;\n\tcurrentGroups: LyricLineGroupBase[];\n}\n\n/**\n * 根据当前时间与当前目标行,计算当前是否处于某个可展示的间奏区间。\n *\n * 仅识别时间轴上的间奏空档,不涉及具体 DOM 元素的创建与摆放。\n * 若当前不应展示间奏动画,则返回 `undefined`。\n */\nexport function computeCurrentInterlude(\n\tinput: ComputeCurrentInterludeInput,\n): PlayerInterlude | undefined {\n\tconst currentTime = input.currentTime + 20;\n\tconst currentIndex = input.scrollToIndex;\n\tconst groups = input.currentGroups;\n\n\tconst checkGap = (k: number): PlayerInterlude | undefined => {\n\t\tif (k < -1 || k >= groups.length - 1) return undefined;\n\n\t\tconst prevGroup = k === -1 ? null : groups[k];\n\t\tconst nextGroup = groups[k + 1];\n\n\t\tconst gapStart = prevGroup ? prevGroup.endTime : 0;\n\t\tconst gapEnd = Math.max(gapStart, nextGroup.startTime - 250);\n\n\t\tif (gapEnd - gapStart < 4000) return undefined;\n\n\t\tif (gapEnd > currentTime && gapStart < currentTime) {\n\t\t\treturn {\n\t\t\t\tstartTime: Math.max(gapStart, currentTime),\n\t\t\t\tendTime: gapEnd,\n\t\t\t\tanchorLineIndex: k,\n\t\t\t\tisNextDuet: nextGroup.mainLine.getLine().isDuet,\n\t\t\t};\n\t\t}\n\t\treturn undefined;\n\t};\n\n\treturn (\n\t\tcheckGap(currentIndex - 1) ||\n\t\tcheckGap(currentIndex) ||\n\t\tcheckGap(currentIndex + 1)\n\t);\n}\n\n/**\n * {@link computeLinePosYSpringParams} 的参数类型,\n * 用于决定当前歌词纵向滚动动画的弹簧参数。\n */\nexport interface ComputeLinePosYSpringParamsInput {\n\t/** 是否启用弹簧动画 */\n\tenabled: boolean;\n\t/** 当前用于布局的歌词数据 */\n\tcurrentGroups: LyricLineGroupBase[];\n\t/** 当前目标对齐行索引 */\n\tscrollToIndex: number;\n\t/** 是否处于 seeking 模式 */\n\tisSeeking: boolean;\n\t/** 是否处于间奏区间 */\n\tisInterludeActive: boolean;\n}\n\n/** {@link computeLinePosYSpringParams} 的结果类型 */\nexport interface ComputeLinePosYSpringParamsResult {\n\t/** 是否需要更新纵向弹簧参数 */\n\tshouldUpdate: boolean;\n\t/** 若需要更新,则返回新的参数 */\n\tparams?: Partial<SpringParams>;\n}\n\n/**\n * 根据当前播放上下文计算歌词纵向滚动动画的弹簧参数。\n *\n * 其策略为:\n * - seeking 或间奏时使用更稳定的固定参数\n * - 普通播放时根据相邻歌词的时间间隔动态调整 stiffness / damping\n */\nexport function computeLinePosYSpringParams(\n\tinput: ComputeLinePosYSpringParamsInput,\n): ComputeLinePosYSpringParamsResult {\n\tconst {\n\t\tenabled,\n\t\tcurrentGroups,\n\t\tscrollToIndex,\n\t\tisSeeking,\n\t\tisInterludeActive,\n\t} = input;\n\n\tif (!enabled || currentGroups.length === 0) {\n\t\treturn { shouldUpdate: false };\n\t}\n\n\tif (isSeeking || isInterludeActive) {\n\t\treturn {\n\t\t\tshouldUpdate: true,\n\t\t\tparams: { stiffness: 90, damping: 15 },\n\t\t};\n\t}\n\n\tconst currentGroup = currentGroups[scrollToIndex];\n\tconst prevGroup = currentGroups[scrollToIndex - 1];\n\n\tif (!currentGroup || !prevGroup) {\n\t\treturn { shouldUpdate: false };\n\t}\n\n\tconst interval = currentGroup.startTime - prevGroup.startTime;\n\n\tconst MIN_INTERVAL = 100;\n\tconst MAX_INTERVAL = 800;\n\tconst clampedInterval = clamp(interval, MIN_INTERVAL, MAX_INTERVAL);\n\n\tconst MAX_STIFFNESS = 220;\n\tconst MIN_STIFFNESS = 170;\n\n\tlet ratio =\n\t\t1 - (clampedInterval - MIN_INTERVAL) / (MAX_INTERVAL - MIN_INTERVAL);\n\n\tratio = ratio ** 0.2;\n\n\tconst targetStiffness =\n\t\tMIN_STIFFNESS + ratio * (MAX_STIFFNESS - MIN_STIFFNESS);\n\n\tconst dampingMultiplier = 2.2;\n\tconst targetDamping = Math.sqrt(targetStiffness) * dampingMultiplier;\n\n\treturn {\n\t\tshouldUpdate: true,\n\t\tparams: {\n\t\t\tstiffness: targetStiffness,\n\t\t\tdamping: targetDamping,\n\t\t},\n\t};\n}\n\n/**\n * {@link computeGroupPresentation} 的参数类型。\n *\n * 描述一行歌词在当前布局上下文中的全部关键信息,\n * 用于计算其视觉呈现结果。\n */\nexport interface ComputeGroupPresentationInput {\n\t/** 当前歌词组索引 */\n\tgroupIndex: number;\n\t/** 当前目标对齐行索引 */\n\tscrollToIndex: number;\n\t/** 当前缓冲区({@link PlayerTimelineState.bufferedGroups})中最靠后的歌词行索引 */\n\tlatestIndex: number;\n\t/** 当前歌词行是否在缓冲集合内 */\n\thasBuffered: boolean;\n\t/** 是否启用隐藏已播放行 */\n\thidePassedLines: boolean;\n\t/** 是否处于播放状态 */\n\tisPlaying: boolean;\n\t/** 当前歌词是否为非逐词歌词 */\n\tisNonDynamic: boolean;\n\t/** 是否启用模糊效果 */\n\tenableBlur: boolean;\n\t/** 是否正在进行滚动交互 */\n\tisUserScrolling: boolean;\n\t/** 是否处于紧凑布局环境,例如窄屏 */\n\tisCompact: boolean;\n\t/** 当前命中的间奏区间信息 */\n\tinterlude?: PlayerInterlude;\n}\n\n/** {@link computeGroupPresentation} 的结果类型 */\nexport interface ComputeGroupPresentationResult {\n\t/** 当前歌词行是否应视为活跃行 */\n\tisActive: boolean;\n\t/** 当前歌词行的目标不透明度 */\n\ttargetOpacity: number;\n\t/** 当前歌词行的目标模糊值 */\n\tblurLevel: number;\n}\n\n/**\n * 计算一组歌词在当前布局中的视觉呈现参数。\n *\n * 根据播放状态、缓冲状态、布局模式与间奏信息,\n * 生成一组歌词最终应使用的活跃状态、不透明度与模糊值。\n */\nexport function computeGroupPresentation(\n\tinput: ComputeGroupPresentationInput,\n): ComputeGroupPresentationResult {\n\tconst {\n\t\tgroupIndex,\n\t\tscrollToIndex,\n\t\tlatestIndex,\n\t\thasBuffered,\n\t\thidePassedLines,\n\t\tisPlaying,\n\t\tisNonDynamic,\n\t\tenableBlur,\n\t\tisUserScrolling,\n\t\tisCompact,\n\t\tinterlude,\n\t} = input;\n\n\tconst isActive =\n\t\thasBuffered || (groupIndex >= scrollToIndex && groupIndex < latestIndex);\n\n\tconst blurLevel = computeLineBlur({\n\t\tenableBlur,\n\t\tisUserScrolling,\n\t\tisActive,\n\t\titemIndex: groupIndex,\n\t\tscrollToIndex,\n\t\tlatestIndex,\n\t\tisCompact,\n\t});\n\n\tlet targetOpacity: number;\n\tif (hidePassedLines) {\n\t\tif (\n\t\t\tgroupIndex <\n\t\t\t\t(interlude ? interlude.anchorLineIndex + 1 : scrollToIndex) &&\n\t\t\tisPlaying\n\t\t) {\n\t\t\t// 为了避免浏览器优化,这里使用了一个极小但不为零的值(几乎不可见)\n\t\t\ttargetOpacity = 1e-4;\n\t\t} else if (hasBuffered) {\n\t\t\ttargetOpacity = 0.85;\n\t\t} else {\n\t\t\ttargetOpacity = isNonDynamic ? 0.2 : 1;\n\t\t}\n\t} else if (hasBuffered) {\n\t\ttargetOpacity = 0.85;\n\t} else {\n\t\ttargetOpacity = isNonDynamic ? 0.2 : 1;\n\t}\n\n\treturn { isActive, targetOpacity, blurLevel };\n}\n\n/** {@link computeLineBlur} 的参数类型 */\nexport interface ComputeLineBlurInput {\n\t/** 是否启用了模糊效果 */\n\tenableBlur: boolean;\n\t/** 用户是否正在滚动 */\n\tisUserScrolling: boolean;\n\t/** 当前项是否活跃 */\n\tisActive: boolean;\n\t/** 当前项索引 */\n\titemIndex: number;\n\t/** 当前目标对齐行索引 */\n\tscrollToIndex: number;\n\t/** 缓冲区中最靠后的歌词行索引 */\n\tlatestIndex: number;\n\t/** 是否处于紧凑布局环境,例如窄屏 */\n\tisCompact: boolean;\n}\n\n/**\n * 计算一行歌词在当前布局中的模糊等级。\n *\n * 越远离当前对齐区域的歌词会得到更高的模糊值;\n * 活跃行、滚动交互中或关闭模糊效果时返回 `0`。\n */\nexport function computeLineBlur(input: ComputeLineBlurInput): number {\n\tconst {\n\t\tenableBlur,\n\t\tisUserScrolling,\n\t\tisActive,\n\t\titemIndex,\n\t\tscrollToIndex,\n\t\tlatestIndex,\n\t\tisCompact,\n\t} = input;\n\n\tif (!enableBlur || isUserScrolling || isActive) {\n\t\treturn 0;\n\t}\n\n\tlet blurLevel = 1;\n\n\tif (itemIndex < scrollToIndex) {\n\t\tblurLevel += Math.abs(scrollToIndex - itemIndex) + 1;\n\t} else {\n\t\tblurLevel += Math.abs(itemIndex - Math.max(scrollToIndex, latestIndex));\n\t}\n\n\treturn isCompact ? blurLevel * 0.8 : blurLevel;\n}\n","import { clamp } from \"#utils/clamp.ts\";\n\n/**\n * 播放器滚动状态。\n *\n * 这部分状态描述用户手势/滚轮滚动产生的临时偏移,以及当前允许滚动的范围。\n * 改状态仅记录用户如何把当前视图上下拖动,不决定应该滚动到哪一行,\n * 后者由时间线状态与布局计算共同决定。\n */\nexport interface PlayerScrollState {\n\t/** 允许的滚动偏移范围 */\n\tscrollBoundary: {\n\t\t/** 允许的最小偏移量 */\n\t\tminOffset: number;\n\t\t/** 允许的最大偏移量 */\n\t\tmaxOffset: number;\n\t};\n\t/** 当前用户滚动带来的额外偏移量 */\n\tscrollOffset: number;\n\t/** 是否允许用户通过手势或滚轮滚动歌词视图 */\n\tallowScroll: boolean;\n\t/** 是否处于用户滚动过,尚未回归自动对齐的状态 */\n\tisScrolled: boolean;\n\t/** 是否正在进行滚动交互或惯性滚动 */\n\tisUserScrolling: boolean;\n}\n\n/**\n * 将滚动偏移量限制在当前允许的滚动边界内。\n *\n * 当手势滚动、滚轮滚动或惯性滚动更新了 {@link PlayerScrollState.scrollOffset}\n * 后,应调用本函数以避免视图越界。\n */\nexport function clampPlayerScrollOffset(scrollState: PlayerScrollState): void {\n\tscrollState.scrollOffset = clamp(\n\t\tscrollState.scrollOffset,\n\t\tscrollState.scrollBoundary.minOffset,\n\t\tscrollState.scrollBoundary.maxOffset,\n\t);\n}\n\n/**\n * 重置滚动状态到未发生用户滚动时的初始状态。\n *\n * 本函数会清除当前偏移,并结束“已滚动”与“正在滚动”的标记;\n * **不会清理**外部持有的计时器或事件监听器。\n */\nexport function resetPlayerScrollState(scrollState: PlayerScrollState): void {\n\tscrollState.isScrolled = false;\n\tscrollState.scrollOffset = 0;\n\tscrollState.isUserScrolling = false;\n}\n\n/**\n * {@link attachPlayerScrollHandlers} 所需的宿主回调。\n *\n * 这些回调将滚动模块与具体播放器实现解耦:\n * 滚动模块只负责处理输入事件和更新滚动状态,布局刷新、点击转发等副作用\n * 由宿主决定如何执行。\n */\nexport interface AttachPlayerScrollHandlersCallbacks {\n\t/** 开始一次滚动处理前调用,返回 `false` 可阻止本次滚动 */\n\tonBeginScroll: () => boolean;\n\t/** 一次滚动交互或惯性滚动结束时调用 */\n\tonEndScroll: () => void;\n\t/** 请求宿主重新布局 */\n\tonLayout: (sync: boolean, force: boolean) => void;\n\t/** 判断某个点击目标是否仍属于当前播放器视图 */\n\tcontainsTarget: (target: Node) => boolean;\n\t/** 将点击事件转发给命中的目标元素 */\n\tclickTarget: (target: HTMLElement) => void;\n}\n\n/**\n * 向指定元素挂载歌词滚动相关的交互处理器。\n *\n * 该函数会处理:\n * - 触摸拖拽滚动\n * - 触摸结束后的惯性滚动\n * - 滚轮滚动\n * - 轻触时的点击透传\n *\n * 只更新 {@link PlayerScrollState} 并通过回调通知宿主执行布局或其它副作用,\n * 不直接依赖具体的播放器类实现。\n */\nexport function attachPlayerScrollHandlers(\n\telement: HTMLElement,\n\tscrollState: PlayerScrollState,\n\tcallbacks: AttachPlayerScrollHandlersCallbacks,\n): void {\n\tlet startScrollY = 0;\n\n\tlet startTouchPosY = 0;\n\tlet startTouchStartX = 0;\n\tlet startTouchStartY = 0;\n\n\tlet lastMoveY = 0;\n\tlet startScrollTime = 0;\n\tlet scrollSpeed = 0;\n\tlet curScrollId = 0;\n\n\telement.addEventListener(\"touchstart\", (evt) => {\n\t\tif (callbacks.onBeginScroll()) {\n\t\t\tscrollState.isUserScrolling = true;\n\n\t\t\tevt.preventDefault();\n\t\t\tstartScrollY = scrollState.scrollOffset;\n\n\t\t\tstartTouchPosY = evt.touches[0].screenY;\n\t\t\tlastMoveY = startTouchPosY;\n\n\t\t\tstartTouchStartX = evt.touches[0].screenX;\n\t\t\tstartTouchStartY = evt.touches[0].screenY;\n\n\t\t\tstartScrollTime = Date.now();\n\t\t\tscrollSpeed = 0;\n\n\t\t\tcallbacks.onLayout(true, true);\n\t\t}\n\t});\n\n\telement.addEventListener(\"touchmove\", (evt) => {\n\t\tif (callbacks.onBeginScroll()) {\n\t\t\tevt.preventDefault();\n\t\t\tconst currentY = evt.touches[0].screenY;\n\n\t\t\tconst deltaY = currentY - startTouchPosY;\n\t\t\tscrollState.scrollOffset = startScrollY - deltaY;\n\t\t\tclampPlayerScrollOffset(scrollState);\n\n\t\t\tconst now = Date.now();\n\t\t\tconst dt = now - startScrollTime;\n\t\t\tif (dt > 0) {\n\t\t\t\tscrollSpeed = (currentY - lastMoveY) / dt;\n\t\t\t}\n\t\t\tlastMoveY = currentY;\n\t\t\tstartScrollTime = now;\n\n\t\t\tcallbacks.onLayout(true, true);\n\t\t}\n\t});\n\n\telement.addEventListener(\"touchend\", (evt) => {\n\t\tif (callbacks.onBeginScroll()) {\n\t\t\tevt.preventDefault();\n\n\t\t\tconst touch = evt.changedTouches[0];\n\t\t\tconst moveX = Math.abs(touch.screenX - startTouchStartX);\n\t\t\tconst moveY = Math.abs(touch.screenY - startTouchStartY);\n\n\t\t\tif (moveX < 10 && moveY < 10) {\n\t\t\t\tconst target = document.elementFromPoint(touch.clientX, touch.clientY);\n\t\t\t\tif (target instanceof HTMLElement && callbacks.containsTarget(target)) {\n\t\t\t\t\tcallbacks.clickTarget(target);\n\t\t\t\t}\n\t\t\t\tscrollState.isUserScrolling = false;\n\t\t\t\tcallbacks.onEndScroll();\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tstartTouchPosY = 0;\n\t\t\tconst scrollId = ++curScrollId;\n\n\t\t\tif (Math.abs(scrollSpeed) < 0.1) scrollSpeed = 0;\n\n\t\t\tlet lastFrameTime = performance.now();\n\n\t\t\tconst onScrollFrame = (time: number) => {\n\t\t\t\tif (scrollId !== curScrollId) return;\n\n\t\t\t\tconst dt = time - lastFrameTime;\n\t\t\t\tlastFrameTime = time;\n\n\t\t\t\tif (dt <= 0 || dt > 100) {\n\t\t\t\t\trequestAnimationFrame(onScrollFrame);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tif (Math.abs(scrollSpeed) > 0.05) {\n\t\t\t\t\tscrollState.scrollOffset -= scrollSpeed * dt;\n\n\t\t\t\t\tclampPlayerScrollOffset(scrollState);\n\n\t\t\t\t\tconst frictionFactor = 0.95 ** (dt / 16);\n\t\t\t\t\tscrollSpeed *= frictionFactor;\n\n\t\t\t\t\tcallbacks.onLayout(true, true);\n\n\t\t\t\t\trequestAnimationFrame(onScrollFrame);\n\t\t\t\t} else {\n\t\t\t\t\tscrollState.isUserScrolling = false;\n\t\t\t\t\tcallbacks.onEndScroll();\n\t\t\t\t}\n\t\t\t};\n\n\t\t\trequestAnimationFrame(onScrollFrame);\n\t\t} else {\n\t\t\tscrollState.isUserScrolling = false;\n\t\t}\n\t});\n\n\telement.addEventListener(\n\t\t\"wheel\",\n\t\t(evt) => {\n\t\t\tif (callbacks.onBeginScroll()) {\n\t\t\t\tevt.preventDefault();\n\n\t\t\t\tif (evt.deltaMode === evt.DOM_DELTA_PIXEL) {\n\t\t\t\t\tscrollState.scrollOffset += evt.deltaY;\n\t\t\t\t\tclampPlayerScrollOffset(scrollState);\n\t\t\t\t\tcallbacks.onLayout(true, false);\n\t\t\t\t} else {\n\t\t\t\t\tscrollState.scrollOffset += evt.deltaY * 50;\n\t\t\t\t\tclampPlayerScrollOffset(scrollState);\n\t\t\t\t\tcallbacks.onLayout(false, false);\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t\t{ passive: false },\n\t);\n}\n","export const eqSet: <T>(xs: Set<T>, ys: Set<T>) => boolean = (\n\txs,\n\tys,\n): boolean => xs.size === ys.size && [...xs].every((x) => ys.has(x));\n","import { eqSet } from \"#utils/eq-set.ts\";\nimport type { LyricLineGroupBase } from \"./group.ts\";\n\n/**\n * 播放时间线状态。\n *\n * 描述播放器在时间轴上的当前位置,当前处于激活状态的歌词组信息\n */\nexport interface PlayerTimelineState {\n\t/** 当前播放时间,单位为毫秒 */\n\tcurrentTime: number;\n\t/** 上一次提交到时间线状态的播放时间,单位为毫秒 */\n\tlastCurrentTime: number;\n\t/** 热行:当前时间 {@link currentTime} 正在命中的组(含主行+可能的背景行) */\n\thotGroups: Set<number>;\n\t/** 缓冲组:UI 上还保持激活表现的组索引,通常包含热组,和刚结束仍在过渡中的组 */\n\tbufferedGroups: Set<number>;\n\t/** 当前应滚动对齐到的歌词组索引 */\n\tscrollToIndex: number;\n\t/** 是否正在拖拽进度条。若是,更新时丢弃缓冲行,并根据当前时间直接计算热行 */\n\tisSeeking: boolean;\n\t/** 是否处于播放状态 */\n\tisPlaying: boolean;\n\t/** 是否已经完成至少一次初始布局 */\n\tinitialLayoutFinished: boolean;\n}\n\n/** {@link computePlayerTimeState} 的参数类型 */\nexport interface ComputePlayerTimeStateInput {\n\ttime: number;\n\tcurrentGroups: LyricLineGroupBase[];\n\ttimelineState: Readonly<PlayerTimelineState>;\n}\n\n/** {@link computePlayerTimeState} 的返回类型 */\nexport interface ComputePlayerTimeStateResult {\n\t/** 计算后的新热组集合 */\n\tnextHotGroups: Set<number>;\n\t/** 需要新加入热组集合的组索引 */\n\taddedIds: Set<number>;\n\t/** 需要从热组集合中移除的组索引 */\n\tremovedHotIds: Set<number>;\n\t/** 需要从缓冲组集合中移除的组索引 */\n\tremovedBufferedIds: Set<number>;\n}\n\n/**\n * 计算指定时间点的热行/缓冲行状态转移的纯函数。其行为包括:\n *\n * - 根据当前时间和已有的热行状态,计算出新的热行状态,并返回应新增的热行 ID 和应移除的热行 ID\n * - 根据新的热行状态和已有的缓冲行状态,计算出应移除的缓冲行 ID\n */\nexport function computePlayerTimeState(\n\tinput: ComputePlayerTimeStateInput,\n): ComputePlayerTimeStateResult {\n\tconst {\n\t\ttime,\n\t\tcurrentGroups,\n\t\ttimelineState: { hotGroups, bufferedGroups },\n\t} = input;\n\n\tconst nextHotGroups = new Set(hotGroups);\n\tconst addedIds = new Set<number>();\n\tconst removedHotIds = new Set<number>();\n\tconst removedBufferedIds = new Set<number>();\n\n\tfor (const lastHotId of hotGroups) {\n\t\tconst group = currentGroups[lastHotId];\n\t\tif (!group || time < group.startTime || group.endTime <= time) {\n\t\t\tnextHotGroups.delete(lastHotId);\n\t\t\tremovedHotIds.add(lastHotId);\n\t\t}\n\t}\n\n\tfor (let id = 0; id < currentGroups.length; id++) {\n\t\tconst group = currentGroups[id];\n\t\tif (!group) continue;\n\n\t\tif (\n\t\t\tgroup.startTime <= time &&\n\t\t\tgroup.endTime > time &&\n\t\t\t!nextHotGroups.has(id)\n\t\t) {\n\t\t\tnextHotGroups.add(id);\n\t\t\taddedIds.add(id);\n\t\t}\n\t}\n\n\tfor (const id of bufferedGroups) {\n\t\tif (!nextHotGroups.has(id)) {\n\t\t\tremovedBufferedIds.add(id);\n\t\t}\n\t}\n\n\treturn {\n\t\tnextHotGroups,\n\t\taddedIds,\n\t\tremovedHotIds,\n\t\tremovedBufferedIds,\n\t};\n}\n\n/**\n * 在 seeking 场景下,根据当前时间选出应对齐滚动到的目标行索引。\n *\n * 若当前仍存在缓冲行,则优先对齐到最靠前的缓冲行;\n * 否则对齐到第一条开始时间不小于当前时间的歌词行。\n */\nexport function pickScrollToIndexForSeek(\n\ttime: number,\n\tcurrentGroups: LyricLineGroupBase[],\n\tbufferedGroups: ReadonlySet<number>,\n): number {\n\tif (bufferedGroups.size > 0) {\n\t\treturn Math.min(...bufferedGroups);\n\t}\n\tconst foundIndex = currentGroups.findIndex(\n\t\t(group) => group.startTime >= time,\n\t);\n\treturn foundIndex === -1 ? currentGroups.length : foundIndex;\n}\n\n/**\n * {@link commitPlayerTimeState} 的参数类型。\n *\n * 用于将一次时间线状态转移提交回 {@link PlayerTimelineState},\n * 并生成供宿主执行的副作用应用计划。\n */\nexport interface CommitPlayerTimeStateInput {\n\t/** 要被更新的时间线状态对象 */\n\ttimelineState: PlayerTimelineState;\n\t/** 当前播放时间,单位为毫秒 */\n\ttime: number;\n\t/** 当前用于计算的歌词数据 */\n\tcurrentGroups: LyricLineGroupBase[];\n\t/** 底部附加区域当前是否有可见内容 */\n\thasBottomContent: boolean;\n\t/** 由 {@link computePlayerTimeState} 得到的状态转移结果 */\n\tstateResult: ComputePlayerTimeStateResult;\n}\n\n/** {@link commitPlayerTimeState} 的返回类型 */\nexport interface CommitPlayerTimeStateResult {\n\t/** 提交后是否需要重新布局 */\n\tshouldLayout: boolean;\n\t/** 提交后是否需要重置用户滚动状态 */\n\tshouldResetScroll: boolean;\n\t/** 需要启用的歌词组索引列表 */\n\tgroupsToEnable: number[];\n\t/** 需要禁用的歌词组索引列表 */\n\tgroupsToDisable: number[];\n}\n\n/**\n * 提交时间线状态转移的纯函数。\n *\n * 把一次时间线状态转移写回 {@link PlayerTimelineState},\n * 并返回一份供宿主执行的副作用应用计划,例如启用/禁用哪些歌词行、\n * 是否需要重置用户滚动状态、是否需要触发布局。\n */\nexport function commitPlayerTimeState(\n\tinput: CommitPlayerTimeStateInput,\n): CommitPlayerTimeStateResult {\n\tconst { timelineState, time, currentGroups, hasBottomContent, stateResult } =\n\t\tinput;\n\tconst { addedIds, removedHotIds, removedBufferedIds } = stateResult;\n\tconst { isSeeking } = timelineState;\n\n\ttimelineState.currentTime = time;\n\ttimelineState.hotGroups = stateResult.nextHotGroups;\n\n\tlet shouldLayout = false;\n\tlet shouldResetScroll = false;\n\tconst groupsToEnable: number[] = [];\n\tconst groupsToDisable = new Set<number>();\n\n\tif (isSeeking) {\n\t\ttimelineState.bufferedGroups = new Set([...timelineState.hotGroups]);\n\t\ttimelineState.scrollToIndex = pickScrollToIndexForSeek(\n\t\t\ttime,\n\t\t\tcurrentGroups,\n\t\t\ttimelineState.bufferedGroups,\n\t\t);\n\t\tfor (const id of removedHotIds) groupsToDisable.add(id);\n\t\tfor (const id of timelineState.hotGroups) groupsToEnable.push(id);\n\t\tfor (const id of removedBufferedIds) groupsToDisable.add(id);\n\n\t\tshouldResetScroll = true;\n\t\tshouldLayout = true;\n\t} else if (addedIds.size > 0) {\n\t\tfor (const id of addedIds) {\n\t\t\ttimelineState.bufferedGroups.add(id);\n\t\t\tgroupsToEnable.push(id);\n\t\t}\n\t\tfor (const id of removedBufferedIds) {\n\t\t\ttimelineState.bufferedGroups.delete(id);\n\t\t\tgroupsToDisable.add(id);\n\t\t}\n\t\tif (timelineState.bufferedGroups.size > 0) {\n\t\t\ttimelineState.scrollToIndex = Math.min(...timelineState.bufferedGroups);\n\t\t}\n\t\tshouldLayout = true;\n\t} else if (\n\t\tremovedBufferedIds.size > 0 &&\n\t\teqSet(removedBufferedIds, timelineState.bufferedGroups)\n\t) {\n\t\tfor (const id of timelineState.bufferedGroups) {\n\t\t\tif (timelineState.hotGroups.has(id)) continue;\n\t\t\ttimelineState.bufferedGroups.delete(id);\n\t\t\tgroupsToDisable.add(id);\n\t\t}\n\t\tshouldLayout = true;\n\t}\n\n\tif (timelineState.bufferedGroups.size === 0 && currentGroups.length > 0) {\n\t\tconst lastGroup = currentGroups[currentGroups.length - 1];\n\t\tif (time >= lastGroup.endTime) {\n\t\t\tconst targetIndex = hasBottomContent\n\t\t\t\t? currentGroups.length\n\t\t\t\t: currentGroups.length - 1;\n\t\t\tif (timelineState.scrollToIndex !== targetIndex) {\n\t\t\t\ttimelineState.scrollToIndex = targetIndex;\n\t\t\t\tshouldLayout = true;\n\t\t\t}\n\t\t}\n\t}\n\n\ttimelineState.lastCurrentTime = time;\n\n\treturn {\n\t\tshouldLayout,\n\t\tshouldResetScroll,\n\t\tgroupsToEnable,\n\t\tgroupsToDisable: [...groupsToDisable],\n\t};\n}\n","import structuredClone from \"@ungap/structured-clone\";\nimport type {\n\tDisposable,\n\tHasElement,\n\tLyricLine,\n\tLyricWord,\n\tOptimizeLyricOptions,\n} from \"#interfaces\";\nimport styles from \"#styles/lyric-player.module.css\";\nimport { clampPositive } from \"#utils/clamp.ts\";\nimport { optimizeLyricLines } from \"#utils/optimize-lyric.ts\";\nimport type { SpringParams } from \"#utils/spring.ts\";\nimport { InterludeDots } from \"../dom/interlude-dots.ts\";\nimport { BottomLineEl } from \"./bottom-line.ts\";\nimport { LayoutAlignAnchor, MaskObsceneWordsMode } from \"./consts.ts\";\nimport type { LyricLineGroupBase } from \"./group.ts\";\nimport {\n\tcomputeCurrentInterlude,\n\tcomputeGroupPresentation,\n\tcomputeLineBlur,\n\tcomputeLinePosYSpringParams,\n\ttype PlayerLayoutState,\n} from \"./layout.ts\";\nimport type { LyricLineBase } from \"./line.ts\";\nimport {\n\tattachPlayerScrollHandlers,\n\ttype PlayerScrollState,\n\tresetPlayerScrollState,\n} from \"./scroll.ts\";\nimport {\n\tcommitPlayerTimeState,\n\tcomputePlayerTimeState,\n\ttype PlayerTimelineState,\n} from \"./timeline.ts\";\n\nexport type { PlayerLayoutState } from \"./layout.ts\";\nexport type { LyricLineBase } from \"./line.ts\";\nexport type { PlayerScrollState } from \"./scroll.ts\";\nexport type { PlayerTimelineState } from \"./timeline.ts\";\n\n/**\n * 歌词播放器的基类,已经包含了有关歌词操作和排版的功能,\n * 子类需要为其实现对应的显示展示操作\n */\nexport abstract class LyricPlayerBase\n\textends EventTarget\n\timplements HasElement, Disposable\n{\n\tprotected element: HTMLElement = document.createElement(\"div\");\n\tabstract get baseFontSize(): number;\n\n\t/** 播放时间线状态 */\n\tprotected timelineState: PlayerTimelineState = {\n\t\tcurrentTime: 0,\n\t\tlastCurrentTime: 0,\n\t\thotGroups: new Set(),\n\t\tbufferedGroups: new Set(),\n\t\tscrollToIndex: 0,\n\t\tisSeeking: false,\n\t\tisPlaying: true,\n\t\tinitialLayoutFinished: false,\n\t};\n\t/** @internal */\n\tlyricGroupElementMap: WeakMap<Element, LyricLineGroupBase> = new WeakMap();\n\tprotected currentLyricLines: LyricLine[] = [];\n\tprotected processedLines: LyricLine[] = [];\n\tprotected lyricLinesIndexes: WeakMap<LyricLineBase, number> = new WeakMap();\n\tprotected isNonDynamic = false;\n\tprotected hasDuetLine = false;\n\tprotected disableSpring = false;\n\tprotected layoutState: PlayerLayoutState = {\n\t\tinterludeDotsSize: [0, 0],\n\t\ttargetAlignIndex: 0,\n\t\tlastInterludeState: false,\n\t\talignAnchor: LayoutAlignAnchor.Center,\n\t\talignPosition: 0.35,\n\t\toverscanPx: 300,\n\t};\n\tprotected interludeDots: InterludeDots = new InterludeDots();\n\tprotected bottomLine: BottomLineEl = new BottomLineEl(this);\n\tprotected enableBlur = true;\n\tprotected enableScale = true;\n\tprotected maskObsceneWords: MaskObsceneWordsMode =\n\t\tMaskObsceneWordsMode.Disabled;\n\tprotected maskObsceneWordChar = \"*\";\n\tprotected hidePassedLines = false;\n\tprotected scrollState: PlayerScrollState = {\n\t\tscrollBoundary: { minOffset: 0, maxOffset: 0 },\n\t\tscrollOffset: 0,\n\t\tallowScroll: true,\n\t\tisScrolled: false,\n\t\tisUserScrolling: false,\n\t};\n\tpublic currentLyricGroups: LyricLineGroupBase[] = [];\n\tlyricGroupSize: WeakMap<LyricLineGroupBase, [number, number]> = new WeakMap();\n\treadonly size: [number, number] = [0, 0];\n\tprotected isPageVisible = true;\n\tprotected optimizeOptions: OptimizeLyricOptions = {};\n\n\t/** 是否强制让背景人声行始终后置(即始终在主歌词下方显示,不前置背景人声) */\n\tprotected alwaysPostpositionBackground = false;\n\n\tprotected posXSpringParams: Partial<SpringParams> = {\n\t\tmass: 1,\n\t\tdamping: 10,\n\t\tstiffness: 100,\n\t};\n\tprotected posYSpringParams: Partial<SpringParams> = {\n\t\tmass: 0.9,\n\t\tdamping: 15,\n\t\tstiffness: 90,\n\t};\n\tprotected scaleSpringParams: Partial<SpringParams> = {\n\t\tmass: 2,\n\t\tdamping: 25,\n\t\tstiffness: 100,\n\t};\n\tprotected scaleForBGSpringParams: Partial<SpringParams> = {\n\t\tmass: 1,\n\t\tdamping: 20,\n\t\tstiffness: 50,\n\t};\n\tprivate onPageShow = () => {\n\t\tthis.isPageVisible = true;\n\t\tthis.setCurrentTime(this.timelineState.currentTime, true);\n\t};\n\tprivate onPageHide = () => {\n\t\tthis.isPageVisible = false;\n\t};\n\tprivate scrolledHandler: ReturnType<typeof setTimeout> | undefined;\n\t/** @internal */\n\tresizeObserver: ResizeObserver = new ResizeObserver(((entries) => {\n\t\tlet shouldRelayout = false;\n\t\tlet shouldRebuildPlayerStyle = false;\n\t\tfor (const entry of entries) {\n\t\t\tif (entry.target === this.element) {\n\t\t\t\tconst rect = entry.contentRect;\n\t\t\t\tthis.size[0] = rect.width;\n\t\t\t\tthis.size[1] = rect.height;\n\t\t\t\tshouldRebuildPlayerStyle = true;\n\t\t\t} else if (entry.target === this.interludeDots.getElement()) {\n\t\t\t\tthis.layoutState.interludeDotsSize[0] = entry.target.clientWidth;\n\t\t\t\tthis.layoutState.interludeDotsSize[1] = entry.target.clientHeight;\n\t\t\t\tshouldRelayout = true;\n\t\t\t} else if (entry.target === this.bottomLine.getElement()) {\n\t\t\t\tconst newSize: [number, number] = [\n\t\t\t\t\tentry.target.clientWidth,\n\t\t\t\t\tentry.target.clientHeight,\n\t\t\t\t];\n\t\t\t\tconst oldSize: [number, number] = this.bottomLine.lineSize;\n\n\t\t\t\tif (newSize[0] !== oldSize[0] || newSize[1] !== oldSize[1]) {\n\t\t\t\t\tthis.bottomLine.lineSize = newSize;\n\t\t\t\t\tshouldRelayout = true;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tconst groupObj = this.lyricGroupElementMap.get(entry.target);\n\t\t\t\tif (groupObj) {\n\t\t\t\t\tconst newSize: [number, number] = [\n\t\t\t\t\t\tentry.target.clientWidth,\n\t\t\t\t\t\tentry.target.clientHeight,\n\t\t\t\t\t];\n\n\t\t\t\t\tconst oldSize: [number, number] = this.lyricGroupSize.get(\n\t\t\t\t\t\tgroupObj,\n\t\t\t\t\t) ?? [0, 0];\n\n\t\t\t\t\tif (newSize[0] !== oldSize[0] || newSize[1] !== oldSize[1]) {\n\t\t\t\t\t\tthis.lyricGroupSize.set(groupObj, newSize);\n\t\t\t\t\t\tgroupObj.onLineSizeChange(newSize);\n\t\t\t\t\t\tshouldRelayout = true;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tif (shouldRelayout) {\n\t\t\tthis.calcLayout(true);\n\t\t}\n\t\tif (shouldRebuildPlayerStyle) {\n\t\t\tthis.onResize();\n\t\t}\n\t}) as ResizeObserverCallback);\n\tprotected wordFadeWidth = 0.5;\n\n\tconstructor(element?: HTMLElement) {\n\t\tsuper();\n\t\tif (element) this.element = element;\n\t\tthis.element.classList.add(\"amll-lyric-player\");\n\n\t\tthis.resizeObserver.observe(this.element);\n\t\tthis.resizeObserver.observe(this.interludeDots.getElement());\n\n\t\tthis.element.appendChild(this.interludeDots.getElement());\n\t\tthis.element.appendChild(this.bottomLine.getElement());\n\t\tthis.interludeDots.setTransform(0, 200);\n\n\t\twindow.addEventListener(\"pageshow\", this.onPageShow);\n\t\twindow.addEventListener(\"pagehide\", this.onPageHide);\n\t\tattachPlayerScrollHandlers(this.element, this.scrollState, {\n\t\t\tonBeginScroll: () => this.beginScrollHandler(),\n\t\t\tonEndScroll: () => this.endScrollHandler(),\n\t\t\tonLayout: (sync, force) => this.calcLayout(sync, force),\n\t\t\tcontainsTarget: (target) => this.element.contains(target),\n\t\t\tclickTarget: (target) => target.click(),\n\t\t});\n\t}\n\n\tprivate beginScrollHandler() {\n\t\tconst allowed = this.scrollState.allowScroll;\n\t\tif (allowed) {\n\t\t\tthis.scrollState.isScrolled = true;\n\t\t\tclearTimeout(this.scrolledHandler);\n\t\t\tthis.scrolledHandler = setTimeout(() => {\n\t\t\t\tthis.scrollState.isScrolled = false;\n\t\t\t\tthis.scrollState.scrollOffset = 0;\n\t\t\t}, 5000);\n\t\t}\n\t\treturn allowed;\n\t}\n\tprivate endScrollHandler() {}\n\n\t/**\n\t * 设置文字动画的渐变宽度,单位以歌词行的主文字字体大小的倍数为单位,默认为 0.5,即一个全角字符的一半宽度\n\t *\n\t * 如果要模拟 Apple Music for Android 的效果,可以设置为 1\n\t *\n\t * 如果要模拟 Apple Music for iPad 的效果,可以设置为 0.5\n\t *\n\t * 如果想要近乎禁用渐变效果,可以设置成非常接近 0 的小数(例如 `0.0001` ),但是**不可以为 0**\n\t *\n\t * @param value 需要设置的渐变宽度,单位以歌词行的主文字字体大小的倍数为单位,默认为 0.5\n\t */\n\tsetWordFadeWidth(value = 0.5): void {\n\t\tthis.wordFadeWidth = Math.max(0.0001, value);\n\t}\n\n\t/**\n\t * 是否启用歌词行缩放效果,默认启用\n\t *\n\t * 如果启用,非选中的歌词行会轻微缩小以凸显当前播放歌词行效果\n\t *\n\t * 此效果对性能影响微乎其微,推荐启用\n\t * @param enable 是否启用歌词行缩放效果\n\t */\n\tsetEnableScale(enable = true): void {\n\t\tthis.enableScale = enable;\n\t\tthis.calcLayout();\n\t}\n\t/**\n\t * 获取当前是否启用了歌词行缩放效果\n\t * @returns 是否启用歌词行缩放效果\n\t */\n\tgetEnableScale(): boolean {\n\t\treturn this.enableScale;\n\t}\n\n\t/**\n\t * 获取当前文字动画的渐变宽度,单位以歌词行的主文字字体大小的倍数为单位\n\t * @returns 当前文字动画的渐变宽度,单位以歌词行的主文字字体大小的倍数为单位\n\t */\n\tgetWordFadeWidth(): number {\n\t\treturn this.wordFadeWidth;\n\t}\n\n\tsetIsSeeking(isSeeking: boolean): void {\n\t\tthis.timelineState.isSeeking = isSeeking;\n\t}\n\t/**\n\t * 设置是否隐藏已经播放过的歌词行,默认不隐藏\n\t * @param hide 是否隐藏已经播放过的歌词行,默认不隐藏\n\t */\n\tsetHidePassedLines(hide: boolean): void {\n\t\tthis.hidePassedLines = hide;\n\t\tthis.calcLayout();\n\t}\n\t/**\n\t * 设置是否启用歌词行的模糊效果\n\t * @param enable 是否启用\n\t */\n\tsetEnableBlur(enable: boolean): void {\n\t\tif (this.enableBlur === enable) return;\n\t\tthis.enableBlur = enable;\n\t\tthis.calcLayout();\n\t}\n\n\t/**\n\t * 设置歌词中不雅用语的掩码模式\n\t * @param mode 掩码模式\n\t * @see {@link MaskObsceneWordsMode}\n\t */\n\tsetMaskObsceneWords(mode: MaskObsceneWordsMode): void {\n\t\tif (this.maskObsceneWords === mode) return;\n\t\tthis.maskObsceneWords = mode;\n\t\tthis.rebuildLyricLines();\n\t\tthis.calcLayout();\n\t}\n\n\t/**\n\t * 设置不雅用语掩码使用的字符,默认为 `*`\n\t * @param char 单个字符,用于替换不雅用语中的字符\n\t */\n\tsetMaskObsceneWordChar(char: string): void {\n\t\tconst c = char.charAt(0) || \"*\";\n\t\tif (this.maskObsceneWordChar === c) return;\n\t\tthis.maskObsceneWordChar = c;\n\t\tif (this.maskObsceneWords !== MaskObsceneWordsMode.Disabled) {\n\t\t\tthis.rebuildLyricLines();\n\t\t\tthis.calcLayout();\n\t\t}\n\t}\n\n\trebuildLyricLines(): void {\n\t\tfor (const group of this.currentLyricGroups) {\n\t\t\tgroup.rebuildAllLines();\n\t\t}\n\t}\n\t/**\n\t * 根据当前配置处理不雅用语单词\n\t * @param word 单词对象\n\t * @internal\n\t */\n\tprocessObsceneWord(word: LyricWord): string {\n\t\tconst text = word.word;\n\n\t\tif (\n\t\t\t!word.obscene ||\n\t\t\tthis.maskObsceneWords === MaskObsceneWordsMode.Disabled\n\t\t) {\n\t\t\treturn text;\n\t\t}\n\n\t\tconst maskChar = this.maskObsceneWordChar;\n\n\t\tif (this.maskObsceneWords === MaskObsceneWordsMode.FullMask) {\n\t\t\treturn text.replace(/\\S/g, maskChar);\n\t\t}\n\n\t\tif (this.maskObsceneWords === MaskObsceneWordsMode.PartialMask) {\n\t\t\tconst trimmed = text.trim();\n\n\t\t\tif (trimmed.length <= 2) {\n\t\t\t\treturn text.replace(/\\S/g, maskChar);\n\t\t\t}\n\n\t\t\tconst startPos = text.indexOf(trimmed);\n\t\t\tconst endPos = startPos + trimmed.length - 1;\n\n\t\t\treturn (\n\t\t\t\ttext.slice(0, startPos + 1) +\n\t\t\t\ttext.slice(startPos + 1, endPos).replace(/\\S/g, maskChar) +\n\t\t\t\ttext.slice(endPos)\n\t\t\t);\n\t\t}\n\n\t\treturn text;\n\t}\n\t/**\n\t * 设置目标歌词行的对齐方式,默认为 `center`\n\t *\n\t * - 设置成 `top` 的话将会向目标歌词行的顶部对齐\n\t * - 设置成 `bottom` 的话将会向目标歌词行的底部对齐\n\t * - 设置成 `center` 的话将会向目标歌词行的垂直中心对齐\n\t * @param alignAnchor 歌词行对齐方式,详情见函数说明\n\t */\n\tsetAlignAnchor(alignAnchor: LayoutAlignAnchor): void {\n\t\tthis.layoutState.alignAnchor = alignAnchor;\n\t}\n\t/**\n\t * 设置默认的歌词行对齐位置,相对于整个歌词播放组件的大小位置,默认为 `0.5`\n\t * @param alignPosition 一个 `[0.0-1.0]` 之间的任意数字,代表组件高度由上到下的比例位置\n\t */\n\tsetAlignPosition(alignPosition: number): void {\n\t\tthis.layoutState.alignPosition = alignPosition;\n\t}\n\n\t/**\n\t * 设置 overscan(视图上下额外缓冲渲染区)距离,单位:像素。\n\t * @param px 像素值,默认 300\n\t */\n\tsetOverscanPx(px: number): void {\n\t\tthis.layoutState.overscanPx = clampPositive(px | 0);\n\t}\n\t/** 获取当前 overscan 像素距离 */\n\tgetOverscanPx(): number {\n\t\treturn this.layoutState.overscanPx;\n\t}\n\t/**\n\t * 设置是否使用物理弹簧算法实现歌词动画效果,默认启用\n\t *\n\t * 如果启用,则会通过弹簧算法实时处理歌词位置,但是需要性能足够强劲的电脑方可流畅运行\n\t *\n\t * 如果不启用,则会回退到基于 `transition` 的过渡效果,对低性能的机器比较友好,但是效果会比较单一\n\t */\n\tsetEnableSpring(enable = true): void {\n\t\tthis.disableSpring = !enable;\n\t\tif (enable) {\n\t\t\tthis.element.classList.remove(styles.disableSpring);\n\t\t} else {\n\t\t\tthis.element.classList.add(styles.disableSpring);\n\t\t}\n\t\tthis.calcLayout(true);\n\t}\n\t/**\n\t * 获取当前是否启用了物理弹簧\n\t * @returns 是否启用物理弹簧\n\t */\n\tgetEnableSpring(): boolean {\n\t\treturn !this.disableSpring;\n\t}\n\n\t/**\n\t * 设置歌词的优化配置项,这些配置项默认全部开启\n\t *\n\t * 注意,如果在 `setLyricLines` 之后修改此配置,需要重新调用 `setLyricLines()` 才能对当前歌词生效\n\t * @param options 优化配置选项\n\t * @see {@link OptimizeLyricOptions}\n\t */\n\tsetOptimizeOptions(options: OptimizeLyricOptions): void {\n\t\tthis.optimizeOptions = { ...this.optimizeOptions, ...options };\n\t}\n\n\t/**\n\t * 设置当前播放歌词,要注意传入后这个数组内的信息不得修改,否则会发生错误\n\t * @param lines 歌词数组\n\t * @param initialTime 初始时间,默认为 0\n\t */\n\tsetLyricLines(lines: LyricLine[], initialTime = 0): void {\n\t\tif (import.meta.env.DEV) {\n\t\t\tconsole.log(\"设置歌词行\", lines, initialTime);\n\t\t}\n\n\t\tthis.timelineState.initialLayoutFinished = true;\n\t\tthis.timelineState.lastCurrentTime = initialTime;\n\t\tthis.timelineState.currentTime = initialTime;\n\n\t\tthis.currentLyricLines = structuredClone(lines);\n\t\tthis.processedLines = structuredClone(this.currentLyricLines);\n\t\toptimizeLyricLines(this.processedLines, this.optimizeOptions);\n\n\t\tthis.isNonDynamic = true;\n\t\tfor (const line of this.processedLines) {\n\t\t\tif (line.words.length > 1) {\n\t\t\t\tthis.isNonDynamic = false;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\tthis.hasDuetLine = this.processedLines.some((line) => line.isDuet);\n\n\t\tfor (const group of this.currentLyricGroups) {\n\t\t\tgroup.dispose();\n\t\t}\n\t\tthis.currentLyricGroups = [];\n\n\t\tthis.interludeDots.setInterlude(undefined);\n\t\tthis.timelineState.hotGroups.clear();\n\t\tthis.timelineState.bufferedGroups.clear();\n\n\t\tif (import.meta.env.DEV) {\n\t\t\tconsole.log(\"歌词处理完成\", this);\n\t\t}\n\t}\n\n\t/**\n\t * 获取当前是否在播放\n\t * @returns 当前是否在播放\n\t */\n\tpublic getIsPlaying(): boolean {\n\t\treturn this.timelineState.isPlaying;\n\t}\n\n\t/**\n\t * 设置当前播放进度,此时将会更新内部的歌词进度信息。\n\t *\n\t * 内部会根据调用间隔和播放进度自动决定如何滚动和显示歌词,所以这个的调用频率越快越准确越好。\n\t * 调用完成后,应每帧调用 {@link update} 方法来执行歌词动画效果。**此函数本身不会触发动画效果**。\n\t *\n\t * @param time 当前播放进度,单位为毫秒\n\t */\n\tsetCurrentTime(time: number, isSeek = false): void {\n\t\t// 歌词行为如下:\n\t\t// 如果当前仍有缓冲行的情况下加入新热行,则不会解除当前缓冲行,且也不会修改当前滚动位置\n\t\t// 如果当前所有缓冲行都将被删除且没有新热行加入,则删除所有缓冲行,且也不会修改当前滚动位置\n\t\t// 如果当前所有缓冲行都将被删除且有新热行加入,则删除所有缓冲行并加入新热行作为缓冲行,然后修改当前滚动位置\n\n\t\ttime = Math.round(time);\n\n\t\tconst { timelineState } = this;\n\t\ttimelineState.isSeeking = Boolean(isSeek);\n\t\ttimelineState.currentTime = time;\n\n\t\tif (!timelineState.initialLayoutFinished && !timelineState.isSeeking)\n\t\t\treturn;\n\n\t\tconst stateResult = computePlayerTimeState({\n\t\t\ttime,\n\t\t\tcurrentGroups: this.currentLyricGroups,\n\t\t\ttimelineState,\n\t\t});\n\n\t\tconst bottomEl = this.bottomLine.getElement();\n\t\tconst hasBottomContent = bottomEl.innerHTML.trim().length > 0;\n\t\tconst commitResult = commitPlayerTimeState({\n\t\t\ttimelineState: timelineState,\n\t\t\ttime,\n\t\t\tcurrentGroups: this.currentLyricGroups,\n\t\t\thasBottomContent,\n\t\t\tstateResult,\n\t\t});\n\n\t\tfor (const id of commitResult.groupsToDisable)\n\t\t\tthis.currentLyricGroups[id]?.disable();\n\n\t\tfor (const id of commitResult.groupsToEnable)\n\t\t\tthis.currentLyricGroups[id]?.enable();\n\n\t\tif (commitResult.shouldResetScroll) this.resetScroll();\n\t\tif (commitResult.shouldLayout) this.calcLayout();\n\t}\n\n\t/**\n\t * 重新布局定位歌词行的位置,调用完成后再逐帧调用 `update`\n\t * 函数即可让歌词通过动画移动到目标位置。\n\t *\n\t * 函数有一个 `force` 参数,用于指定是否强制修改布局,也就是不经过动画直接调整元素位置和大小。\n\t *\n\t * 此函数还有一个 `reflow` 参数,用于指定是否需要重新计算布局\n\t *\n\t * 因为计算布局必定会导致浏览器重排布局,所以会大幅度影响流畅度和性能,故请只在以下情况下将其​设置为 true:\n\t *\n\t * 1. 歌词页面大小发生改变时(这个组件会自行处理)\n\t * 2. 加载了新的歌词时(不论前后歌词是否完全一样)\n\t * 3. 用户自行跳转了歌曲播放位置(不论距离远近)\n\t *\n\t * @param sync 是否同步执行,通常用于初始化或 Resize 时立即布局\n\t * @param force 是否绕过弹簧效果强制更新位置\n\t */\n\tasync calcLayout(sync = false, force = false): Promise<void> {\n\t\tconst interlude = computeCurrentInterlude({\n\t\t\tcurrentTime: this.timelineState.currentTime,\n\t\t\tscrollToIndex: this.timelineState.scrollToIndex,\n\t\t\tcurrentGroups: this.currentLyricGroups,\n\t\t});\n\t\tconst isInterludeActive = !!interlude;\n\n\t\tif (\n\t\t\tthis.layoutState.targetAlignIndex !== this.timelineState.scrollToIndex ||\n\t\t\tthis.layoutState.lastInterludeState !== isInterludeActive\n\t\t) {\n\t\t\tthis.layoutState.lastInterludeState = isInterludeActive;\n\n\t\t\tconst springParams = computeLinePosYSpringParams({\n\t\t\t\tenabled: this.getEnableSpring(),\n\t\t\t\tcurrentGroups: this.currentLyricGroups,\n\t\t\t\tscrollToIndex: this.timelineState.scrollToIndex,\n\t\t\t\tisSeeking: this.timelineState.isSeeking,\n\t\t\t\tisInterludeActive,\n\t\t\t});\n\t\t\tif (springParams.shouldUpdate && springParams.params) {\n\t\t\t\tthis.setLinePosYSpringParams(springParams.params);\n\t\t\t}\n\t\t}\n\n\t\tlet curPos = -this.scrollState.scrollOffset;\n\t\tconst targetAlignIndex = this.timelineState.scrollToIndex;\n\t\tlet isNextDuet = false;\n\t\tif (interlude) {\n\t\t\tisNextDuet = interlude.isNextDuet;\n\t\t} else {\n\t\t\tthis.interludeDots.setInterlude(undefined);\n\t\t}\n\n\t\tconst fontSize = this.baseFontSize || 24;\n\t\tconst dotMargin = fontSize * 0.4;\n\t\tconst totalInterludeHeight =\n\t\t\tthis.layoutState.interludeDotsSize[1] + dotMargin * 2;\n\n\t\tif (interlude) {\n\t\t\tif (interlude.anchorLineIndex !== -1) {\n\t\t\t\tcurPos -= totalInterludeHeight;\n\t\t\t}\n\t\t}\n\t\t// 避免一开始就让所有歌词行挤在一起\n\t\tconst LINE_HEIGHT_FALLBACK = this.size[1] / 5;\n\t\tconst scrollOffset = this.currentLyricGroups\n\t\t\t.slice(0, targetAlignIndex)\n\t\t\t.reduce(\n\t\t\t\t(acc, group) =>\n\t\t\t\t\tacc + (this.lyricGroupSize.get(group)?.[1] ?? LINE_HEIGHT_FALLBACK),\n\t\t\t\t0,\n\t\t\t);\n\n\t\tthis.scrollState.scrollBoundary.minOffset = -scrollOffset;\n\t\tcurPos -= scrollOffset;\n\t\tcurPos += this.size[1] * this.layoutState.alignPosition;\n\n\t\tconst curGroup = this.currentLyricGroups[targetAlignIndex];\n\t\tthis.layoutState.targetAlignIndex = targetAlignIndex;\n\n\t\tconst isBottomFocused = targetAlignIndex === this.currentLyricGroups.length;\n\t\tthis.bottomLine.setFocused(isBottomFocused);\n\n\t\tconst targetLineHeight = curGroup\n\t\t\t? (this.lyricGroupSize.get(curGroup)?.[1] ?? LINE_HEIGHT_FALLBACK)\n\t\t\t: isBottomFocused\n\t\t\t\t? this.bottomLine.lineSize[1]\n\t\t\t\t: 0;\n\n\t\tif (targetLineHeight > 0) {\n\t\t\tswitch (this.layoutState.alignAnchor) {\n\t\t\t\tcase LayoutAlignAnchor.Bottom:\n\t\t\t\t\tcurPos -= targetLineHeight;\n\t\t\t\t\tbreak;\n\t\t\t\tcase LayoutAlignAnchor.Center:\n\t\t\t\t\tcurPos -= targetLineHeight / 2;\n\t\t\t\t\tbreak;\n\t\t\t\tcase LayoutAlignAnchor.Top:\n\t\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\tconst latestIndex = Math.max(...this.timelineState.bufferedGroups);\n\t\tlet delay = 0;\n\t\tlet baseDelay = sync ? 0 : 0.05;\n\t\tlet setDots = false;\n\n\t\tthis.currentLyricGroups.forEach((group, i) => {\n\t\t\tconst hasBuffered = this.timelineState.bufferedGroups.has(i);\n\n\t\t\tconst shouldShowDots = interlude && i === interlude.anchorLineIndex + 1;\n\n\t\t\tif (!setDots && shouldShowDots) {\n\t\t\t\tsetDots = true;\n\n\t\t\t\tcurPos += dotMargin;\n\n\t\t\t\tlet targetX = 0;\n\t\t\t\tif (interlude && isNextDuet) {\n\t\t\t\t\ttargetX = this.size[0] - this.layoutState.interludeDotsSize[0];\n\t\t\t\t}\n\n\t\t\t\tthis.interludeDots.setTransform(targetX, curPos);\n\n\t\t\t\tif (interlude) {\n\t\t\t\t\tthis.interludeDots.setInterlude([\n\t\t\t\t\t\tinterlude.startTime,\n\t\t\t\t\t\tinterlude.endTime,\n\t\t\t\t\t]);\n\t\t\t\t}\n\t\t\t\tcurPos += this.layoutState.interludeDotsSize[1];\n\t\t\t\tcurPos += dotMargin;\n\t\t\t}\n\n\t\t\tconst presentation = computeGroupPresentation({\n\t\t\t\tgroupIndex: i,\n\t\t\t\tscrollToIndex: this.timelineState.scrollToIndex,\n\t\t\t\tlatestIndex,\n\t\t\t\thasBuffered,\n\t\t\t\thidePassedLines: this.hidePassedLines,\n\t\t\t\tisPlaying: this.timelineState.isPlaying,\n\t\t\t\tisNonDynamic: this.isNonDynamic,\n\t\t\t\tenableBlur: this.enableBlur,\n\t\t\t\tisUserScrolling: this.scrollState.isUserScrolling,\n\t\t\t\tisCompact: window.innerWidth <= 1024,\n\t\t\t\tinterlude,\n\t\t\t});\n\n\t\t\tgroup.setTransform(\n\t\t\t\tcurPos,\n\t\t\t\tforce,\n\t\t\t\tdelay,\n\t\t\t\tpresentation.isActive,\n\t\t\t\tpresentation.targetOpacity,\n\t\t\t\tpresentation.blurLevel,\n\t\t\t);\n\n\t\t\tcurPos += this.lyricGroupSize.get(group)?.[1] ?? LINE_HEIGHT_FALLBACK;\n\n\t\t\tif (curPos >= 0 && !this.timelineState.isSeeking) {\n\t\t\t\tdelay += baseDelay;\n\t\t\t\tif (i >= this.timelineState.scrollToIndex) baseDelay /= 1.05;\n\t\t\t}\n\t\t});\n\t\tthis.scrollState.scrollBoundary.maxOffset =\n\t\t\tcurPos + this.scrollState.scrollOffset - this.size[1] / 2;\n\n\t\tconst bottomIndex = this.currentLyricGroups.length;\n\t\tconst finalBottomBlur = computeLineBlur({\n\t\t\tenableBlur: this.enableBlur,\n\t\t\tisUserScrolling: this.scrollState.isUserScrolling,\n\t\t\tisActive: isBottomFocused,\n\t\t\titemIndex: bottomIndex,\n\t\t\tscrollToIndex: this.timelineState.scrollToIndex,\n\t\t\tlatestIndex,\n\t\t\tisCompact: window.innerWidth <= 1024,\n\t\t});\n\n\t\tthis.bottomLine.setTransform(0, curPos, finalBottomBlur, force, delay);\n\t}\n\n\t/**\n\t * 设置所有歌词行在横坐标上的弹簧属性,包括重量、弹力和阻力。\n\t *\n\t * @param params 需要设置的弹簧属性,提供的属性将会覆盖原来的属性,未提供的属性将会保持原样\n\t * @deprecated 考虑到横向弹簧效果并不常见,所以这个函数将会在未来的版本中移除\n\t */\n\tsetLinePosXSpringParams(_params: Partial<SpringParams> = {}): void {}\n\t/**\n\t * 设置所有歌词行在​纵坐标上的弹簧属性,包括重量、弹力和阻力。\n\t *\n\t * @param params 需要设置的弹簧属性,提供的属性将会覆盖原来的属性,未提供的属性将会保持原样\n\t */\n\tsetLinePosYSpringParams(params: Partial<SpringParams> = {}): void {\n\t\tthis.posYSpringParams = {\n\t\t\t...this.posYSpringParams,\n\t\t\t...params,\n\t\t};\n\t\tthis.bottomLine.lineTransforms.posY.updateParams(this.posYSpringParams);\n\t\tfor (const group of this.currentLyricGroups) {\n\t\t\tgroup.posY.updateParams(this.posYSpringParams);\n\t\t\tgroup.bgSlideY.updateParams(this.posYSpringParams);\n\t\t}\n\t}\n\t/**\n\t * 设置所有歌词行在​缩放大小上的弹簧属性,包括重量、弹力和阻力。\n\t *\n\t * @param params 需要设置的弹簧属性,提供的属性将会覆盖原来的属性,未提供的属性将会保持原样\n\t */\n\tsetLineScaleSpringParams(params: Partial<SpringParams> = {}): void {\n\t\tthis.scaleSpringParams = {\n\t\t\t...this.scaleSpringParams,\n\t\t\t...params,\n\t\t};\n\t\tthis.scaleForBGSpringParams = {\n\t\t\t...this.scaleForBGSpringParams,\n\t\t\t...params,\n\t\t};\n\t\tfor (const group of this.currentLyricGroups) {\n\t\t\tgroup.mainLine.lineTransforms.scale.updateParams(this.scaleSpringParams);\n\n\t\t\tgroup.bgLine?.lineTransforms.scale.updateParams(\n\t\t\t\tthis.scaleForBGSpringParams,\n\t\t\t);\n\t\t}\n\t}\n\t/**\n\t * 暂停部分效果演出,目前会暂停播放间奏点的动画,且将背景歌词显示出来\n\t */\n\tpause(): void {\n\t\tthis.interludeDots.pause();\n\t\tif (this.timelineState.isPlaying) {\n\t\t\tthis.timelineState.isPlaying = false;\n\t\t\tthis.calcLayout();\n\t\t}\n\t}\n\t/**\n\t * 恢复部分效果演出,目前会恢复播放间奏点的动画\n\t */\n\tresume(): void {\n\t\tthis.interludeDots.resume();\n\t\tif (!this.timelineState.isPlaying) {\n\t\t\tthis.timelineState.isPlaying = true;\n\t\t\tthis.calcLayout();\n\t\t}\n\t}\n\t/**\n\t * 更新动画,这个函数应该被逐帧调用或者在以下情况下调用一次:\n\t *\n\t * 1. 刚刚调用完设置歌词函数的时候\n\t * @param delta 距离上一次被调用到现在的时长,单位为毫秒(可为浮点数)\n\t */\n\n\tupdate(delta = 0): void {\n\t\tthis.bottomLine.update(delta / 1000);\n\t\tthis.interludeDots.update(delta);\n\t}\n\n\tprotected onResize(): void {}\n\n\t/**\n\t * 获取一个特殊的底栏元素,默认是空白的,可以往内部添加任意元素\n\t *\n\t * 这个元素始终在歌词的底部,可以用于显示歌曲创作者等信息\n\t *\n\t * 但是请勿删除该元素,只能在内部存放元素\n\t *\n\t * @returns 一个元素,可以往内部添加任意元素\n\t */\n\tgetBottomLineElement(): HTMLElement {\n\t\treturn this.bottomLine.getElement();\n\t}\n\t/**\n\t * 重置用户滚动状态\n\t *\n\t * 请在用户完成滚动点击跳转歌词时调用本事件再调用 `calcLayout` 以正确滚动到目标位置\n\t */\n\tresetScroll(): void {\n\t\tresetPlayerScrollState(this.scrollState);\n\t\tclearTimeout(this.scrolledHandler);\n\t}\n\t/**\n\t * 获取当前歌词数组\n\t *\n\t * 一般和最后调用 `setLyricLines` 给予的参数一样\n\t * @returns 当前歌词数组\n\t */\n\tgetLyricLines(): LyricLine[] {\n\t\treturn this.currentLyricLines;\n\t}\n\t/**\n\t * 获取当前歌词的播放位置\n\t *\n\t * 一般和最后调用 `setCurrentTime` 给予的参数一样\n\t * @returns 当前播放位置\n\t */\n\tgetCurrentTime(): number {\n\t\treturn this.timelineState.currentTime;\n\t}\n\n\t/**\n\t * 设置是否让背景人声行始终后置显示\n\t *\n\t * 默认情况下,如果背景歌词开始时间早于主歌词,会在主歌词上方展示;\n\t * 如果设置为 `true`,则无论时间顺序如何,背景歌词都会始终在主歌词下方展示\n\t * @param enable 是否启用始终后置\n\t */\n\tsetAlwaysPostpositionBackground(enable: boolean): void {\n\t\tif (this.alwaysPostpositionBackground === enable) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis.alwaysPostpositionBackground = enable;\n\n\t\tthis.rebuildLyricLines();\n\t\tthis.calcLayout();\n\t}\n\n\t/** 获取当前是否设置了让背景人声行始终后置显示 */\n\tgetAlwaysPostpositionBackground(): boolean {\n\t\treturn this.alwaysPostpositionBackground;\n\t}\n\n\tgetElement(): HTMLElement {\n\t\treturn this.element;\n\t}\n\tdispose(): void {\n\t\tthis.element.remove();\n\t\twindow.removeEventListener(\"pageshow\", this.onPageShow);\n\t\twindow.removeEventListener(\"pagehide\", this.onPageHide);\n\t}\n}\n","import type { Disposable } from \"#interfaces\";\nimport { Spring } from \"#utils/spring.ts\";\nimport { LyricLineRenderMode } from \"./consts.ts\";\nimport type { LyricLineBase } from \"./line.ts\";\n\nexport interface LyricPlayerFlags {\n\tgetEnableSpring(): boolean;\n\tgetEnableScale(): boolean;\n\tgetIsPlaying(): boolean;\n\tgetAlwaysPostpositionBackground(): boolean;\n}\n\nexport abstract class LyricLineGroupBase<\n\tT extends LyricLineBase = LyricLineBase,\n> implements Disposable\n{\n\tprotected abstract readonly lyricPlayer: LyricPlayerFlags;\n\n\tpublic posY: Spring = new Spring(0);\n\tpublic bgSlideY: Spring = new Spring(-80);\n\tpublic top = 0;\n\tpublic delay = 0;\n\n\tpublic isActive = false;\n\tpublic opacity = 1;\n\tpublic blur = 0;\n\n\tpublic isBgFirst = false;\n\n\tconstructor(\n\t\tpublic mainLine: T,\n\t\tpublic bgLine?: T | undefined,\n\t) {}\n\n\tget startTime(): number {\n\t\t// 优化歌词时 `syncMainAndBackgroundLines` 已经把时间同步好了,直接读取主歌词的即可\n\t\t// 要是用户关掉了这个优化,我们认为在这种情况下主歌词和背景人声显示不同步是符合用户预期的\n\t\treturn this.mainLine.getLine().startTime;\n\t}\n\n\tget endTime(): number {\n\t\treturn this.mainLine.getLine().endTime;\n\t}\n\n\tonLineSizeChange(size: [number, number]): void {\n\t\tthis.mainLine.onLineSizeChange(size);\n\t\tthis.bgLine?.onLineSizeChange(size);\n\t}\n\n\tsetTransform(\n\t\ttop: number,\n\t\tforce: boolean,\n\t\tdelay: number,\n\t\tisActive: boolean,\n\t\topacity: number,\n\t\tblur: number,\n\t): void {\n\t\tthis.top = top;\n\t\tthis.delay = delay;\n\t\tthis.isActive = isActive;\n\t\tthis.opacity = opacity;\n\t\tthis.blur = blur;\n\n\t\tthis.setLineTransformations(force, delay);\n\n\t\tconst enableSpring = this.lyricPlayer.getEnableSpring();\n\t\tconst alwaysPostposition =\n\t\t\tthis.lyricPlayer.getAlwaysPostpositionBackground();\n\t\tconst shouldBgFirst = alwaysPostposition ? false : this.isBgFirst;\n\t\tconst hiddenSlideY = shouldBgFirst ? 80 : -80;\n\n\t\tconst isPlaying = this.lyricPlayer.getIsPlaying();\n\n\t\tconst targetBgSlideY = isActive || !isPlaying ? 0 : hiddenSlideY;\n\n\t\tif (force || !enableSpring) {\n\t\t\tthis.posY.setPosition(top);\n\t\t\tthis.bgSlideY.setPosition(targetBgSlideY);\n\t\t\tthis.renderStyles();\n\t\t} else {\n\t\t\tthis.posY.setTargetPosition(top, delay);\n\t\t\tthis.bgSlideY.setTargetPosition(targetBgSlideY, delay);\n\t\t}\n\t}\n\n\tprivate setLineTransformations(force: boolean, delay: number) {\n\t\tconst enableScale = this.lyricPlayer.getEnableScale();\n\t\tconst isPlaying = this.lyricPlayer.getIsPlaying();\n\n\t\tconst renderMode = this.isActive\n\t\t\t? LyricLineRenderMode.GRADIENT\n\t\t\t: LyricLineRenderMode.SOLID;\n\n\t\tconst SCALE_ASPECT = enableScale ? 97 : 100;\n\t\tlet mainScale = 100;\n\t\tif (!this.isActive && isPlaying) {\n\t\t\tmainScale = SCALE_ASPECT;\n\t\t}\n\t\tthis.mainLine.setTransform(mainScale, 1, 0, force, delay, renderMode);\n\n\t\tlet bgScale = 100;\n\t\tif (!this.isActive && isPlaying) {\n\t\t\tbgScale = 75;\n\t\t}\n\t\tthis.bgLine?.setTransform(bgScale, 1, 0, force, delay, renderMode);\n\t}\n\n\tprotected abstract renderStyles(): void;\n\n\tabstract get isInSight(): boolean;\n\n\tupdate(delta: number): void {\n\t\tif (this.lyricPlayer.getEnableSpring()) {\n\t\t\tthis.posY.update(delta);\n\t\t\tthis.bgSlideY.update(delta);\n\t\t\tthis.renderStyles();\n\t\t}\n\n\t\tthis.mainLine.update(delta);\n\t\tthis.bgLine?.update(delta);\n\t}\n\n\trebuildAllLines(): void {\n\t\tthis.mainLine.rebuildElement();\n\t\tthis.bgLine?.rebuildElement();\n\t}\n\n\tenable(time?: number, shouldPlay?: boolean): void {\n\t\tthis.mainLine.enable(time, shouldPlay);\n\t\tthis.bgLine?.enable(time, shouldPlay);\n\t}\n\n\tdisable(): void {\n\t\tthis.mainLine.disable();\n\t\tthis.bgLine?.disable();\n\t}\n\n\tdispose(): void {\n\t\tthis.mainLine.dispose();\n\t\tthis.bgLine?.dispose();\n\t}\n}\n","import { LyricLineGroupBase } from \"#lyric/base/group.ts\";\nimport styles from \"#styles/lyric-player.module.css\";\nimport { clamp01 } from \"#utils/clamp.ts\";\nimport type { DomLyricPlayer } from \"./index.ts\";\nimport type { LyricLineEl } from \"./lyric-line.ts\";\n\nexport class LyricLineGroup extends LyricLineGroupBase<LyricLineEl> {\n\tpublic element: HTMLElement;\n\tpublic bgWrapper?: HTMLElement;\n\tprivate lastIsActive?: boolean;\n\n\tconstructor(\n\t\tpublic lyricPlayer: DomLyricPlayer,\n\t\tmainLine: LyricLineEl,\n\t) {\n\t\tsuper(mainLine);\n\t\tthis.element = document.createElement(\"div\");\n\t\tthis.element.className = styles.lyricLineWrapper;\n\t\tthis.element.appendChild(mainLine.getElement());\n\t\tthis.posY.setPosition(window.innerHeight * 2);\n\n\t\tlyricPlayer.resizeObserver.observe(this.element);\n\t}\n\n\tget isInSight(): boolean {\n\t\tconst t = this.posY.getCurrentPosition();\n\n\t\tlet h = this.lyricPlayer.lyricGroupSize?.get(this)?.[1];\n\t\tif (h === undefined || h === 0) {\n\t\t\th = this.element.clientHeight || 0;\n\t\t}\n\n\t\tconst pb = this.lyricPlayer.size[1];\n\t\tconst ov = this.lyricPlayer.getOverscanPx();\n\n\t\treturn !(t > pb + h + ov || t < -h - ov);\n\t}\n\n\tshow(): void {\n\t\tif (!this.element.parentElement) {\n\t\t\tconst playerEl = this.lyricPlayer.getElement();\n\t\t\tconst groups = this.lyricPlayer.currentLyricGroups;\n\t\t\tconst myIndex = groups.indexOf(this);\n\n\t\t\tlet referenceNode: HTMLElement | null = null;\n\t\t\tif (myIndex !== -1) {\n\t\t\t\tfor (let i = myIndex + 1; i < groups.length; i++) {\n\t\t\t\t\tif (groups[i].element.parentElement === playerEl) {\n\t\t\t\t\t\treferenceNode = groups[i].element;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tplayerEl.insertBefore(this.element, referenceNode);\n\n\t\t\tthis.lyricPlayer.resizeObserver.observe(this.element);\n\t\t}\n\n\t\tthis.mainLine.show();\n\t\tthis.bgLine?.show();\n\t}\n\n\thide(): void {\n\t\tif (this.element.parentElement) {\n\t\t\tthis.lyricPlayer.resizeObserver.unobserve(this.element);\n\t\t\tthis.element.remove();\n\n\t\t\tthis.mainLine.teardownContent();\n\t\t\tthis.bgLine?.teardownContent();\n\t\t}\n\t}\n\n\toverride update(delta: number): void {\n\t\tif (this.isInSight) {\n\t\t\tthis.show();\n\t\t} else {\n\t\t\tthis.hide();\n\t\t}\n\n\t\tsuper.update(delta);\n\t}\n\n\taddBgLine(bgLine: LyricLineEl): void {\n\t\tif (this.bgLine) {\n\t\t\tthis.bgLine.dispose();\n\t\t}\n\t\tif (this.bgWrapper) {\n\t\t\tthis.bgWrapper.remove();\n\t\t}\n\n\t\tthis.bgLine = bgLine;\n\n\t\t// 需要对比第一个词的开始时间而不是行起始时间,因为行的起始时间已经被\n\t\t// `syncMainAndBackgroundLines` 同步过了\n\t\tconst bgStartTime =\n\t\t\tbgLine.getLine().words[0]?.startTime ?? bgLine.getLine().startTime;\n\t\tconst mainStartTime =\n\t\t\tthis.mainLine.getLine().words[0]?.startTime ??\n\t\t\tthis.mainLine.getLine().startTime;\n\n\t\tthis.isBgFirst = bgStartTime < mainStartTime;\n\n\t\tif (this.mainLine.getLine().isDuet) {\n\t\t\tbgLine.getElement().classList.add(styles.lyricDuetLine);\n\t\t}\n\n\t\tthis.bgWrapper = document.createElement(\"div\");\n\t\tthis.bgWrapper.className = styles.bgWrapper;\n\n\t\tthis.bgWrapper.appendChild(bgLine.getElement());\n\n\t\tconst alwaysPostposition =\n\t\t\tthis.lyricPlayer.getAlwaysPostpositionBackground();\n\t\tconst shouldBgFirst = !alwaysPostposition && this.isBgFirst;\n\n\t\tif (shouldBgFirst) {\n\t\t\tthis.bgWrapper.classList.add(styles.bgWrapperTop);\n\t\t\tthis.element.insertBefore(this.bgWrapper, this.mainLine.getElement());\n\t\t\tthis.bgSlideY.setPosition(80);\n\t\t} else {\n\t\t\tthis.element.appendChild(this.bgWrapper);\n\t\t}\n\t}\n\n\tprotected renderStyles(): void {\n\t\tconst y = this.posY.getCurrentPosition().toFixed(1);\n\n\t\tthis.element.style.transform = `translateY(${y}px)`;\n\t\tthis.element.style.opacity = this.opacity.toString();\n\t\tthis.element.style.filter = `blur(${Math.min(5, this.blur)}px)`;\n\n\t\tif (!this.lyricPlayer.getEnableSpring()) {\n\t\t\tthis.element.style.transitionDelay = `${this.delay}ms`;\n\t\t}\n\n\t\tif (this.bgWrapper) {\n\t\t\tif (this.lastIsActive !== this.isActive) {\n\t\t\t\tthis.lastIsActive = this.isActive;\n\t\t\t\tthis.bgWrapper.classList.toggle(styles.bgWrapperActive, this.isActive);\n\t\t\t}\n\n\t\t\tconst slideY = this.bgSlideY.getCurrentPosition();\n\t\t\tconst slideYStr = slideY.toFixed(1);\n\t\t\tconst activeProgress = clamp01(1 - Math.abs(slideY) / 80);\n\n\t\t\tconst scaleStr = (0.8 + activeProgress * 0.2).toFixed(3);\n\t\t\tthis.bgWrapper.style.transform = `translateY(${slideYStr}%) scale(${scaleStr})`;\n\n\t\t\tconst alwaysPostposition =\n\t\t\t\tthis.lyricPlayer.getAlwaysPostpositionBackground();\n\t\t\tconst shouldBgFirst = !alwaysPostposition && this.isBgFirst;\n\n\t\t\tif (shouldBgFirst) {\n\t\t\t\tconst bgHeight = this.bgWrapper.clientHeight || 0;\n\t\t\t\tconst currentMarginTop = -bgHeight * (1 - activeProgress);\n\t\t\t\tthis.bgWrapper.style.marginTop = `${currentMarginTop.toFixed(1)}px`;\n\t\t\t} else {\n\t\t\t\tthis.bgWrapper.style.marginTop = \"\";\n\t\t\t}\n\n\t\t\tconst targetHiddenYStr = shouldBgFirst ? \"80.0\" : \"-80.0\";\n\t\t\tconst isHidden = slideYStr === targetHiddenYStr && !this.isActive;\n\t\t\tthis.bgWrapper.classList.toggle(styles.bgWrapperHidden, isHidden);\n\t\t}\n\t}\n\n\toverride dispose(): void {\n\t\tsuper.dispose();\n\t\tthis.lyricPlayer.resizeObserver.unobserve(this.element);\n\t\tthis.element.remove();\n\t}\n}\n","export const isCJK = (char: string): boolean => {\n\treturn /^[\\p{Unified_Ideograph}\\u0800-\\u9FFC]+$/u.test(char);\n};\n","import type { Disposable, LyricLine, LyricWord } from \"#interfaces\";\nimport { isCJK } from \"#utils/is-cjk.ts\";\nimport { Spring } from \"#utils/spring.ts\";\nimport { LyricLineRenderMode } from \"./consts.ts\";\n\ninterface LineTransforms {\n\tscale: Spring;\n}\n\n/**\n * 所有标准歌词行的基类\n * @internal\n */\nexport abstract class LyricLineBase extends EventTarget implements Disposable {\n\tprotected top = 0;\n\tprotected scale = 1;\n\tprotected blur = 0;\n\tprotected opacity = 1;\n\tprotected delay = 0;\n\treadonly lineTransforms: LineTransforms = {\n\t\tscale: new Spring(100),\n\t};\n\n\t/**\n\t * 用于 CJK 词语边界检测的分词器\n\t */\n\tstatic readonly wordSegmenter: Intl.Segmenter | null =\n\t\ttypeof Intl !== \"undefined\" && Intl.Segmenter\n\t\t\t? new Intl.Segmenter(undefined, { granularity: \"word\" })\n\t\t\t: null;\n\n\t/**\n\t * Unicode 标准的全局 Grapheme Cluster 分词器\n\t * 用于正确处理 emoji、复合字符等\n\t */\n\tstatic readonly graphemeSegmenter: Intl.Segmenter | null =\n\t\ttypeof Intl !== \"undefined\" && Intl.Segmenter\n\t\t\t? new Intl.Segmenter(undefined, { granularity: \"grapheme\" })\n\t\t\t: null;\n\n\tabstract getLine(): LyricLine;\n\tabstract enable(time?: number, shouldPlay?: boolean): void;\n\tabstract disable(): void;\n\tabstract resume(): void;\n\tabstract pause(): void;\n\tabstract onLineSizeChange(size: [number, number]): void;\n\n\tsetTransform(\n\t\tscale: number = this.scale,\n\t\topacity: number = this.opacity,\n\t\tblur: number = this.blur,\n\t\t_force = false,\n\t\tdelay = 0,\n\t\t_mode: LyricLineRenderMode = LyricLineRenderMode.SOLID,\n\t): void {\n\t\tthis.scale = scale;\n\t\tthis.opacity = opacity;\n\t\tthis.blur = blur;\n\t\tthis.delay = delay;\n\t}\n\n\trebuildElement(): void {}\n\n\t/**\n\t * 判定歌词是否可以应用强调辉光效果\n\t *\n\t * 果子在对辉光效果的解释是一种强调(emphasized)效果\n\t *\n\t * 条件是一个单词时长大于等于 1s 且长度小于等于 7\n\t *\n\t * @param word 单词\n\t * @returns 是否可以应用强调辉光效果\n\t */\n\tstatic shouldEmphasize(word: LyricWord): boolean {\n\t\tif (isCJK(word.word)) return word.endTime - word.startTime >= 1000;\n\n\t\treturn (\n\t\t\tword.endTime - word.startTime >= 1000 &&\n\t\t\tword.word.trim().length <= 7 &&\n\t\t\tword.word.trim().length > 1\n\t\t);\n\t}\n\tabstract update(delta?: number): void;\n\tdispose(): void {}\n}\n","import { isCJK } from \"./is-cjk.ts\";\n\nexport interface ChildNodeInfo {\n\twidth: number;\n\ttext: string;\n\tisSpace: boolean;\n}\n\n/**\n * 单个词超过容器宽度时的大惩罚倍数\n */\nconst OVERFLOW_PENALTY_MULTIPLIER = 1000;\n/**\n * 截断 CJK 词组边界的惩罚比例\n *\n * 相对于容器宽度\n */\nconst CJK_BREAK_PENALTY_RATIO = 0.15;\n/**\n * 截断普通文本(非空格、非 CJK 词界)的惩罚比例\n */\nconst NORMAL_BREAK_PENALTY_RATIO = 0.5;\n/**\n * 在空格处断开的奖励比例\n */\nconst SPACE_BREAK_REWARD_RATIO = 0.4;\n/**\n * 在标点符号处断开的奖励比例\n *\n * 比空格更高以便优先一点在标点处换行\n */\nconst PUNCTUATION_BREAK_REWARD_RATIO = 0.6;\nconst PUNCTUATION_REGEX = /[,.;:!?,。;:!?、)】》」』’”)[\\]}>~…]$/;\n\n/**\n * 计算平均行长度的断点位置\n * @param children 子节点信息\n * @param containerWidth 容器可用内容宽度\n * @param fullText 完整的行文本\n * @param segmenter 预创建的 Intl.Segmenter 分词器\n * @returns 需要在其前面插入 `<br>` 的子节点索引数组,升序\n */\nexport function calcBalancedBreaks(\n\tchildren: ChildNodeInfo[],\n\tcontainerWidth: number,\n\tfullText: string,\n\tsegmenter: Intl.Segmenter,\n): number[] {\n\tconst n = children.length;\n\tif (n === 0 || containerWidth <= 0) {\n\t\treturn [];\n\t}\n\n\t// 计算哪里是 CJK 词组的边界\n\tconst cjkBoundaries = new Set<number>();\n\tlet offset = 0;\n\tfor (const { segment, isWordLike } of segmenter.segment(fullText)) {\n\t\tif (offset > 0 && isWordLike) {\n\t\t\tif ([...segment].some((ch) => isCJK(ch))) {\n\t\t\t\tcjkBoundaries.add(offset);\n\t\t\t}\n\t\t}\n\t\toffset += segment.length;\n\t}\n\n\t// 计算前缀宽和字符偏移量用于快速查询\n\tconst charOffsets = new Int32Array(n + 1);\n\tconst prefixWidth = new Float64Array(n + 1);\n\tfor (let i = 0; i < n; i++) {\n\t\tcharOffsets[i + 1] = charOffsets[i] + children[i].text.length;\n\t\tprefixWidth[i + 1] = prefixWidth[i] + children[i].width;\n\t}\n\n\tif (prefixWidth[n] <= containerWidth) {\n\t\treturn [];\n\t}\n\n\t/**\n\t * dp[i] 表示将 index i 到 n-1 的节点进行排版的最小代价\n\t */\n\tconst dp = new Float64Array(n + 1).fill(Number.POSITIVE_INFINITY);\n\tconst nextBreak = new Int32Array(n + 1).fill(-1);\n\tdp[n] = 0;\n\n\tconst PENALTY_CJK = (containerWidth * CJK_BREAK_PENALTY_RATIO) ** 2;\n\tconst PENALTY_NORMAL = (containerWidth * NORMAL_BREAK_PENALTY_RATIO) ** 2;\n\n\tfor (let i = n - 1; i >= 0; i--) {\n\t\tfor (let j = i + 1; j <= n; j++) {\n\t\t\tconst w = prefixWidth[j] - prefixWidth[i];\n\n\t\t\tlet lineCost = 0;\n\n\t\t\tif (w > containerWidth) {\n\t\t\t\tif (j === i + 1) {\n\t\t\t\t\t// 单个无法分割的词自身就比容器宽,被迫独立成行,给大惩罚\n\t\t\t\t\tlineCost = (w - containerWidth) ** 2 * OVERFLOW_PENALTY_MULTIPLIER;\n\t\t\t\t} else {\n\t\t\t\t\t// 行内包含多个超过物理宽度的词就跳过\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\t// 迫使所有行的长度方差最小化\n\t\t\t\tlineCost = (containerWidth - w) ** 2;\n\t\t\t}\n\n\t\t\tlet breakPenalty = 0;\n\t\t\tif (j < n) {\n\t\t\t\tconst prevChild = children[j - 1];\n\n\t\t\t\t// 优先级:标点 > 空格 > CJK 词界 > 普通文本\n\t\t\t\tif (PUNCTUATION_REGEX.test(prevChild.text)) {\n\t\t\t\t\tbreakPenalty = -(\n\t\t\t\t\t\t(containerWidth * PUNCTUATION_BREAK_REWARD_RATIO) **\n\t\t\t\t\t\t2\n\t\t\t\t\t);\n\t\t\t\t} else if (prevChild.isSpace) {\n\t\t\t\t\tbreakPenalty = -((containerWidth * SPACE_BREAK_REWARD_RATIO) ** 2);\n\t\t\t\t} else if (cjkBoundaries.has(charOffsets[j])) {\n\t\t\t\t\tbreakPenalty = PENALTY_CJK;\n\t\t\t\t} else {\n\t\t\t\t\tbreakPenalty = PENALTY_NORMAL;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst totalCost = lineCost + breakPenalty + dp[j];\n\n\t\t\tif (totalCost < dp[i]) {\n\t\t\t\tdp[i] = totalCost;\n\t\t\t\tnextBreak[i] = j;\n\t\t\t}\n\t\t}\n\t}\n\n\tconst breaks: number[] = [];\n\tlet curr = 0;\n\twhile (curr < n) {\n\t\tcurr = nextBreak[curr];\n\t\tif (curr > 0 && curr < n) {\n\t\t\tbreaks.push(curr);\n\t\t}\n\t}\n\n\treturn breaks;\n}\n","import { clampPositive } from \"./clamp.ts\";\nimport { type ChildNodeInfo, calcBalancedBreaks } from \"./lyric-line-break.ts\";\n\nlet sharedCanvasCtx: CanvasRenderingContext2D | null = null;\nexport function getMeasurementContext(): CanvasRenderingContext2D | null {\n\tif (!sharedCanvasCtx) {\n\t\tconst canvas = document.createElement(\"canvas\");\n\t\tsharedCanvasCtx = canvas.getContext(\"2d\");\n\t}\n\treturn sharedCanvasCtx;\n}\n\ninterface LineBalanceAdapter {\n\tresetDOM(): void;\n\tbuildChildInfos(): { childInfos: ChildNodeInfo[]; fullText: string };\n\tapplyBreaks(breaks: number[], childInfos: ChildNodeInfo[]): void;\n\tneedsCalibration: boolean;\n}\n\n/**\n * 用于平衡歌词行在换行后的各行长度\n */\nexport class LineBalancer {\n\tprivate isBalancing = false;\n\tprivate lastBalancedContainerWidth = -1;\n\n\tconstructor(private mainElement: HTMLDivElement) {}\n\n\tpublic balanceLineBreaks(\n\t\tisNonDynamic: boolean,\n\t\thasSplittedWords: boolean,\n\t\twordSegmenter: Intl.Segmenter,\n\t): void {\n\t\tif (this.isBalancing || !this.mainElement) return;\n\n\t\tconst computedStyle = getComputedStyle(this.mainElement);\n\t\tconst paddingLeft = Number.parseFloat(computedStyle.paddingLeft) || 0;\n\t\tconst paddingRight = Number.parseFloat(computedStyle.paddingRight) || 0;\n\t\tconst containerWidth =\n\t\t\tthis.mainElement.clientWidth - paddingLeft - paddingRight;\n\n\t\tif (containerWidth <= 0) return;\n\n\t\tif (isNonDynamic) {\n\t\t\tthis.balanceNonDynamicLineBreaks(\n\t\t\t\tcontainerWidth,\n\t\t\t\tcomputedStyle,\n\t\t\t\twordSegmenter,\n\t\t\t);\n\t\t\treturn;\n\t\t}\n\n\t\tif (!hasSplittedWords) return;\n\t\tthis.balanceDynamicLineBreaks(containerWidth, wordSegmenter);\n\t}\n\n\tpublic reset(): void {\n\t\tthis.lastBalancedContainerWidth = -1;\n\t}\n\n\tprivate executeLineBalance(\n\t\tcontainerWidth: number,\n\t\tadapter: LineBalanceAdapter,\n\t\twordSegmenter: Intl.Segmenter,\n\t): void {\n\t\tconst existingBrs = this.mainElement.querySelectorAll(\"br\");\n\t\tif (\n\t\t\tcontainerWidth === this.lastBalancedContainerWidth &&\n\t\t\texistingBrs.length > 0\n\t\t) {\n\t\t\treturn;\n\t\t}\n\n\t\tadapter.resetDOM();\n\n\t\t// 临时设置 white-space: nowrap 以便测量单个歌词行的宽度\n\t\tconst prevWhiteSpace = this.mainElement.style.whiteSpace;\n\t\tthis.mainElement.style.whiteSpace = \"nowrap\";\n\n\t\t// 临时移除父级的 transform 以便让 getBoundingClientRect 返回纯粹的布局尺寸\n\t\t// 基类在 enableScale 时设置的 0.97 缩放倍率会影响到计算的宽度\n\t\tconst parentElement = this.mainElement.parentElement;\n\t\tlet prevTransform = \"\";\n\t\tlet transformChanged = false;\n\n\t\tif (parentElement) {\n\t\t\tprevTransform = parentElement.style.transform;\n\t\t\tif (prevTransform && prevTransform !== \"none\") {\n\t\t\t\tparentElement.style.transform = \"none\";\n\t\t\t\ttransformChanged = true;\n\t\t\t}\n\t\t}\n\n\t\tlet lockAcquired = false;\n\n\t\ttry {\n\t\t\tconst { childInfos, fullText } = adapter.buildChildInfos();\n\n\t\t\tlet layoutWidth = childInfos.reduce((sum, c) => sum + c.width, 0);\n\n\t\t\t// 非动态歌词(用 Canvas 测量)才用 range 来缩放校准;动态歌词的强调 wrapper 有 1em 的 padding 和\n\t\t\t// margin,用 range 测会把首尾溢出的 1em 也加进来,极大地增大了行长度,视觉上就是非常激进地换行\n\t\t\tif (adapter.needsCalibration) {\n\t\t\t\tconst range = document.createRange();\n\t\t\t\trange.selectNodeContents(this.mainElement);\n\t\t\t\tconst visualWidth = range.getBoundingClientRect().width;\n\n\t\t\t\tif (layoutWidth > 0 && visualWidth > 0) {\n\t\t\t\t\tconst scale = visualWidth / layoutWidth;\n\t\t\t\t\tfor (const info of childInfos) {\n\t\t\t\t\t\tinfo.width *= scale;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tlayoutWidth = visualWidth;\n\t\t\t}\n\n\t\t\tconst safeContainerWidth = Math.max(1, containerWidth);\n\n\t\t\tif (layoutWidth <= safeContainerWidth) {\n\t\t\t\tthis.lastBalancedContainerWidth = containerWidth;\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst breaks = calcBalancedBreaks(\n\t\t\t\tchildInfos,\n\t\t\t\tsafeContainerWidth,\n\t\t\t\tfullText,\n\t\t\t\twordSegmenter,\n\t\t\t);\n\n\t\t\tif (breaks.length === 0) {\n\t\t\t\tthis.lastBalancedContainerWidth = containerWidth;\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tthis.isBalancing = true;\n\t\t\tlockAcquired = true;\n\n\t\t\tadapter.applyBreaks(breaks, childInfos);\n\t\t\tthis.lastBalancedContainerWidth = containerWidth;\n\t\t\tthis.isBalancing = false;\n\t\t} finally {\n\t\t\tthis.mainElement.style.whiteSpace = prevWhiteSpace;\n\t\t\tif (transformChanged && parentElement) {\n\t\t\t\tparentElement.style.transform = prevTransform;\n\t\t\t}\n\n\t\t\tif (lockAcquired) {\n\t\t\t\tthis.isBalancing = false;\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate balanceDynamicLineBreaks(\n\t\tcontainerWidth: number,\n\t\twordSegmenter: Intl.Segmenter,\n\t): void {\n\t\tconst infoToNode: Node[] = [];\n\n\t\tconst dynamicAdapter: LineBalanceAdapter = {\n\t\t\tresetDOM: () => {\n\t\t\t\tthis.mainElement.querySelectorAll(\"br\").forEach((br) => {\n\t\t\t\t\tbr.remove();\n\t\t\t\t});\n\t\t\t},\n\t\t\tbuildChildInfos: () => {\n\t\t\t\tinfoToNode.length = 0;\n\t\t\t\tconst childNodes = Array.from(this.mainElement.childNodes);\n\t\t\t\tconst childInfos: ChildNodeInfo[] = [];\n\t\t\t\tconst range = document.createRange();\n\n\t\t\t\tfor (const node of childNodes) {\n\t\t\t\t\tif (node.nodeType === Node.TEXT_NODE) {\n\t\t\t\t\t\tconst text = node.textContent ?? \"\";\n\t\t\t\t\t\tif (text.length === 0) continue;\n\t\t\t\t\t\trange.selectNodeContents(node);\n\t\t\t\t\t\tchildInfos.push({\n\t\t\t\t\t\t\twidth: range.getBoundingClientRect().width,\n\t\t\t\t\t\t\ttext,\n\t\t\t\t\t\t\tisSpace: text.trim().length === 0,\n\t\t\t\t\t\t});\n\t\t\t\t\t\tinfoToNode.push(node);\n\t\t\t\t\t} else if (node.nodeType === Node.ELEMENT_NODE) {\n\t\t\t\t\t\tconst el = node as HTMLElement;\n\t\t\t\t\t\tconst rect = el.getBoundingClientRect();\n\t\t\t\t\t\tconst elStyle = getComputedStyle(el);\n\t\t\t\t\t\tconst marginLeft = Number.parseFloat(elStyle.marginLeft) || 0;\n\t\t\t\t\t\tconst marginRight = Number.parseFloat(elStyle.marginRight) || 0;\n\t\t\t\t\t\tchildInfos.push({\n\t\t\t\t\t\t\twidth: clampPositive(rect.width + marginLeft + marginRight),\n\t\t\t\t\t\t\ttext: el.textContent ?? \"\",\n\t\t\t\t\t\t\tisSpace: false,\n\t\t\t\t\t\t});\n\t\t\t\t\t\tinfoToNode.push(node);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn { childInfos, fullText: childInfos.map((c) => c.text).join(\"\") };\n\t\t\t},\n\t\t\tapplyBreaks: (breaks) => {\n\t\t\t\tfor (let i = breaks.length - 1; i >= 0; i--) {\n\t\t\t\t\tconst breakIndex = breaks[i];\n\t\t\t\t\tif (breakIndex >= 0 && breakIndex < infoToNode.length) {\n\t\t\t\t\t\tthis.mainElement.insertBefore(\n\t\t\t\t\t\t\tdocument.createElement(\"br\"),\n\t\t\t\t\t\t\tinfoToNode[breakIndex],\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t},\n\t\t\tneedsCalibration: false,\n\t\t};\n\n\t\tthis.executeLineBalance(containerWidth, dynamicAdapter, wordSegmenter);\n\t}\n\n\tprivate balanceNonDynamicLineBreaks(\n\t\tcontainerWidth: number,\n\t\tcomputedStyle: CSSStyleDeclaration,\n\t\twordSegmenter: Intl.Segmenter,\n\t): void {\n\t\tconst fullText = this.mainElement.textContent ?? \"\";\n\t\tif (fullText.trim().length === 0) return;\n\n\t\tconst nonDynamicAdapter: LineBalanceAdapter = {\n\t\t\tresetDOM: () => {\n\t\t\t\tthis.mainElement.innerHTML = \"\";\n\t\t\t\tthis.mainElement.textContent = fullText;\n\t\t\t},\n\t\t\tbuildChildInfos: () => {\n\t\t\t\tconst ctx = getMeasurementContext();\n\n\t\t\t\tif (!ctx) {\n\t\t\t\t\tconsole.debug(\n\t\t\t\t\t\t\"Canvas 2D context is not supported, skipping line balancing\",\n\t\t\t\t\t);\n\t\t\t\t\treturn { childInfos: [], fullText };\n\t\t\t\t}\n\n\t\t\t\tctx.font = `${computedStyle.fontWeight} ${computedStyle.fontSize} ${computedStyle.fontFamily}`;\n\n\t\t\t\tif (\"letterSpacing\" in ctx) {\n\t\t\t\t\tctx.letterSpacing =\n\t\t\t\t\t\tcomputedStyle.letterSpacing !== \"normal\"\n\t\t\t\t\t\t\t? computedStyle.letterSpacing\n\t\t\t\t\t\t\t: \"0px\";\n\t\t\t\t}\n\t\t\t\tif (\"wordSpacing\" in ctx) {\n\t\t\t\t\tctx.wordSpacing =\n\t\t\t\t\t\tcomputedStyle.wordSpacing !== \"normal\"\n\t\t\t\t\t\t\t? computedStyle.wordSpacing\n\t\t\t\t\t\t\t: \"0px\";\n\t\t\t\t}\n\n\t\t\t\tconst childInfos: ChildNodeInfo[] = [];\n\t\t\t\tfor (const { segment } of wordSegmenter.segment(fullText)) {\n\t\t\t\t\tchildInfos.push({\n\t\t\t\t\t\twidth: ctx.measureText(segment).width,\n\t\t\t\t\t\ttext: segment,\n\t\t\t\t\t\tisSpace: segment.trim().length === 0,\n\t\t\t\t\t});\n\t\t\t\t}\n\n\t\t\t\treturn { childInfos, fullText };\n\t\t\t},\n\t\t\tapplyBreaks: (breaks, childInfos) => {\n\t\t\t\tthis.mainElement.innerHTML = \"\";\n\t\t\t\tconst breakSet = new Set(breaks);\n\t\t\t\tconst fragment = document.createDocumentFragment();\n\n\t\t\t\tfor (let i = 0; i < childInfos.length; i++) {\n\t\t\t\t\tif (breakSet.has(i)) {\n\t\t\t\t\t\tfragment.appendChild(document.createElement(\"br\"));\n\t\t\t\t\t}\n\t\t\t\t\tfragment.appendChild(document.createTextNode(childInfos[i].text));\n\t\t\t\t}\n\t\t\t\tthis.mainElement.appendChild(fragment);\n\t\t\t},\n\t\t\tneedsCalibration: true,\n\t\t};\n\n\t\tthis.executeLineBalance(containerWidth, nonDynamicAdapter, wordSegmenter);\n\t}\n}\n","import type { LyricWord } from \"../interfaces.ts\";\nimport { isCJK } from \"./is-cjk.ts\";\n\nconst SPLIT_WHITESPACE_RE = /(\\s+)/;\nconst WHITESPACE_RE = /\\s/g;\n\n/**\n * 将输入的单词重新分组,之间没有空格的单词将会组合成一个单词数组\n *\n * 例如输入:`[\"Life\", \" \", \"is\", \" a\", \" su\", \"gar so\", \"sweet\"]`\n *\n * 应该返回:`[\"Life\", \" \", \"is\", \" a\", [\" su\", \"gar\"], \"so\", \"sweet\"]`\n * @param words 输入的单词数组\n * @returns 重新分组后的单词数组\n */\nexport function chunkAndSplitLyricWords(\n\twords: LyricWord[],\n): (LyricWord | LyricWord[])[] {\n\tconst result: (LyricWord | LyricWord[])[] = [];\n\tlet currentGroup: LyricWord[] = [];\n\n\tconst flushGroup = () => {\n\t\tif (currentGroup.length > 0) {\n\t\t\tresult.push(\n\t\t\t\tcurrentGroup.length === 1 ? currentGroup[0] : [...currentGroup],\n\t\t\t);\n\t\t\tcurrentGroup = [];\n\t\t}\n\t};\n\n\tconst processAtom = (atom: LyricWord) => {\n\t\tconst isSpace = atom.word.trim().length === 0;\n\t\tconst hasRuby = (atom.ruby?.length ?? 0) > 0;\n\t\tconst isCJKChar = isCJK(atom.word);\n\n\t\tconst isMergeable = !isSpace && !hasRuby && !isCJKChar;\n\n\t\tif (isMergeable) {\n\t\t\tcurrentGroup.push(atom);\n\t\t} else {\n\t\t\tflushGroup();\n\t\t\tresult.push(atom);\n\t\t}\n\t};\n\n\tfor (const w of words) {\n\t\tconst content = w.word.trim();\n\t\tconst isSpace = content.length === 0;\n\t\tconst romanWord = w.romanWord ?? \"\";\n\t\tconst obscene = w.obscene ?? false;\n\t\tconst hasRuby = (w.ruby?.length ?? 0) > 0;\n\n\t\tif (isSpace || hasRuby) {\n\t\t\tprocessAtom({ ...w });\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst parts = w.word.split(SPLIT_WHITESPACE_RE).filter((p) => p.length > 0);\n\n\t\tconst totalLength = w.word.replace(WHITESPACE_RE, \"\").length || 1;\n\t\tconst timeSpan = w.endTime - w.startTime;\n\t\tconst timePerUnit = timeSpan / totalLength;\n\n\t\tlet currentOffset = 0;\n\n\t\tfor (const part of parts) {\n\t\t\tif (!part.trim()) {\n\t\t\t\tconst startTime = w.startTime + currentOffset * timePerUnit;\n\t\t\t\tprocessAtom({\n\t\t\t\t\tword: part,\n\t\t\t\t\tromanWord: \"\",\n\t\t\t\t\tstartTime: startTime,\n\t\t\t\t\tendTime: startTime,\n\t\t\t\t\tobscene: obscene,\n\t\t\t\t});\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif (isCJK(part) && part.length > 1 && romanWord.trim().length === 0) {\n\t\t\t\tconst chars = part.split(\"\");\n\t\t\t\tfor (const char of chars) {\n\t\t\t\t\tconst startTime = w.startTime + currentOffset * timePerUnit;\n\t\t\t\t\tprocessAtom({\n\t\t\t\t\t\tword: char,\n\t\t\t\t\t\tromanWord: \"\",\n\t\t\t\t\t\tstartTime: startTime,\n\t\t\t\t\t\tendTime: startTime + timePerUnit,\n\t\t\t\t\t\tobscene: obscene,\n\t\t\t\t\t});\n\t\t\t\t\tcurrentOffset += 1;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tconst partRealLen = part.length;\n\t\t\t\tconst startTime = w.startTime + currentOffset * timePerUnit;\n\t\t\t\tconst duration = partRealLen * timePerUnit;\n\n\t\t\t\tprocessAtom({\n\t\t\t\t\tword: part,\n\t\t\t\t\tromanWord: romanWord,\n\t\t\t\t\tstartTime: startTime,\n\t\t\t\t\tendTime: startTime + duration,\n\t\t\t\t\tobscene: obscene,\n\t\t\t\t});\n\t\t\t\tcurrentOffset += partRealLen;\n\t\t\t}\n\t\t}\n\t}\n\n\tflushGroup();\n\n\treturn result;\n}\n","// biome-ignore format: matrix\nexport type Matrix4 = [\n\tnumber, number, number, number,\n\tnumber, number, number, number,\n\tnumber, number, number, number,\n\tnumber, number, number, number,\n];\n\nexport function createMatrix4(): Matrix4 {\n\t// biome-ignore format: matrix\n\treturn [\n 1, 0, 0, 0,\n 0, 1, 0, 0,\n 0, 0, 1, 0,\n 0, 0, 0, 1\n ];\n}\n\nexport function scaleMatrix4(\n\tm: Matrix4,\n\tscale = 1,\n\torigin = { x: 0, y: 0 },\n): Matrix4 {\n\tconst [ox, oy] = [origin.x, origin.y];\n\t// biome-ignore format: matrix\n\treturn [\n m[0] * scale , m[1] * scale , m[2] * scale , m[3],\n m[4] * scale , m[5] * scale , m[6] * scale , m[7],\n m[8] * scale , m[9] * scale , m[10] * scale, m[11],\n m[12] - ox * scale + ox, m[13] - oy * scale + oy, m[14] , m[15]\n ];\n}\n\nexport function translateMatrix4(m: Matrix4, x = 0, y = 0, z = 0): Matrix4 {\n\t// biome-ignore format: matrix\n\treturn [\n m[0] , m[1] , m[2] , m[3] ,\n m[4] , m[5] , m[6] , m[7] ,\n m[8] , m[9] , m[10] , m[11],\n m[12] + x, m[13] + y, m[14] + z, m[15]\n ];\n}\n\nexport function matrix4ToCSS(m: Matrix4, fractionDigits = 4): string {\n\tconst format = (n: number, _: number) => n.toFixed(fractionDigits);\n\treturn `matrix3d(${m.map(format).join(\", \")})`;\n}\n","import bezier from \"bezier-easing\";\nimport type { LyricLine, LyricWord } from \"#interfaces\";\nimport { LyricLineRenderMode } from \"#lyric/base/consts.ts\";\nimport { LyricLineBase } from \"#lyric/base/line.ts\";\nimport styles from \"#styles/lyric-player.module.css\";\nimport { clamp, clamp01, clampPositive } from \"#utils/clamp.ts\";\nimport { isCJK } from \"#utils/is-cjk.ts\";\nimport { LineBalancer } from \"#utils/line-balancer.ts\";\nimport { chunkAndSplitLyricWords } from \"#utils/lyric-split-words.ts\";\nimport { createMatrix4, matrix4ToCSS, scaleMatrix4 } from \"#utils/matrix.ts\";\nimport type { DomLyricPlayer } from \".\";\n\ninterface RealWord extends LyricWord {\n\tmainElement: HTMLSpanElement;\n\tsubElements: HTMLSpanElement[];\n\telementAnimations: Animation[];\n\tmaskAnimations: Animation[];\n\twidth: number;\n\theight: number;\n\tpadding: number;\n\tshouldEmphasize: boolean;\n}\n\nconst ANIMATION_FRAME_QUANTITY = 32;\n\nconst norNum = (min: number, max: number) => (x: number) =>\n\tclamp01((x - min) / (max - min));\nconst EMP_EASING_MID = 0.5;\nconst beginNum = norNum(0, EMP_EASING_MID);\nconst endNum = norNum(EMP_EASING_MID, 1);\n\nconst bezIn = bezier(0.2, 0.4, 0.58, 1.0);\nconst bezOut = bezier(0.3, 0.0, 0.58, 1.0);\n\nconst makeEmpEasing = (mid: number) => {\n\treturn (x: number) => (x < mid ? bezIn(beginNum(x)) : 1 - bezOut(endNum(x)));\n};\n\nfunction generateFadeGradient(\n\twidth: number,\n\tpadding = 0,\n\tbright = \"rgba(0,0,0,var(--bright-mask-alpha, 1.0))\",\n\tdark = \"rgba(0,0,0,var(--dark-mask-alpha, 1.0))\",\n): [string, number] {\n\tconst totalAspect = 2 + width + padding;\n\tconst widthInTotal = width / totalAspect;\n\tconst leftPos = (1 - widthInTotal) / 2;\n\treturn [\n\t\t`linear-gradient(to right,${bright} ${leftPos * 100}%,${dark} ${\n\t\t\t(leftPos + widthInTotal) * 100\n\t\t}%)`,\n\t\ttotalAspect,\n\t];\n}\n\nexport class RawLyricLineMouseEvent extends MouseEvent {\n\tconstructor(\n\t\tpublic readonly line: LyricLineBase,\n\t\tevent: MouseEvent,\n\t) {\n\t\tsuper(event.type, event);\n\t}\n}\n\ntype MouseEventMap = {\n\t[evt in keyof HTMLElementEventMap]: HTMLElementEventMap[evt] extends MouseEvent\n\t\t? evt\n\t\t: never;\n};\ntype MouseEventTypes = MouseEventMap[keyof MouseEventMap];\ntype MouseEventListener = (\n\tthis: LyricLineEl,\n\tev: RawLyricLineMouseEvent,\n) => void;\n\nexport class LyricLineEl extends LyricLineBase {\n\tprivate element: HTMLElement = document.createElement(\"div\");\n\tprivate splittedWords: RealWord[] = [];\n\t// 标记是否已经构建了行内的实际 DOM(单词与动画等)\n\tprivate built = false;\n\n\t// 由 LyricPlayer 来设置\n\tlineSize: number[] = [0, 0];\n\n\tprivate renderMode: LyricLineRenderMode = LyricLineRenderMode.SOLID;\n\n\tprivate currentBrightAlpha = 1.0;\n\tprivate currentDarkAlpha = 0.2;\n\n\tprivate targetBrightAlpha = 1.0;\n\tprivate targetDarkAlpha = 0.2;\n\n\t/**\n\t * 用于平衡换行、尽量减少各行长度差异的类\n\t */\n\tprivate balancer?: LineBalancer;\n\n\tconstructor(\n\t\tprivate lyricPlayer: DomLyricPlayer,\n\t\tprivate lyricLine: LyricLine = {\n\t\t\twords: [],\n\t\t\ttranslatedLyric: \"\",\n\t\t\tromanLyric: \"\",\n\t\t\tstartTime: 0,\n\t\t\tendTime: 0,\n\t\t\tisBG: false,\n\t\t\tisDuet: false,\n\t\t},\n\t) {\n\t\tsuper();\n\t\tthis.element.setAttribute(\"class\", styles.lyricLine);\n\t\tif (this.lyricLine.isBG) {\n\t\t\tthis.element.classList.add(styles.lyricBgLine);\n\t\t}\n\t\tif (this.lyricLine.isDuet) {\n\t\t\tthis.element.classList.add(styles.lyricDuetLine);\n\t\t}\n\t\tthis.element.appendChild(document.createElement(\"div\")); // 歌词行\n\t\tthis.element.appendChild(document.createElement(\"div\")); // 翻译行\n\t\tthis.element.appendChild(document.createElement(\"div\")); // 音译行\n\t\tconst main = this.element.children[0] as HTMLDivElement;\n\t\tconst trans = this.element.children[1] as HTMLDivElement;\n\t\tconst roman = this.element.children[2] as HTMLDivElement;\n\t\tmain.setAttribute(\"class\", styles.lyricMainLine);\n\t\ttrans.setAttribute(\"class\", styles.lyricSubLine);\n\t\troman.setAttribute(\"class\", styles.lyricSubLine);\n\t\tif (LyricLineBase.wordSegmenter) {\n\t\t\tthis.balancer = new LineBalancer(main);\n\t\t}\n\t\t// 延迟构建具体行内容,进入可视区(含 overscan)时再构建\n\t\tthis.rebuildStyle();\n\t}\n\tprivate listenersMap = new Map<string, Set<MouseEventListener>>();\n\tprivate readonly onMouseEvent = (e: MouseEvent) => {\n\t\tconst wrapped = new RawLyricLineMouseEvent(this, e);\n\t\tfor (const listener of this.listenersMap.get(e.type) ?? []) {\n\t\t\tlistener.call(this, wrapped);\n\t\t}\n\t\tif (!this.dispatchEvent(wrapped) || wrapped.defaultPrevented) {\n\t\t\te.preventDefault();\n\t\t\te.stopPropagation();\n\t\t\te.stopImmediatePropagation();\n\t\t}\n\t};\n\n\taddMouseEventListener(\n\t\ttype: MouseEventTypes,\n\t\tcallback: MouseEventListener | null,\n\t\toptions?: boolean | AddEventListenerOptions | undefined,\n\t): void {\n\t\tif (callback) {\n\t\t\tconst listeners = this.listenersMap.get(type) ?? new Set();\n\t\t\tif (listeners.size === 0)\n\t\t\t\tthis.element.addEventListener(type, this.onMouseEvent, options);\n\t\t\tlisteners.add(callback);\n\t\t\tthis.listenersMap.set(type, listeners);\n\t\t}\n\t}\n\n\tremoveMouseEventListener(\n\t\ttype: MouseEventTypes,\n\t\tcallback: MouseEventListener | null,\n\t\toptions?: boolean | EventListenerOptions | undefined,\n\t): void {\n\t\tif (callback) {\n\t\t\tconst listeners = this.listenersMap.get(type);\n\t\t\tif (listeners) {\n\t\t\t\tlisteners.delete(callback);\n\t\t\t\tif (listeners.size === 0)\n\t\t\t\t\tthis.element.removeEventListener(type, this.onMouseEvent, options);\n\t\t\t}\n\t\t}\n\t}\n\n\tareWordsOnSameLine(word1: RealWord, word2: RealWord): boolean {\n\t\tif (word1?.mainElement && word2?.mainElement) {\n\t\t\tconst word1el = word1.mainElement;\n\t\t\tconst word2el = word2.mainElement;\n\n\t\t\tconst rect1 = word1el.getBoundingClientRect();\n\t\t\tconst rect2 = word2el.getBoundingClientRect();\n\n\t\t\t// 检查两个单词的顶部距离是否相等(或者差值很小)\n\t\t\tconst topDifference = Math.abs(rect1.top - rect2.top);\n\n\t\t\t// 如果顶部距离相差很小,可以认为它们在同一行上\n\t\t\treturn topDifference < 10;\n\t\t}\n\n\t\treturn true;\n\t}\n\n\tprivate isEnabled = false;\n\tasync enable(\n\t\tmaskAnimationTime: number = this.lyricPlayer.getCurrentTime(),\n\t\tshouldPlay: boolean = this.lyricPlayer.getIsPlaying(),\n\t): Promise<void> {\n\t\tthis.isEnabled = true;\n\t\tthis.element.classList.add(styles.active);\n\t\tconst main = this.element.children[0] as HTMLDivElement;\n\n\t\tconst relativeTime = clampPositive(\n\t\t\tmaskAnimationTime - this.lyricLine.startTime,\n\t\t);\n\n\t\tfor (const word of this.splittedWords) {\n\t\t\tfor (const a of word.elementAnimations) {\n\t\t\t\ta.currentTime = relativeTime;\n\t\t\t\ta.playbackRate = 1;\n\n\t\t\t\tconst timing = a.effect?.getComputedTiming();\n\t\t\t\tconst duration = Number(timing?.duration ?? 0);\n\t\t\t\tconst delay = Number(timing?.delay ?? 0);\n\t\t\t\tconst endTime = delay + duration;\n\n\t\t\t\tif (shouldPlay && relativeTime < endTime) a.play();\n\t\t\t\telse a.pause();\n\t\t\t}\n\n\t\t\tfor (const a of word.maskAnimations) {\n\t\t\t\tconst t = Math.min(this.totalDuration, relativeTime);\n\t\t\t\ta.currentTime = t;\n\t\t\t\ta.playbackRate = 1;\n\n\t\t\t\tconst timing = a.effect?.getComputedTiming();\n\t\t\t\tconst duration = Number(timing?.duration ?? 0);\n\t\t\t\tconst delay = Number(timing?.delay ?? 0);\n\t\t\t\tconst endTime = delay + duration;\n\n\t\t\t\tif (shouldPlay && t < endTime) a.play();\n\t\t\t\telse a.pause();\n\t\t\t}\n\t\t}\n\t\tmain.classList.add(styles.active);\n\t}\n\n\tdisable(): void {\n\t\tthis.isEnabled = false;\n\t\tthis.element.classList.remove(styles.active);\n\t\tthis.renderMode = LyricLineRenderMode.SOLID;\n\n\t\tconst main = this.element.children[0] as HTMLDivElement;\n\n\t\tfor (const word of this.splittedWords) {\n\t\t\tfor (const a of word.elementAnimations) {\n\t\t\t\tif (\n\t\t\t\t\ta.id === \"float-word\" ||\n\t\t\t\t\ta.id.includes(\"emphasize-word-float-only\")\n\t\t\t\t) {\n\t\t\t\t\ta.playbackRate = -1;\n\t\t\t\t\ta.play();\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tfor (const a of word.maskAnimations) {\n\t\t\t\ta.pause();\n\t\t\t}\n\t\t}\n\t\tmain.classList.remove(styles.active);\n\t}\n\n\tprivate lastWord?: RealWord;\n\n\tasync resume(): Promise<void> {\n\t\tif (!this.isEnabled) return;\n\t\tfor (const word of this.splittedWords) {\n\t\t\tfor (const a of word.elementAnimations) {\n\t\t\t\tif (\n\t\t\t\t\t!this.lastWord ||\n\t\t\t\t\tthis.splittedWords.indexOf(this.lastWord) <\n\t\t\t\t\t\tthis.splittedWords.indexOf(word)\n\t\t\t\t) {\n\t\t\t\t\tconst timing = a.effect?.getComputedTiming();\n\t\t\t\t\tconst duration = (timing?.duration as number) || 0;\n\t\t\t\t\tconst delay = (timing?.delay as number) || 0;\n\t\t\t\t\tconst endTime = delay + duration;\n\t\t\t\t\tconst currentTime = (a.currentTime as number) || 0;\n\n\t\t\t\t\tif (a.playState !== \"finished\" && currentTime < endTime) {\n\t\t\t\t\t\ta.play();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tfor (const a of word.maskAnimations) {\n\t\t\t\tif (\n\t\t\t\t\t!this.lastWord ||\n\t\t\t\t\tthis.splittedWords.indexOf(this.lastWord) <\n\t\t\t\t\t\tthis.splittedWords.indexOf(word)\n\t\t\t\t) {\n\t\t\t\t\tconst timing = a.effect?.getComputedTiming();\n\t\t\t\t\tconst duration = (timing?.duration as number) || 0;\n\t\t\t\t\tconst delay = (timing?.delay as number) || 0;\n\t\t\t\t\tconst endTime = delay + duration;\n\n\t\t\t\t\tconst currentTime = (a.currentTime as number) || 0;\n\n\t\t\t\t\tif (a.playState !== \"finished\" && currentTime < endTime) {\n\t\t\t\t\t\ta.play();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tasync pause(): Promise<void> {\n\t\tif (!this.isEnabled) return;\n\t\tfor (const word of this.splittedWords) {\n\t\t\tfor (const a of word.elementAnimations) {\n\t\t\t\ta.pause();\n\t\t\t}\n\t\t\tfor (const a of word.maskAnimations) {\n\t\t\t\ta.pause();\n\t\t\t}\n\t\t}\n\t}\n\tsetMaskAnimationState(maskAnimationTime = 0): void {\n\t\tconst t = maskAnimationTime - this.lyricLine.startTime;\n\t\tfor (const word of this.splittedWords) {\n\t\t\tfor (const a of word.maskAnimations) {\n\t\t\t\ta.currentTime = clamp(t, 0, this.totalDuration);\n\t\t\t\ta.playbackRate = 1;\n\t\t\t\tif (t >= 0 && t < this.totalDuration) a.play();\n\t\t\t\telse a.pause();\n\t\t\t}\n\t\t}\n\t}\n\n\tgetLine(): LyricLine {\n\t\treturn this.lyricLine;\n\t}\n\t// private _hide = true;\n\tprivate lastStyle = \"\";\n\tshow(): void {\n\t\tif (!this.built) {\n\t\t\tthis.rebuildElement();\n\t\t\tthis.built = true;\n\t\t\tthis.updateMaskImageSync();\n\t\t}\n\t}\n\n\tprivate rebuildStyle() {\n\t\tlet style = \"\";\n\t\tstyle += `transform: scale(${(this.lineTransforms.scale.getCurrentPosition() / 100).toFixed(4)});`;\n\n\t\tif (!this.lyricPlayer.getEnableSpring()) {\n\t\t\tstyle += `transition-delay:${this.delay}ms;`;\n\t\t}\n\n\t\tstyle += `filter:blur(${Math.min(5, this.blur)}px);`;\n\t\tif (style !== this.lastStyle) {\n\t\t\tthis.lastStyle = style;\n\t\t\tthis.element.setAttribute(\"style\", style);\n\t\t}\n\t}\n\n\toverride rebuildElement(): void {\n\t\tthis.disposeElements();\n\t\tconst main = this.element.children[0] as HTMLDivElement;\n\t\tconst trans = this.element.children[1] as HTMLDivElement;\n\t\tconst roman = this.element.children[2] as HTMLDivElement;\n\t\t// 非动态歌词,直接渲染整行与副行\n\t\tif (this.lyricPlayer._getIsNonDynamic()) {\n\t\t\tmain.innerText = this.lyricLine.words\n\t\t\t\t.map((w) => this.lyricPlayer.processObsceneWord(w))\n\t\t\t\t.join(\"\");\n\t\t\tthis.setSubLinesText(trans, roman);\n\t\t\treturn;\n\t\t}\n\n\t\tconst chunkedWords = chunkAndSplitLyricWords(this.lyricLine.words);\n\t\tconst hasRubyLine = this.lyricLine.words.some(\n\t\t\t(word) => (word.ruby?.length ?? 0) > 0,\n\t\t);\n\t\tconst hasRomanLine = this.lyricLine.words.some(\n\t\t\t(word) => (word.romanWord?.trim().length ?? 0) > 0,\n\t\t);\n\t\tmain.innerHTML = \"\";\n\n\t\tfor (const chunk of chunkedWords) {\n\t\t\tthis.buildWord(chunk, main, hasRubyLine, hasRomanLine);\n\t\t}\n\n\t\tthis.setSubLinesText(trans, roman);\n\t}\n\n\t/** 设置翻译与音译行文本 */\n\tprivate setSubLinesText(trans: HTMLDivElement, roman: HTMLDivElement) {\n\t\ttrans.innerText = this.lyricLine.translatedLyric;\n\t\troman.innerText = this.lyricLine.romanLyric;\n\t}\n\n\tprivate getRubyCharCount(word: LyricWord) {\n\t\treturn (word.ruby ?? []).reduce(\n\t\t\t(total, ruby) => total + ruby.word.length,\n\t\t\t0,\n\t\t);\n\t}\n\n\tprivate getRubySegments(word: LyricWord) {\n\t\treturn (word.ruby ?? []).filter(\n\t\t\t(ruby) => (ruby?.word?.trim().length ?? 0) > 0,\n\t\t);\n\t}\n\n\tprivate createWord(\n\t\tword: LyricWord,\n\t\tshouldEmphasize: boolean,\n\t\thasRubyLine: boolean,\n\t\thasRomanLine: boolean,\n\t): RealWord {\n\t\tconst mainWordEl = document.createElement(\"span\");\n\t\tconst subElements: HTMLSpanElement[] = [];\n\t\tconst romanWord = word.romanWord?.trim() ?? \"\";\n\t\tconst wordContainer = hasRubyLine\n\t\t\t? document.createElement(\"div\")\n\t\t\t: mainWordEl;\n\n\t\tif (hasRubyLine) {\n\t\t\tconst rubyWordEl = document.createElement(\"div\");\n\t\t\tconst rubySegments = this.getRubySegments(word);\n\t\t\tfor (const ruby of rubySegments) {\n\t\t\t\tconst rubyPartEl = document.createElement(\"span\");\n\t\t\t\trubyPartEl.innerText = ruby.word;\n\t\t\t\trubyPartEl.dataset.startTime = String(ruby.startTime);\n\t\t\t\trubyPartEl.dataset.endTime = String(ruby.endTime);\n\t\t\t\trubyWordEl.appendChild(rubyPartEl);\n\t\t\t}\n\t\t\trubyWordEl.classList.add(styles.rubyWord);\n\t\t\tmainWordEl.classList.add(styles.wordWithRuby);\n\t\t\twordContainer.classList.add(styles.wordBody);\n\t\t\tmainWordEl.appendChild(rubyWordEl);\n\t\t\tmainWordEl.appendChild(wordContainer);\n\t\t}\n\n\t\tconst displayWord = this.lyricPlayer.processObsceneWord(word);\n\n\t\tif (shouldEmphasize) {\n\t\t\tmainWordEl.classList.add(styles.emphasize);\n\t\t\tconst trimmedWord = displayWord.trim();\n\n\t\t\tif (LyricLineBase.graphemeSegmenter) {\n\t\t\t\tfor (const { segment } of LyricLineBase.graphemeSegmenter.segment(\n\t\t\t\t\ttrimmedWord,\n\t\t\t\t)) {\n\t\t\t\t\tconst charEl = document.createElement(\"span\");\n\t\t\t\t\tcharEl.innerText = segment;\n\t\t\t\t\tsubElements.push(charEl);\n\t\t\t\t\twordContainer.appendChild(charEl);\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tfor (const segment of Array.from(trimmedWord)) {\n\t\t\t\t\tconst charEl = document.createElement(\"span\");\n\t\t\t\t\tcharEl.innerText = segment;\n\t\t\t\t\tsubElements.push(charEl);\n\t\t\t\t\twordContainer.appendChild(charEl);\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\tif (hasRomanLine) {\n\t\t\t\tconst wordEl = document.createElement(\"div\");\n\t\t\t\twordEl.innerText = displayWord.trim();\n\t\t\t\twordContainer.appendChild(wordEl);\n\t\t\t} else if (romanWord.length === 0) {\n\t\t\t\twordContainer.innerText = displayWord.trim();\n\t\t\t}\n\t\t}\n\n\t\tif (hasRomanLine) {\n\t\t\tconst romanWordEl = document.createElement(\"div\");\n\t\t\tromanWordEl.innerText = romanWord.length > 0 ? romanWord : \"\\u00A0\";\n\t\t\tromanWordEl.classList.add(styles.romanWord);\n\t\t\twordContainer.appendChild(romanWordEl);\n\t\t}\n\n\t\tconst realWord: RealWord = {\n\t\t\t...word,\n\t\t\tmainElement: mainWordEl,\n\t\t\tsubElements: subElements,\n\t\t\telementAnimations: [this.initFloatAnimation(word, mainWordEl)],\n\t\t\tmaskAnimations: [],\n\t\t\twidth: 0,\n\t\t\theight: 0,\n\t\t\tpadding: 0,\n\t\t\tshouldEmphasize: shouldEmphasize,\n\t\t};\n\n\t\treturn realWord;\n\t}\n\n\tprivate buildWord(\n\t\tinput: LyricWord | LyricWord[],\n\t\tmain: HTMLDivElement,\n\t\thasRubyLine: boolean,\n\t\thasRomanLine: boolean,\n\t) {\n\t\tconst chunk = Array.isArray(input) ? input : [input];\n\t\tif (chunk.length === 0) return;\n\n\t\tconst isPureSpace = chunk.every((w) => !w.word.trim());\n\t\tif (isPureSpace) {\n\t\t\tconst textContent = chunk.map((w) => w.word).join(\"\");\n\t\t\tmain.appendChild(document.createTextNode(textContent));\n\t\t\treturn;\n\t\t}\n\n\t\tconst merged = chunk.reduce(\n\t\t\t(a, b) => {\n\t\t\t\ta.endTime = Math.max(a.endTime, b.endTime);\n\t\t\t\ta.startTime = Math.min(a.startTime, b.startTime);\n\t\t\t\ta.word += b.word;\n\t\t\t\treturn a;\n\t\t\t},\n\t\t\t{\n\t\t\t\tword: \"\",\n\t\t\t\tromanWord: \"\",\n\t\t\t\tstartTime: Number.POSITIVE_INFINITY,\n\t\t\t\tendTime: Number.NEGATIVE_INFINITY,\n\t\t\t\twordType: \"normal\",\n\t\t\t\tobscene: false,\n\t\t\t} as LyricWord,\n\t\t);\n\n\t\tlet emp = chunk.some((word) => LyricLineBase.shouldEmphasize(word));\n\t\tif (!isCJK(merged.word)) {\n\t\t\temp = emp || LyricLineBase.shouldEmphasize(merged);\n\t\t}\n\n\t\tconst wrapperWordEl = document.createElement(\"span\");\n\t\twrapperWordEl.classList.add(styles.emphasizeWrapper);\n\n\t\tconst characterElements: HTMLElement[] = [];\n\n\t\tfor (const word of chunk) {\n\t\t\tif (!word.word.trim()) {\n\t\t\t\twrapperWordEl.appendChild(document.createTextNode(word.word));\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst realWord = this.createWord(word, emp, hasRubyLine, hasRomanLine);\n\n\t\t\tif (emp) {\n\t\t\t\tcharacterElements.push(...realWord.subElements);\n\t\t\t}\n\n\t\t\tthis.splittedWords.push(realWord);\n\t\t\twrapperWordEl.appendChild(realWord.mainElement);\n\t\t}\n\n\t\tif (emp && this.splittedWords.length > 0) {\n\t\t\tconst lastWordOfChunk = this.splittedWords[this.splittedWords.length - 1];\n\t\t\tconst rubyCharCount = chunk.reduce(\n\t\t\t\t(total, word) => total + this.getRubyCharCount(word),\n\t\t\t\t0,\n\t\t\t);\n\n\t\t\tlastWordOfChunk.elementAnimations.push(\n\t\t\t\t...this.initEmphasizeAnimation(\n\t\t\t\t\tmerged,\n\t\t\t\t\tcharacterElements,\n\t\t\t\t\tmerged.endTime - merged.startTime,\n\t\t\t\t\tmerged.startTime - this.lyricLine.startTime,\n\t\t\t\t\trubyCharCount,\n\t\t\t\t),\n\t\t\t);\n\t\t}\n\n\t\tmain.appendChild(wrapperWordEl);\n\t}\n\n\tprivate initFloatAnimation(word: LyricWord, wordEl: HTMLSpanElement) {\n\t\tconst delay = word.startTime - this.lyricLine.startTime;\n\t\tconst duration = Math.max(1000, word.endTime - word.startTime);\n\t\tlet up = 0.05;\n\t\tif (this.lyricLine.isBG) {\n\t\t\tup *= 2;\n\t\t}\n\t\tconst a = wordEl.animate(\n\t\t\t[\n\t\t\t\t{\n\t\t\t\t\ttransform: \"translateY(0px)\",\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\ttransform: `translateY(${-up}em)`,\n\t\t\t\t},\n\t\t\t],\n\t\t\t{\n\t\t\t\tduration: Number.isFinite(duration) ? duration : 0,\n\t\t\t\tdelay: Number.isFinite(delay) ? delay : 0,\n\t\t\t\tid: \"float-word\",\n\t\t\t\tcomposite: \"add\",\n\t\t\t\tfill: \"both\",\n\t\t\t\teasing: \"ease-out\",\n\t\t\t},\n\t\t);\n\t\ta.pause();\n\t\treturn a;\n\t}\n\t// 按照原 Apple Music 参考,强调效果只应用缩放、轻微左右位移和辉光效果,原主要的悬浮位移效果不变\n\t// 为了避免产生锯齿抖动感,使用 matrix3d 来实现缩放和位移\n\tprivate initEmphasizeAnimation(\n\t\tword: LyricWord,\n\t\tcharacterElements: HTMLElement[],\n\t\tduration: number,\n\t\tdelay: number,\n\t\trubyCharCount: number,\n\t): Animation[] {\n\t\tconst de = clampPositive(delay);\n\t\tlet du = Math.max(1000, duration);\n\t\tconst anchorCharCount =\n\t\t\trubyCharCount > 0 ? rubyCharCount : Math.max(1, characterElements.length);\n\n\t\tlet result: Animation[] = [];\n\n\t\tlet amount = du / 2000;\n\t\tamount = amount > 1 ? Math.sqrt(amount) : amount ** 3;\n\t\tlet blur = du / 3000;\n\t\tblur = blur > 1 ? Math.sqrt(blur) : blur ** 3;\n\t\tamount *= 0.6;\n\t\tblur *= 0.5;\n\t\tif (\n\t\t\tthis.lyricLine.words.length > 0 &&\n\t\t\tword.word.includes(\n\t\t\t\tthis.lyricLine.words[this.lyricLine.words.length - 1].word,\n\t\t\t)\n\t\t) {\n\t\t\tamount *= 1.6;\n\t\t\tblur *= 1.5;\n\t\t\tdu *= 1.2;\n\t\t}\n\t\tamount = Math.min(1.2, amount);\n\t\tblur = Math.min(0.8, blur);\n\n\t\tconst animateDu = Number.isFinite(du) ? du : 0;\n\t\tconst empEasing = makeEmpEasing(EMP_EASING_MID);\n\n\t\tresult = characterElements.flatMap((el, i, arr) => {\n\t\t\tconst wordDe = de + (du / 2.5 / anchorCharCount) * i;\n\t\t\tconst result: Animation[] = [];\n\n\t\t\tconst frames: Keyframe[] = new Array(ANIMATION_FRAME_QUANTITY)\n\t\t\t\t.fill(0)\n\t\t\t\t.map((_, j) => {\n\t\t\t\t\tconst x = (j + 1) / ANIMATION_FRAME_QUANTITY;\n\t\t\t\t\tconst transX = empEasing(x);\n\t\t\t\t\tconst glowLevel = empEasing(x) * blur;\n\n\t\t\t\t\tconst mat = scaleMatrix4(createMatrix4(), 1 + transX * 0.1 * amount);\n\t\t\t\t\tconst offsetX = -transX * 0.03 * amount * (arr.length / 2 - i);\n\t\t\t\t\tconst offsetY = -transX * 0.025 * amount;\n\n\t\t\t\t\treturn {\n\t\t\t\t\t\toffset: x,\n\t\t\t\t\t\ttransform: `${matrix4ToCSS(\n\t\t\t\t\t\t\tmat,\n\t\t\t\t\t\t\t4,\n\t\t\t\t\t\t)} translate(${offsetX}em, ${offsetY}em)`,\n\t\t\t\t\t\ttextShadow: `0 0 ${Math.min(\n\t\t\t\t\t\t\t0.3,\n\t\t\t\t\t\t\tblur * 0.3,\n\t\t\t\t\t\t)}em rgba(255, 255, 255, ${glowLevel})`,\n\t\t\t\t\t};\n\t\t\t\t});\n\n\t\t\tconst glow = el.animate(frames, {\n\t\t\t\tduration: animateDu,\n\t\t\t\tdelay: Number.isFinite(wordDe) ? wordDe : 0,\n\t\t\t\tid: `emphasize-word-${el.innerText}-${i}`,\n\t\t\t\titerations: 1,\n\t\t\t\tcomposite: \"replace\",\n\t\t\t\tfill: \"both\",\n\t\t\t});\n\t\t\tglow.onfinish = () => {\n\t\t\t\tglow.pause();\n\t\t\t};\n\t\t\tglow.pause();\n\t\t\tresult.push(glow);\n\n\t\t\tconst floatFrame: Keyframe[] = new Array(ANIMATION_FRAME_QUANTITY)\n\t\t\t\t.fill(0)\n\t\t\t\t.map((_, j) => {\n\t\t\t\t\tconst x = (j + 1) / ANIMATION_FRAME_QUANTITY;\n\t\t\t\t\tlet y = Math.sin(x * Math.PI);\n\t\t\t\t\t// y = x < 0.5 ? y : Math.max(y, 1.0);\n\t\t\t\t\tif (this.lyricLine.isBG) {\n\t\t\t\t\t\ty *= 2;\n\t\t\t\t\t}\n\n\t\t\t\t\treturn {\n\t\t\t\t\t\toffset: x,\n\t\t\t\t\t\ttransform: `translateY(${-y * 0.05}em)`,\n\t\t\t\t\t};\n\t\t\t\t});\n\t\t\tconst float = el.animate(floatFrame, {\n\t\t\t\tduration: animateDu * 1.4,\n\t\t\t\tdelay: Number.isFinite(wordDe) ? wordDe - 400 : 0,\n\t\t\t\tid: \"emphasize-word-float\",\n\t\t\t\titerations: 1,\n\t\t\t\tcomposite: \"add\",\n\t\t\t\tfill: \"both\",\n\t\t\t});\n\t\t\tfloat.onfinish = () => {\n\t\t\t\tfloat.pause();\n\t\t\t};\n\t\t\tfloat.pause();\n\t\t\tresult.push(float);\n\n\t\t\treturn result;\n\t\t});\n\n\t\treturn result;\n\t}\n\n\tprivate get totalDuration() {\n\t\treturn this.lyricLine.endTime - this.lyricLine.startTime;\n\t}\n\n\toverride onLineSizeChange(_size: [number, number]): void {\n\t\tthis.updateMaskImageSync();\n\t}\n\tupdateMaskImageSync(): void {\n\t\tfor (const word of this.splittedWords) {\n\t\t\tconst el = word.mainElement;\n\t\t\tif (el) {\n\t\t\t\tword.padding = Number.parseFloat(getComputedStyle(el).paddingLeft);\n\t\t\t\tword.width = el.clientWidth - word.padding * 2;\n\t\t\t\tword.height = el.clientHeight - word.padding * 2;\n\t\t\t} else {\n\t\t\t\tword.width = 0;\n\t\t\t\tword.height = 0;\n\t\t\t\tword.padding = 0;\n\t\t\t}\n\t\t}\n\t\tif (this.balancer && LyricLineBase.wordSegmenter) {\n\t\t\tthis.balancer.balanceLineBreaks(\n\t\t\t\tthis.lyricPlayer._getIsNonDynamic(),\n\t\t\t\tthis.splittedWords.length > 0,\n\t\t\t\tLyricLineBase.wordSegmenter,\n\t\t\t);\n\t\t}\n\t\tif (this.lyricPlayer.supportMaskImage) {\n\t\t\tthis.generateWebAnimationBasedMaskImage();\n\t\t} else {\n\t\t\tthis.generateCalcBasedMaskImage();\n\t\t}\n\t\tif (this.isEnabled) {\n\t\t\tconst isPlayerRunning = this.lyricPlayer.getIsPlaying?.() ?? true;\n\t\t\tthis.enable(this.lyricPlayer.getCurrentTime(), isPlayerRunning);\n\t\t}\n\t}\n\n\tprivate generateCalcBasedMaskImage() {\n\t\tfor (const word of this.splittedWords) {\n\t\t\tconst wordEl = word.mainElement;\n\t\t\tif (wordEl) {\n\t\t\t\tword.width = wordEl.clientWidth;\n\t\t\t\tword.height = wordEl.clientHeight;\n\t\t\t\tconst fadeWidth = word.height * this.lyricPlayer.getWordFadeWidth();\n\t\t\t\tconst [maskImage, totalAspect] = generateFadeGradient(\n\t\t\t\t\tfadeWidth / word.width,\n\t\t\t\t);\n\t\t\t\tconst totalAspectStr = `${totalAspect * 100}% 100%`;\n\t\t\t\tif (this.lyricPlayer.supportMaskImage) {\n\t\t\t\t\twordEl.style.maskImage = maskImage;\n\t\t\t\t\twordEl.style.maskRepeat = \"no-repeat\";\n\t\t\t\t\twordEl.style.maskOrigin = \"left\";\n\t\t\t\t\twordEl.style.maskSize = totalAspectStr;\n\t\t\t\t} else {\n\t\t\t\t\twordEl.style.webkitMaskImage = maskImage;\n\t\t\t\t\twordEl.style.webkitMaskRepeat = \"no-repeat\";\n\t\t\t\t\twordEl.style.webkitMaskOrigin = \"left\";\n\t\t\t\t\twordEl.style.webkitMaskSize = totalAspectStr;\n\t\t\t\t}\n\t\t\t\tconst w = word.width + fadeWidth;\n\t\t\t\tconst maskPos = `clamp(${-w}px,calc(${-w}px + (var(--amll-player-time) - ${\n\t\t\t\t\tword.startTime\n\t\t\t\t})*${\n\t\t\t\t\tw / Math.abs(word.endTime - word.startTime)\n\t\t\t\t}px),0px) 0px, left top`;\n\t\t\t\twordEl.style.maskPosition = maskPos;\n\t\t\t\twordEl.style.webkitMaskPosition = maskPos;\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate generateWebAnimationBasedMaskImage() {\n\t\t// 因为歌词行有可能比行内单词的结束时间早,有可能导致过渡动画提早停止出现瑕疵\n\t\t// 所以要以单词的结束时间为准\n\t\tconst totalFadeDuration =\n\t\t\tMath.max(\n\t\t\t\t0,\n\t\t\t\t...this.splittedWords.map((w) => w.endTime),\n\t\t\t\tthis.lyricLine.endTime,\n\t\t\t) - this.lyricLine.startTime;\n\t\tthis.splittedWords.forEach((word, i) => {\n\t\t\tconst wordEl = word.mainElement;\n\t\t\tif (wordEl) {\n\t\t\t\tconst fadeWidth = word.height * this.lyricPlayer.getWordFadeWidth();\n\t\t\t\tconst [maskImage, totalAspect] = generateFadeGradient(\n\t\t\t\t\tfadeWidth / (word.width + word.padding * 2),\n\t\t\t\t);\n\t\t\t\tconst totalAspectStr = `${totalAspect * 100}% 100%`;\n\t\t\t\tif (this.lyricPlayer.supportMaskImage) {\n\t\t\t\t\twordEl.style.maskImage = maskImage;\n\t\t\t\t\twordEl.style.maskRepeat = \"no-repeat\";\n\t\t\t\t\twordEl.style.maskOrigin = \"left\";\n\t\t\t\t\twordEl.style.maskSize = totalAspectStr;\n\t\t\t\t} else {\n\t\t\t\t\twordEl.style.webkitMaskImage = maskImage;\n\t\t\t\t\twordEl.style.webkitMaskRepeat = \"no-repeat\";\n\t\t\t\t\twordEl.style.webkitMaskOrigin = \"left\";\n\t\t\t\t\twordEl.style.webkitMaskSize = totalAspectStr;\n\t\t\t\t}\n\t\t\t\t// 为了尽可能将渐变动画在相连的每个单词间近似衔接起来\n\t\t\t\t// 要综合每个单词的效果时间和间隙生成动画帧数组\n\t\t\t\tconst widthBeforeSelf =\n\t\t\t\t\tthis.splittedWords.slice(0, i).reduce((a, b) => a + b.width, 0) +\n\t\t\t\t\t(this.splittedWords[0] ? fadeWidth : 0);\n\t\t\t\tconst minOffset = -(word.width + word.padding * 2 + fadeWidth);\n\t\t\t\tconst clampOffset = (x: number) => clamp(x, minOffset, 0);\n\t\t\t\tlet curPos = -widthBeforeSelf - word.width - word.padding - fadeWidth;\n\t\t\t\tlet timeOffset = 0;\n\t\t\t\tconst frames: Keyframe[] = [];\n\t\t\t\tlet lastPos = curPos;\n\t\t\t\tlet lastTime = 0;\n\t\t\t\tconst pushFrame = () => {\n\t\t\t\t\t// 此处如果添加过渡函数,会导致单词时序不准确,所以不添加\n\t\t\t\t\t// const easing = \"cubic-bezier(.33,.12,.83,.9)\";\n\t\t\t\t\tconst moveOffset = curPos - lastPos;\n\t\t\t\t\tconst time = clamp01(timeOffset);\n\t\t\t\t\tconst duration = time - lastTime;\n\t\t\t\t\tconst d = Math.abs(duration / moveOffset);\n\t\t\t\t\t// 因为有可能会和之前的动画有边界\n\t\t\t\t\tif (curPos > minOffset && lastPos < minOffset) {\n\t\t\t\t\t\tconst staticTime = Math.abs(lastPos - minOffset) * d;\n\t\t\t\t\t\tconst value = `${clampOffset(lastPos)}px 0`;\n\t\t\t\t\t\tconst frame: Keyframe = {\n\t\t\t\t\t\t\toffset: lastTime + staticTime,\n\t\t\t\t\t\t\tmaskPosition: value,\n\t\t\t\t\t\t};\n\t\t\t\t\t\tframes.push(frame);\n\t\t\t\t\t}\n\t\t\t\t\tif (curPos > 0 && lastPos < 0) {\n\t\t\t\t\t\tconst staticTime = Math.abs(lastPos) * d;\n\t\t\t\t\t\tconst value = `${clampOffset(curPos)}px 0`;\n\t\t\t\t\t\tconst frame: Keyframe = {\n\t\t\t\t\t\t\toffset: lastTime + staticTime,\n\t\t\t\t\t\t\tmaskPosition: value,\n\t\t\t\t\t\t};\n\t\t\t\t\t\tframes.push(frame);\n\t\t\t\t\t}\n\t\t\t\t\tconst value = `${clampOffset(curPos)}px 0`;\n\t\t\t\t\tconst frame: Keyframe = {\n\t\t\t\t\t\toffset: time,\n\t\t\t\t\t\tmaskPosition: value,\n\t\t\t\t\t};\n\t\t\t\t\tframes.push(frame);\n\t\t\t\t\tlastPos = curPos;\n\t\t\t\t\tlastTime = time;\n\t\t\t\t};\n\t\t\t\tpushFrame();\n\t\t\t\tlet lastTimeStamp = 0;\n\t\t\t\tthis.splittedWords.forEach((otherWord, j) => {\n\t\t\t\t\t// 停顿\n\t\t\t\t\t{\n\t\t\t\t\t\tconst curTimeStamp = otherWord.startTime - this.lyricLine.startTime;\n\t\t\t\t\t\tconst staticDuration = curTimeStamp - lastTimeStamp;\n\t\t\t\t\t\ttimeOffset += staticDuration / totalFadeDuration;\n\t\t\t\t\t\tif (staticDuration > 0) pushFrame();\n\t\t\t\t\t\tlastTimeStamp = curTimeStamp;\n\t\t\t\t\t}\n\t\t\t\t\t// 移动\n\t\t\t\t\t{\n\t\t\t\t\t\tconst fadeDuration = clampPositive(\n\t\t\t\t\t\t\totherWord.endTime - otherWord.startTime,\n\t\t\t\t\t\t);\n\t\t\t\t\t\tconst rubySegments = this.getRubySegments(otherWord);\n\t\t\t\t\t\tconst rubyCharCount = rubySegments.reduce(\n\t\t\t\t\t\t\t(total, ruby) => total + ruby.word.length,\n\t\t\t\t\t\t\t0,\n\t\t\t\t\t\t);\n\t\t\t\t\t\tif (rubyCharCount > 0) {\n\t\t\t\t\t\t\tconst widthPerChar = otherWord.width / rubyCharCount;\n\t\t\t\t\t\t\tlet charIndex = 0;\n\t\t\t\t\t\t\tfor (const ruby of rubySegments) {\n\t\t\t\t\t\t\t\tconst rubyStartTime = Number.isFinite(ruby.startTime)\n\t\t\t\t\t\t\t\t\t? ruby.startTime\n\t\t\t\t\t\t\t\t\t: otherWord.startTime;\n\t\t\t\t\t\t\t\tconst rubyEndTime = Number.isFinite(ruby.endTime)\n\t\t\t\t\t\t\t\t\t? ruby.endTime\n\t\t\t\t\t\t\t\t\t: otherWord.endTime;\n\t\t\t\t\t\t\t\tconst rubyStart = Math.max(rubyStartTime, otherWord.startTime);\n\t\t\t\t\t\t\t\tconst rubyEnd = Math.min(\n\t\t\t\t\t\t\t\t\tMath.max(rubyEndTime, rubyStart),\n\t\t\t\t\t\t\t\t\totherWord.endTime,\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\tconst rubyStartStamp = rubyStart - this.lyricLine.startTime;\n\t\t\t\t\t\t\t\tconst rubyStaticDuration = rubyStartStamp - lastTimeStamp;\n\t\t\t\t\t\t\t\ttimeOffset += rubyStaticDuration / totalFadeDuration;\n\t\t\t\t\t\t\t\tif (rubyStaticDuration > 0) pushFrame();\n\t\t\t\t\t\t\t\tlastTimeStamp = rubyStartStamp;\n\t\t\t\t\t\t\t\tconst rubyDuration = clampPositive(rubyEnd - rubyStart);\n\t\t\t\t\t\t\t\tconst perCharDuration = rubyDuration / ruby.word.length;\n\t\t\t\t\t\t\t\tfor (\n\t\t\t\t\t\t\t\t\tlet rubyCharIndex = 0;\n\t\t\t\t\t\t\t\t\trubyCharIndex < ruby.word.length;\n\t\t\t\t\t\t\t\t\trubyCharIndex++\n\t\t\t\t\t\t\t\t) {\n\t\t\t\t\t\t\t\t\ttimeOffset += perCharDuration / totalFadeDuration;\n\t\t\t\t\t\t\t\t\tcurPos += widthPerChar;\n\t\t\t\t\t\t\t\t\tif (j === 0 && charIndex === 0) {\n\t\t\t\t\t\t\t\t\t\tcurPos += fadeWidth * 1.5;\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\tif (\n\t\t\t\t\t\t\t\t\t\tj === this.splittedWords.length - 1 &&\n\t\t\t\t\t\t\t\t\t\tcharIndex === rubyCharCount - 1\n\t\t\t\t\t\t\t\t\t) {\n\t\t\t\t\t\t\t\t\t\tcurPos += fadeWidth * 0.5;\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\tif (perCharDuration > 0) pushFrame();\n\t\t\t\t\t\t\t\t\tlastTimeStamp += perCharDuration;\n\t\t\t\t\t\t\t\t\tcharIndex++;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tconst wordEndStamp = Math.max(\n\t\t\t\t\t\t\t\totherWord.endTime - this.lyricLine.startTime,\n\t\t\t\t\t\t\t\tlastTimeStamp,\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\tconst wordTailDuration = wordEndStamp - lastTimeStamp;\n\t\t\t\t\t\t\ttimeOffset += wordTailDuration / totalFadeDuration;\n\t\t\t\t\t\t\tif (wordTailDuration > 0) pushFrame();\n\t\t\t\t\t\t\tlastTimeStamp = wordEndStamp;\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tconst segmentCount = 1;\n\t\t\t\t\t\t\tconst segmentWidth = otherWord.width / segmentCount;\n\t\t\t\t\t\t\tconst segmentDuration = fadeDuration / segmentCount;\n\t\t\t\t\t\t\tfor (\n\t\t\t\t\t\t\t\tlet segmentIndex = 0;\n\t\t\t\t\t\t\t\tsegmentIndex < segmentCount;\n\t\t\t\t\t\t\t\tsegmentIndex++\n\t\t\t\t\t\t\t) {\n\t\t\t\t\t\t\t\ttimeOffset += segmentDuration / totalFadeDuration;\n\t\t\t\t\t\t\t\tcurPos += segmentWidth;\n\t\t\t\t\t\t\t\tif (j === 0 && segmentIndex === 0) {\n\t\t\t\t\t\t\t\t\tcurPos += fadeWidth * 1.5;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tif (\n\t\t\t\t\t\t\t\t\tj === this.splittedWords.length - 1 &&\n\t\t\t\t\t\t\t\t\tsegmentIndex === segmentCount - 1\n\t\t\t\t\t\t\t\t) {\n\t\t\t\t\t\t\t\t\tcurPos += fadeWidth * 0.5;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tif (segmentDuration > 0) pushFrame();\n\t\t\t\t\t\t\t\tlastTimeStamp += segmentDuration;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t\tfor (const a of word.maskAnimations) {\n\t\t\t\t\ta.cancel();\n\t\t\t\t}\n\t\t\t\ttry {\n\t\t\t\t\t// TODO: 如果此处动画帧计算出错,需要一个后备方案\n\t\t\t\t\t// 此处如果添加过渡函数,会导致单词时序不准确,所以不添加\n\t\t\t\t\tconst ani = wordEl.animate(frames, {\n\t\t\t\t\t\tduration: totalFadeDuration || 1,\n\t\t\t\t\t\tid: `fade-word-${word.word}-${i}`,\n\t\t\t\t\t\tfill: \"both\",\n\t\t\t\t\t});\n\t\t\t\t\tani.pause();\n\t\t\t\t\tword.maskAnimations = [ani];\n\t\t\t\t} catch (err) {\n\t\t\t\t\tconsole.warn(\"应用渐变动画发生错误\", frames, totalFadeDuration, err);\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\t}\n\tgetElement(): HTMLElement {\n\t\treturn this.element;\n\t}\n\n\tprivate updateMaskAlphaTargets(scale: number) {\n\t\tconst factor = clamp01((scale - 0.97) / 0.03);\n\t\tconst dynamicDarkAlpha = factor * 0.2 + 0.2;\n\t\tconst dynamicBrightAlpha = factor * 0.8 + 0.2;\n\n\t\tif (this.renderMode === LyricLineRenderMode.SOLID) {\n\t\t\tthis.targetBrightAlpha = dynamicDarkAlpha;\n\t\t\tthis.targetDarkAlpha = dynamicDarkAlpha;\n\t\t} else {\n\t\t\tthis.targetBrightAlpha = dynamicBrightAlpha;\n\t\t\tthis.targetDarkAlpha = dynamicDarkAlpha;\n\t\t}\n\t}\n\n\tprivate applyAlphaToDom(delta: number) {\n\t\tconst dt = delta || 0.016;\n\t\tconst ATTACK_SPEED = 50.0;\n\t\tconst RELEASE_SPEED = 7.0;\n\t\tconst getFactor = (speed: number) => 1 - Math.exp(-speed * dt);\n\n\t\t// 根据即将变亮还是变暗选择速度\n\t\t// 如果即将变亮,让速度非常快,以免播放到第一个字的时候透明度还在慢慢增加导致看不清\n\t\tconst isBrightening = this.targetBrightAlpha > this.currentBrightAlpha;\n\t\tconst brightSpeed = isBrightening ? ATTACK_SPEED : RELEASE_SPEED;\n\t\tconst brightFactor = getFactor(brightSpeed);\n\n\t\tif (Math.abs(this.targetBrightAlpha - this.currentBrightAlpha) < 0.001) {\n\t\t\tthis.currentBrightAlpha = this.targetBrightAlpha;\n\t\t} else {\n\t\t\tthis.currentBrightAlpha +=\n\t\t\t\t(this.targetBrightAlpha - this.currentBrightAlpha) * brightFactor;\n\t\t}\n\n\t\tconst isDarkening = this.targetDarkAlpha > this.currentDarkAlpha;\n\t\tconst darkSpeed = isDarkening ? ATTACK_SPEED : RELEASE_SPEED;\n\t\tconst darkFactor = getFactor(darkSpeed);\n\n\t\tif (Math.abs(this.targetDarkAlpha - this.currentDarkAlpha) < 0.001) {\n\t\t\tthis.currentDarkAlpha = this.targetDarkAlpha;\n\t\t} else {\n\t\t\tthis.currentDarkAlpha +=\n\t\t\t\t(this.targetDarkAlpha - this.currentDarkAlpha) * darkFactor;\n\t\t}\n\n\t\tthis.element.style.setProperty(\n\t\t\t\"--bright-mask-alpha\",\n\t\t\tthis.currentBrightAlpha.toFixed(3),\n\t\t);\n\t\tthis.element.style.setProperty(\n\t\t\t\"--dark-mask-alpha\",\n\t\t\tthis.currentDarkAlpha.toFixed(3),\n\t\t);\n\t}\n\n\toverride setTransform(\n\t\tscale: number = this.scale,\n\t\topacity = 1,\n\t\tblur = 0,\n\t\tforce = false,\n\t\tdelay = 0,\n\t\tmode: LyricLineRenderMode = LyricLineRenderMode.SOLID,\n\t): void {\n\t\tsuper.setTransform(scale, opacity, blur, force, delay);\n\n\t\tthis.renderMode = mode;\n\t\tconst enableSpring = this.lyricPlayer.getEnableSpring();\n\n\t\tthis.top = 0;\n\t\tthis.scale = scale;\n\t\tthis.delay = (delay * 1000) | 0;\n\n\t\tconst main = this.element.children[0] as HTMLDivElement;\n\t\tmain.style.opacity = `${opacity}`;\n\n\t\tif (force || !enableSpring) {\n\t\t\tthis.blur = Math.min(32, blur);\n\t\t\tthis.lineTransforms.scale.setPosition(scale);\n\n\t\t\tthis.rebuildStyle();\n\n\t\t\tconst currentScale = this.lineTransforms.scale.getCurrentPosition();\n\t\t\tthis.updateMaskAlphaTargets(currentScale / 100);\n\t\t\tthis.currentBrightAlpha = this.targetBrightAlpha;\n\t\t\tthis.currentDarkAlpha = this.targetDarkAlpha;\n\t\t\tthis.element.style.setProperty(\n\t\t\t\t\"--bright-mask-alpha\",\n\t\t\t\tString(this.currentBrightAlpha),\n\t\t\t);\n\t\t\tthis.element.style.setProperty(\n\t\t\t\t\"--dark-mask-alpha\",\n\t\t\t\tString(this.currentDarkAlpha),\n\t\t\t);\n\t\t} else {\n\t\t\tthis.lineTransforms.scale.setTargetPosition(scale);\n\t\t\tif (this.blur !== Math.min(5, blur)) {\n\t\t\t\tthis.blur = Math.min(5, blur);\n\t\t\t\tthis.element.style.filter = `blur(${blur.toFixed(3)}px)`;\n\t\t\t}\n\t\t}\n\t}\n\n\tupdate(delta = 0): void {\n\t\tif (!this.lyricPlayer.getEnableSpring()) return;\n\n\t\tthis.lineTransforms.scale.update(delta);\n\t\tthis.rebuildStyle();\n\n\t\tif (!this.built) return;\n\n\t\tconst currentScale = this.lineTransforms.scale.getCurrentPosition() / 100;\n\t\tthis.updateMaskAlphaTargets(currentScale);\n\t\tthis.applyAlphaToDom(delta);\n\t}\n\n\t_getDebugTargetPos(): string {\n\t\treturn `[位移: ${this.top}; 缩放: ${this.scale}; 延时: ${this.delay}]`;\n\t}\n\n\tteardownContent(): void {\n\t\tif (this.built) {\n\t\t\tthis.disposeElements();\n\t\t\tthis.built = false;\n\t\t}\n\t}\n\n\tprivate disposeElements() {\n\t\tthis.balancer?.reset();\n\t\tfor (const realWord of this.splittedWords) {\n\t\t\tfor (const a of realWord.elementAnimations) {\n\t\t\t\ta.cancel();\n\t\t\t}\n\t\t\tfor (const a of realWord.maskAnimations) {\n\t\t\t\ta.cancel();\n\t\t\t}\n\t\t\tfor (const sub of realWord.subElements) {\n\t\t\t\tsub.remove();\n\t\t\t\tsub.parentNode?.removeChild(sub);\n\t\t\t}\n\t\t\trealWord.elementAnimations = [];\n\t\t\trealWord.maskAnimations = [];\n\t\t\trealWord.subElements = [];\n\t\t\tif (realWord.mainElement?.parentNode) {\n\t\t\t\trealWord.mainElement.parentNode.removeChild(realWord.mainElement);\n\t\t\t}\n\t\t}\n\t\tthis.splittedWords = [];\n\t\tconst main = this.element.children[0] as HTMLDivElement;\n\t\tconst trans = this.element.children[1] as HTMLDivElement;\n\t\tconst roman = this.element.children[2] as HTMLDivElement;\n\t\tif (main) main.innerHTML = \"\";\n\t\tif (trans) trans.innerHTML = \"\";\n\t\tif (roman) roman.innerHTML = \"\";\n\t}\n\toverride dispose(): void {\n\t\tthis.disposeElements();\n\t\tthis.lyricPlayer.resizeObserver.unobserve(this.element);\n\t\tthis.element.remove();\n\t}\n}\n","/**\n * @fileoverview\n * 一个播放歌词的组件\n * @author SteveXMH\n */\n\nimport type { LyricLine } from \"#interfaces\";\nimport \"#styles/index.css\";\nimport { LyricPlayerBase } from \"#lyric/base/index.ts\";\nimport type { LyricLineBase } from \"#lyric/base/line.ts\";\nimport styles from \"#styles/lyric-player.module.css\";\nimport { LyricLineGroup } from \"./lyric-group.ts\";\nimport { LyricLineEl, type RawLyricLineMouseEvent } from \"./lyric-line.ts\";\n\n/**\n * 歌词行鼠标相关事件,可以获取到歌词行的索引和歌词行元素\n */\nexport class LyricLineMouseEvent extends MouseEvent {\n\tconstructor(\n\t\t/**\n\t\t * 歌词行索引\n\t\t */\n\t\tpublic readonly lineIndex: number,\n\t\t/**\n\t\t * 歌词行元素\n\t\t */\n\t\tpublic readonly line: LyricLineBase,\n\t\tevent: MouseEvent,\n\t) {\n\t\tsuper(`line-${event.type}`, event);\n\t}\n}\n\nexport type LyricLineMouseEventListener = (evt: LyricLineMouseEvent) => void;\n\n/**\n * 歌词播放组件,本框架的核心组件\n *\n * 尽可能贴切 Apple Music for iPad 的歌词效果设计,且做了力所能及的优化措施\n */\nexport class DomLyricPlayer extends LyricPlayerBase {\n\toverride currentLyricGroups: LyricLineGroup[] = [];\n\n\toverride onResize(): void {\n\t\tconst computedStyles = getComputedStyle(this.element);\n\t\tthis._baseFontSize = Number.parseFloat(computedStyles.fontSize);\n\t\tthis.rebuildStyle();\n\t}\n\n\treadonly supportPlusLighter: boolean = CSS.supports(\n\t\t\"mix-blend-mode\",\n\t\t\"plus-lighter\",\n\t);\n\treadonly supportMaskImage: boolean = CSS.supports(\"mask-image\", \"none\");\n\treadonly innerSize: [number, number] = [0, 0];\n\tprivate readonly onLineClickedHandler = (e: RawLyricLineMouseEvent) => {\n\t\tconst evt = new LyricLineMouseEvent(\n\t\t\tthis.lyricLinesIndexes.get(e.line) ?? -1,\n\t\t\te.line,\n\t\t\te,\n\t\t);\n\t\tif (!this.dispatchEvent(evt)) {\n\t\t\te.preventDefault();\n\t\t\te.stopPropagation();\n\t\t\te.stopImmediatePropagation();\n\t\t}\n\t};\n\t/**\n\t * 是否为非逐词歌词\n\t * @internal\n\t */\n\t_getIsNonDynamic(): boolean {\n\t\treturn this.isNonDynamic;\n\t}\n\tprivate _baseFontSize = Number.parseFloat(\n\t\tgetComputedStyle(this.element).fontSize,\n\t);\n\tpublic get baseFontSize(): number {\n\t\treturn this._baseFontSize;\n\t}\n\tconstructor() {\n\t\tsuper();\n\t\tthis.onResize();\n\t\tthis.element.classList.add(\"amll-lyric-player\", \"dom\");\n\t\tif (this.disableSpring) {\n\t\t\tthis.element.classList.add(styles.disableSpring);\n\t\t}\n\t}\n\n\tprivate rebuildStyle() {\n\t\t// const width = this.innerSize[0];\n\t\t// const height = this.innerSize[1];\n\t\t// this.element.style.setProperty(\"--amll-lp-width\", `${width.toFixed(4)}px`);\n\t\t// this.element.style.setProperty(\n\t\t// \t\"--amll-lp-height\",\n\t\t// \t`${height.toFixed(4)}px`,\n\t\t// );\n\t}\n\n\toverride setWordFadeWidth(value = 0.5): void {\n\t\tsuper.setWordFadeWidth(value);\n\t\tfor (const group of this.currentLyricGroups) {\n\t\t\tgroup.mainLine.updateMaskImageSync();\n\t\t\tgroup.bgLine?.updateMaskImageSync();\n\t\t}\n\t}\n\n\t/**\n\t * 设置当前播放歌词,要注意传入后这个数组内的信息不得修改,否则会发生错误\n\t * @param lines 歌词数组\n\t * @param initialTime 初始时间,默认为 0\n\t */\n\toverride setLyricLines(lines: LyricLine[], initialTime = 0): void {\n\t\tsuper.setLyricLines(lines, initialTime);\n\t\tif (this.hasDuetLine) {\n\t\t\tthis.element.classList.add(styles.hasDuetLine);\n\t\t} else {\n\t\t\tthis.element.classList.remove(styles.hasDuetLine);\n\t\t}\n\t\tif (!this.supportMaskImage) {\n\t\t\tthis.element.style.setProperty(\"--amll-player-time\", `${initialTime}`);\n\t\t}\n\n\t\tfor (const group of this.currentLyricGroups) {\n\t\t\tconst linesToDispose = [group.mainLine, group.bgLine].filter(\n\t\t\t\t(line) => !!line,\n\t\t\t);\n\n\t\t\tfor (const line of linesToDispose) {\n\t\t\t\tline.removeMouseEventListener(\"click\", this.onLineClickedHandler);\n\t\t\t\tline.removeMouseEventListener(\"contextmenu\", this.onLineClickedHandler);\n\t\t\t}\n\t\t\tgroup.dispose();\n\t\t}\n\t\tthis.currentLyricGroups = [];\n\n\t\tlet currentGroup: LyricLineGroup | null = null;\n\n\t\tfor (let i = 0; i < this.processedLines.length; i++) {\n\t\t\tconst line = this.processedLines[i];\n\t\t\tconst lineEl = new LyricLineEl(this, line);\n\n\t\t\tlineEl.addMouseEventListener(\"click\", this.onLineClickedHandler);\n\t\t\tlineEl.addMouseEventListener(\"contextmenu\", this.onLineClickedHandler);\n\n\t\t\tthis.lyricLinesIndexes.set(lineEl, i);\n\n\t\t\tif (!line.isBG || !currentGroup) {\n\t\t\t\tcurrentGroup = new LyricLineGroup(this, lineEl);\n\t\t\t\tthis.currentLyricGroups.push(currentGroup);\n\t\t\t\tthis.lyricGroupElementMap.set(currentGroup.element, currentGroup);\n\t\t\t} else {\n\t\t\t\tcurrentGroup.addBgLine(lineEl);\n\t\t\t}\n\t\t}\n\n\t\tthis.setLinePosXSpringParams({});\n\t\tthis.setLinePosYSpringParams({});\n\t\tthis.setLineScaleSpringParams({});\n\t\tthis.setCurrentTime(initialTime, true);\n\t\tthis.calcLayout(true);\n\t\tthis.update(0);\n\t}\n\n\toverride pause(): void {\n\t\tsuper.pause();\n\t\tthis.element.classList.remove(styles.playing);\n\t\tthis.interludeDots.pause();\n\t\tfor (const group of this.currentLyricGroups) {\n\t\t\tgroup.mainLine.pause();\n\t\t\tgroup.bgLine?.pause();\n\t\t}\n\t}\n\n\toverride resume(): void {\n\t\tsuper.resume();\n\t\tthis.element.classList.add(styles.playing);\n\t\tthis.interludeDots.resume();\n\t\tfor (const group of this.currentLyricGroups) {\n\t\t\tgroup.mainLine.resume();\n\t\t\tgroup.bgLine?.resume();\n\t\t}\n\t}\n\n\toverride update(delta = 0): void {\n\t\tif (!this.timelineState.initialLayoutFinished) return;\n\t\tsuper.update(delta);\n\t\tif (!this.supportMaskImage) {\n\t\t\tthis.element.style.setProperty(\n\t\t\t\t\"--amll-player-time\",\n\t\t\t\t`${this.timelineState.currentTime}`,\n\t\t\t);\n\t\t}\n\t\tif (!this.isPageVisible) return;\n\t\tconst deltaS = delta / 1000;\n\t\tfor (const group of this.currentLyricGroups) {\n\t\t\tgroup.update(deltaS);\n\t\t}\n\t}\n\n\toverride dispose(): void {\n\t\tsuper.dispose();\n\t\tthis.element.remove();\n\t\tfor (const group of this.currentLyricGroups) {\n\t\t\tgroup.dispose();\n\t\t}\n\t\tthis.bottomLine.dispose();\n\t\tthis.interludeDots.dispose();\n\t}\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"amll-core.mjs","names":["isolationVertShader","isolationFragShader","meshVertShader","meshFragShader","exhaustiveCheck","styles","styles","styles","styles","styles","styles"],"sources":["../src/bg-render/base.ts","../src/bg-render/gl-program.ts","../src/utils/resource.ts","../src/bg-render/palette/color-utilities.ts","../src/bg-render/palette/kmeans.ts","../src/bg-render/palette/octtree.ts","../src/bg-render/palette/auto.ts","../src/utils/canvas.ts","../src/bg-render/palette/histogram.ts","../src/bg-render/palette/index.ts","../src/bg-render/support.ts","../src/bg-render/isolation/index.ts","../src/utils/clamp.ts","../src/bg-render/img.ts","../src/bg-render/mesh-renderer/cp-presets.ts","../src/bg-render/mesh-renderer/cp-generate.ts","../src/bg-render/mesh-renderer/index.ts","../src/bg-render/pixi-renderer.ts","../src/bg-render/index.ts","../src/utils/time.ts","../src/lyric-player/base/consts.ts","../src/styles/lyric-player.module.css","../src/utils/optimize-lyric.ts","../src/lyric-player/base/focus.ts","../src/lyric-player/base/layout.ts","../src/utils/validate-lyric.ts","../src/lyric-player/base/lyric-data-manager.ts","../src/lyric-player/base/scroll.ts","../src/lyric-player/base/seek-detector.ts","../src/lyric-player/base/spring.ts","../src/lyric-player/base/timeline.ts","../src/lyric-player/base/index.ts","../src/utils/derivative.ts","../src/utils/spring.ts","../src/lyric-player/dom/bottom-line.ts","../src/lyric-player/base/interlude-dots.ts","../src/lyric-player/dom/interlude-dots.ts","../src/lyric-player/base/group.ts","../src/lyric-player/dom/lyric-group.ts","../src/utils/is-cjk.ts","../src/lyric-player/base/line.ts","../src/utils/lyric-line-break.ts","../src/utils/line-balancer.ts","../src/utils/lyric-split-words.ts","../src/utils/matrix.ts","../src/lyric-player/dom/animation/emphasize/index.ts","../src/lyric-player/dom/animation/float/index.ts","../src/lyric-player/dom/animation/mask/utils.ts","../src/lyric-player/dom/animation/mask/animator-calc.ts","../src/lyric-player/dom/animation/mask/animator-web.ts","../src/lyric-player/dom/animation/mask/index.ts","../src/lyric-player/dom/lyric-line.ts","../src/lyric-player/dom/index.ts"],"sourcesContent":["import type { Disposable, HasElement } from \"../interfaces.ts\";\n\nexport abstract class AbstractBaseRenderer implements Disposable, HasElement {\n\t/**\n\t * 修改背景的流动速度,数字越大越快,默认为 8\n\t * @param speed 背景的流动速度,默认为 8\n\t */\n\tabstract setFlowSpeed(speed: number): void;\n\t/**\n\t * 修改背景的渲染比例,默认是 0.5\n\t *\n\t * 一般情况下这个程度既没有明显瑕疵也不会特别吃性能\n\t * @param scale 背景的渲染比例\n\t */\n\tabstract setRenderScale(scale: number): void;\n\t/**\n\t * 是否启用静态模式,即图片在更换后就会保持静止状态并禁用更新,以节省性能\n\t * @param enable 是否启用静态模式\n\t */\n\tabstract setStaticMode(enable: boolean): void;\n\t/**\n\t * 修改背景动画帧率,默认是 30 FPS\n\t *\n\t * 如果设置成 0 则会停止动画\n\t * @param fps 目标帧率,默认 30 FPS\n\t */\n\tabstract setFPS(fps: number): void;\n\t/**\n\t * 暂停背景动画,画面即便是更新了图片也不会发生变化\n\t */\n\tabstract pause(): void;\n\t/**\n\t * 恢复播放背景动画\n\t */\n\tabstract resume(): void;\n\t/**\n\t * 设置背景专辑资源,纹理加载并设置完成后会返回\n\t * @param albumSource 专辑的资源链接,可以是图片或视频链接,抑或是任意 img/video 元素,如果提供字符串链接且为视频则需要指定第二个参数\n\t */\n\tabstract setAlbum(\n\t\talbumSource: string | HTMLImageElement | HTMLVideoElement,\n\t\tisVideo?: boolean,\n\t): Promise<void>;\n\t/**\n\t * 设置低频的音量大小,范围在 80hz-120hz 之间为宜,取值范围在 [0.0-1.0] 之间\n\t *\n\t * 部分渲染器会根据音量大小调整背景效果(例如根据鼓点跳动)\n\t *\n\t * 如果无法获取到类似的数据,请传入 1.0 作为默认值,或不做任何处理(默认值即 1.0)\n\t * @param volume 低频的音量大小,范围在 50hz-120hz 之间为宜,取值范围在 [0.0-1.0] 之间\n\t */\n\tabstract setLowFreqVolume(volume: number): void;\n\t/**\n\t * 设置背景是否根据“是否有歌词”这个特征调整自身效果,例如有歌词时会变得更加活跃\n\t *\n\t * 部分渲染器会根据这个特征调整自身效果\n\t *\n\t * 如果不确定是否需要赋值或无法知晓是否包含歌词,请传入 true 或不做任何处理(默认值为 true)\n\t *\n\t * @param hasLyric 是否有歌词,如不确定是否需要赋值,请传入 true 或不做任何处理(默认值为 true)\n\t */\n\tabstract setHasLyric(hasLyric: boolean): void;\n\tabstract dispose(): void;\n\tabstract getElement(): HTMLElement;\n}\n\nfunction clamp1(x: number): number {\n\treturn Math.max(1, x);\n}\n\nexport abstract class BaseRenderer extends AbstractBaseRenderer {\n\tprivate observer: ResizeObserver;\n\tprotected flowSpeed = 1;\n\tprotected currerntRenderScale = 0.75;\n\tconstructor(protected canvas: HTMLCanvasElement) {\n\t\tsuper();\n\t\tthis.observer = new ResizeObserver(() => {\n\t\t\tconst width = clamp1(\n\t\t\t\tcanvas.clientWidth * window.devicePixelRatio * this.currerntRenderScale,\n\t\t\t);\n\t\t\tconst height = clamp1(\n\t\t\t\tcanvas.clientHeight *\n\t\t\t\t\twindow.devicePixelRatio *\n\t\t\t\t\tthis.currerntRenderScale,\n\t\t\t);\n\t\t\tthis.onResize(width, height);\n\t\t});\n\t\tthis.observer.observe(canvas);\n\t}\n\tsetRenderScale(scale: number): void {\n\t\tthis.currerntRenderScale = scale;\n\t\tthis.onResize(\n\t\t\tthis.canvas.clientWidth *\n\t\t\t\twindow.devicePixelRatio *\n\t\t\t\tthis.currerntRenderScale,\n\t\t\tthis.canvas.clientHeight *\n\t\t\t\twindow.devicePixelRatio *\n\t\t\t\tthis.currerntRenderScale,\n\t\t);\n\t}\n\t/**\n\t * 当画板元素大小发生变化时此函数会被调用\n\t * 可以在此处重设和渲染器相关的尺寸设置\n\t * 考虑到初始化的时候元素不一定在文档中或出于某些特殊样式状态,尺寸长宽有可能会为 0,请注意进行特判处理\n\t * @param width 画板元素实际的物理像素宽度,有可能为 0\n\t * @param height 画板元素实际的物理像素高度,有可能为 0\n\t */\n\tprotected onResize(width: number, height: number): void {\n\t\tthis.canvas.width = width;\n\t\tthis.canvas.height = height;\n\t}\n\t/**\n\t * 修改背景的流动速度,数字越大越快,默认为 1\n\t * @param speed 背景的流动速度,默认为 1\n\t */\n\tsetFlowSpeed(speed: number): void {\n\t\tthis.flowSpeed = speed;\n\t}\n\t/**\n\t * 是否启用静态模式,即图片在更换后就会保持静止状态并禁用更新,以节省性能\n\t * @param enable 是否启用静态模式\n\t */\n\tabstract override setStaticMode(enable: boolean): void;\n\t/**\n\t * 修改背景动画帧率,默认是 30 FPS\n\t *\n\t * 如果设置成 0 则会停止动画\n\t * @param fps 目标帧率,默认 30 FPS\n\t */\n\tabstract override setFPS(fps: number): void;\n\t/**\n\t * 暂停背景动画,画面即便是更新了图片也不会发生变化\n\t */\n\tabstract override pause(): void;\n\t/**\n\t * 恢复播放背景动画\n\t */\n\tabstract override resume(): void;\n\t/**\n\t * 设置背景专辑资源,纹理加载并设置完成后会返回\n\t * @param albumSource 专辑的资源链接,可以是图片或视频链接,抑或是任意 img/video 元素,如果提供字符串链接且为视频则需要指定第二个参数\n\t */\n\tabstract override setAlbum(\n\t\talbumSource: string | HTMLImageElement | HTMLVideoElement,\n\t\tisVideo?: boolean,\n\t): Promise<void>;\n\t/** 停止监听画板尺寸,供构造失败等尚未接管画板所有权的路径清理 */\n\tprotected disconnectResizeObserver(): void {\n\t\tthis.observer.disconnect();\n\t}\n\tdispose(): void {\n\t\tthis.disconnectResizeObserver();\n\t\tthis.canvas.remove();\n\t}\n\toverride getElement(): HTMLElement {\n\t\treturn this.canvas;\n\t}\n}\n","import type { Disposable } from \"../interfaces.ts\";\n\n/**\n * 着色器程序可用的渲染上下文。\n *\n * 目前的背景渲染器以 WebGL1 为主,但这个封装本身不依赖特定版本,所以两者\n * 都接受。\n */\nexport type GLRenderingContext = WebGLRenderingContext | WebGL2RenderingContext;\n\n/**\n * 对 WebGL 着色器程序的一层薄封装,负责编译、链接、缓存 uniform 位置。\n */\nexport class GLProgram implements Disposable {\n\tprivate gl: GLRenderingContext;\n\tprogram: WebGLProgram;\n\tprivate vertexShader: WebGLShader;\n\tprivate fragmentShader: WebGLShader;\n\treadonly attrs: { [name: string]: number };\n\tprivate uniformLocations = new Map<string, WebGLUniformLocation | null>();\n\tconstructor(\n\t\tgl: GLRenderingContext,\n\t\tvertexShaderSource: string,\n\t\tfragmentShaderSource: string,\n\t\tprivate readonly label = \"unknown\",\n\t) {\n\t\tthis.gl = gl;\n\t\tconst vertexShader = this.createShader(\n\t\t\tgl.VERTEX_SHADER,\n\t\t\tvertexShaderSource,\n\t\t);\n\t\tlet fragmentShader: WebGLShader | undefined;\n\t\ttry {\n\t\t\tfragmentShader = this.createShader(\n\t\t\t\tgl.FRAGMENT_SHADER,\n\t\t\t\tfragmentShaderSource,\n\t\t\t);\n\t\t\tthis.program = this.createProgram(vertexShader, fragmentShader);\n\t\t} catch (error) {\n\t\t\tgl.deleteShader(vertexShader);\n\t\t\tif (fragmentShader) gl.deleteShader(fragmentShader);\n\t\t\tthrow error;\n\t\t}\n\t\tthis.vertexShader = vertexShader;\n\t\tthis.fragmentShader = fragmentShader;\n\n\t\tconst num = gl.getProgramParameter(this.program, gl.ACTIVE_ATTRIBUTES);\n\t\tconst attrs: { [name: string]: number } = {};\n\t\tfor (let i = 0; i < num; i++) {\n\t\t\tconst info = gl.getActiveAttrib(this.program, i);\n\t\t\tif (!info) continue;\n\t\t\tconst location = gl.getAttribLocation(this.program, info.name);\n\t\t\tif (location === -1) continue;\n\t\t\tattrs[info.name] = location;\n\t\t}\n\t\tthis.attrs = attrs;\n\t}\n\tprivate createShader(type: number, source: string): WebGLShader {\n\t\tconst gl = this.gl;\n\t\tconst shader = gl.createShader(type);\n\t\tif (!shader) throw new Error(\"Failed to create shader\");\n\t\tgl.shaderSource(shader, source);\n\t\tgl.compileShader(shader);\n\t\tif (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {\n\t\t\tconst error = new Error(\n\t\t\t\t`Failed to compile shader for type ${type} \"${\n\t\t\t\t\tthis.label\n\t\t\t\t}\": ${gl.getShaderInfoLog(shader)}`,\n\t\t\t);\n\t\t\tgl.deleteShader(shader);\n\t\t\tthrow error;\n\t\t}\n\t\treturn shader;\n\t}\n\tprivate createProgram(\n\t\tvertexShader: WebGLShader,\n\t\tfragmentShader: WebGLShader,\n\t): WebGLProgram {\n\t\tconst gl = this.gl;\n\t\tconst program = gl.createProgram();\n\t\tif (!program) throw new Error(\"Failed to create program\");\n\t\tgl.attachShader(program, vertexShader);\n\t\tgl.attachShader(program, fragmentShader);\n\t\tgl.linkProgram(program);\n\t\tif (!gl.getProgramParameter(program, gl.LINK_STATUS)) {\n\t\t\tconst errLog = gl.getProgramInfoLog(program);\n\t\t\tgl.deleteProgram(program);\n\t\t\tthrow new Error(`Failed to link program \"${this.label}\": ${errLog}`);\n\t\t}\n\t\treturn program;\n\t}\n\tuse(): void {\n\t\tconst gl = this.gl;\n\t\tgl.useProgram(this.program);\n\t}\n\tprivate notFoundUniforms: Set<string> = new Set();\n\tprivate warnUniformNotFound(name: string): void {\n\t\tif (this.notFoundUniforms.has(name)) return;\n\t\tthis.notFoundUniforms.add(name);\n\t\tconsole.warn(\n\t\t\t`Failed to get uniform location for program \"${this.label}\": ${name}`,\n\t\t);\n\t}\n\t/**\n\t * 取 uniform 位置并缓存。逐帧设置几十个 uniform 时,省下的\n\t * `getUniformLocation` 调用相当可观。\n\t */\n\tprivate getUniformLocation(name: string): WebGLUniformLocation | null {\n\t\tlet location = this.uniformLocations.get(name);\n\t\tif (location === undefined) {\n\t\t\tlocation = this.gl.getUniformLocation(this.program, name);\n\t\t\tthis.uniformLocations.set(name, location);\n\t\t}\n\t\tif (location === null) this.warnUniformNotFound(name);\n\t\treturn location;\n\t}\n\tsetUniform1f(name: string, value: number): void {\n\t\tconst location = this.getUniformLocation(name);\n\t\tif (location !== null) this.gl.uniform1f(location, value);\n\t}\n\tsetUniform2f(name: string, value1: number, value2: number): void {\n\t\tconst location = this.getUniformLocation(name);\n\t\tif (location !== null) this.gl.uniform2f(location, value1, value2);\n\t}\n\tsetUniform3f(\n\t\tname: string,\n\t\tvalue1: number,\n\t\tvalue2: number,\n\t\tvalue3: number,\n\t): void {\n\t\tconst location = this.getUniformLocation(name);\n\t\tif (location !== null) this.gl.uniform3f(location, value1, value2, value3);\n\t}\n\tsetUniform4f(\n\t\tname: string,\n\t\tvalue1: number,\n\t\tvalue2: number,\n\t\tvalue3: number,\n\t\tvalue4: number,\n\t): void {\n\t\tconst location = this.getUniformLocation(name);\n\t\tif (location !== null)\n\t\t\tthis.gl.uniform4f(location, value1, value2, value3, value4);\n\t}\n\tsetUniform1i(name: string, value: number): void {\n\t\tconst location = this.getUniformLocation(name);\n\t\tif (location !== null) this.gl.uniform1i(location, value);\n\t}\n\tsetUniform1fv(name: string, value: Float32Array): void {\n\t\tconst location = this.getUniformLocation(name);\n\t\tif (location !== null) this.gl.uniform1fv(location, value);\n\t}\n\tsetUniform3fv(name: string, value: Float32Array): void {\n\t\tconst location = this.getUniformLocation(name);\n\t\tif (location !== null) this.gl.uniform3fv(location, value);\n\t}\n\tdispose(): void {\n\t\tconst gl = this.gl;\n\t\tgl.deleteShader(this.vertexShader);\n\t\tgl.deleteShader(this.fragmentShader);\n\t\tgl.deleteProgram(this.program);\n\t\tthis.uniformLocations.clear();\n\t}\n}\n","export function loadImage(imageUrl: string): Promise<HTMLImageElement> {\n\treturn new Promise((resolve, reject) => {\n\t\tconst img = document.createElement(\"img\");\n\t\timg.onload = () => resolve(img);\n\t\timg.onerror = reject;\n\t\timg.src = imageUrl;\n\t\timg.crossOrigin = \"anonymous\";\n\t\timg.loading = \"eager\";\n\t});\n}\n\nexport function loadVideo(videoUrl: string): Promise<HTMLVideoElement> {\n\treturn new Promise((resolve, reject) => {\n\t\tconst video = document.createElement(\"video\");\n\t\tlet playing = false;\n\t\tlet timeupdate = false;\n\t\tlet rejected = false;\n\t\tvideo.addEventListener(\n\t\t\t\"playing\",\n\t\t\t() => {\n\t\t\t\tplaying = true;\n\t\t\t\tcheckReady();\n\t\t\t},\n\t\t\ttrue,\n\t\t);\n\t\tvideo.addEventListener(\n\t\t\t\"timeupdate\",\n\t\t\t() => {\n\t\t\t\ttimeupdate = true;\n\t\t\t\tcheckReady();\n\t\t\t},\n\t\t\ttrue,\n\t\t);\n\t\tvideo.addEventListener(\n\t\t\t\"error\",\n\t\t\t(err) => {\n\t\t\t\trejected = true;\n\t\t\t\treject(err);\n\t\t\t},\n\t\t\ttrue,\n\t\t);\n\t\tfunction checkReady() {\n\t\t\tif (playing && timeupdate && !rejected) {\n\t\t\t\tresolve(video);\n\t\t\t}\n\t\t}\n\t\tvideo.src = videoUrl;\n\t\tvideo.playsInline = true;\n\t\tvideo.crossOrigin = \"anonymous\";\n\t\tvideo.autoplay = true;\n\t\tvideo.loop = true;\n\t\tvideo.muted = true;\n\t\tvideo.play();\n\t});\n}\n\nexport function loadResourceFromUrl(\n\turl: string,\n\tisVideo = false,\n): Promise<HTMLImageElement | HTMLVideoElement> {\n\treturn isVideo ? loadVideo(url) : loadImage(url);\n}\n\nexport function loadResourceFromElement(\n\telement: HTMLImageElement | HTMLVideoElement,\n): Promise<HTMLImageElement | HTMLVideoElement> {\n\treturn new Promise((resolve, reject) => {\n\t\tif (\n\t\t\telement instanceof HTMLImageElement\n\t\t\t\t? element.complete\n\t\t\t\t: element.readyState >= 3\n\t\t) {\n\t\t\tresolve(element);\n\t\t} else {\n\t\t\telement.onload = () => resolve(element);\n\t\t\telement.onerror = reject;\n\t\t}\n\t});\n}\n","/**\n * @fileoverview\n * 色彩空间转换与明暗判定。\n *\n * 逐行移植自 Storyteller-Studios/Impressionist(MIT)的\n * `Impressionist/Implementations/ColorUtilities.cs`。\n *\n * @see https://github.com/Storyteller-Studios/Impressionist/blob/master/Impressionist/Implementations/ColorUtilities.cs\n */\n\nimport type { ColorVec3, HSVColor } from \"./types.ts\";\n\nexport function rgbToHsv(color: ColorVec3): HSVColor {\n\tconst [r, g, b] = color;\n\tconst max = Math.max(r, g, b);\n\tconst min = Math.min(r, g, b);\n\n\tconst v = (max * 100) / 255;\n\tif (max === min) return { h: 0, s: 0, v };\n\n\tconst s = ((max - min) / max) * 100;\n\tlet h = 0;\n\tif (max === r) {\n\t\th = (60 * (g - b)) / (max - min);\n\t} else if (max === g) {\n\t\th = 60 * (2 + (b - r) / (max - min));\n\t} else {\n\t\th = 60 * (4 + (r - g) / (max - min));\n\t}\n\tif (h < 0) h += 360;\n\treturn { h, s, v };\n}\n\nexport function hsvToRgb(hsv: HSVColor): ColorVec3 {\n\tconst h = hsv.h === 360 ? 0 : hsv.h;\n\tconst hi = Math.floor(h / 60) % 6;\n\tconst f = h / 60 - hi;\n\tconst p = (hsv.v / 100) * (1 - hsv.s / 100) * 255;\n\tconst q = (hsv.v / 100) * (1 - f * (hsv.s / 100)) * 255;\n\tconst t = (hsv.v / 100) * (1 - (1 - f) * (hsv.s / 100)) * 255;\n\tconst v = (hsv.v * 255) / 100;\n\n\tconst rgbLookup: readonly ColorVec3[] = [\n\t\t[v, t, p],\n\t\t[q, v, p],\n\t\t[p, v, t],\n\t\t[p, q, v],\n\t\t[t, p, v],\n\t\t[v, p, q],\n\t];\n\treturn rgbLookup[hi] ?? [v, p, q];\n}\n\nexport function rgbToXyz(rgb: ColorVec3): ColorVec3 {\n\tconst [red, green, blue] = rgb;\n\tconst r = red / 255;\n\tconst g = green / 255;\n\tconst b = blue / 255;\n\treturn [\n\t\tr * 0.4124 + g * 0.3576 + b * 0.1805,\n\t\tr * 0.2126 + g * 0.7152 + b * 0.0722,\n\t\tr * 0.0193 + g * 0.1192 + b * 0.9505,\n\t];\n}\n\nexport function xyzToRgb(xyz: ColorVec3): ColorVec3 {\n\tconst [x, y, z] = xyz;\n\treturn [\n\t\t(x * 3.2406 - y * 1.5372 - z * 0.4986) * 255,\n\t\t(-x * 0.9689 + y * 1.8758 + z * 0.0415) * 255,\n\t\t(x * 0.0557 - y * 0.204 + z * 1.057) * 255,\n\t];\n}\n\n/** D65 标准光源的白点。 */\nconst D65 = {\n\tx: 0.95047,\n\ty: 1.0,\n\tz: 1.0883,\n} as const;\n\nfunction fxyz(t: number): number {\n\treturn t > 0.008856 ? Math.cbrt(t) : 7.787 * t + 16 / 116;\n}\n\nexport function xyzToLab(xyz: ColorVec3): ColorVec3 {\n\tconst [x, y, z] = xyz;\n\treturn [\n\t\t116 * fxyz(y / D65.y) - 16,\n\t\t500 * (fxyz(x / D65.x) - fxyz(y / D65.y)),\n\t\t200 * (fxyz(y / D65.y) - fxyz(z / D65.z)),\n\t];\n}\n\nexport function labToXyz(lab: ColorVec3): ColorVec3 {\n\tconst delta = 6 / 29;\n\tconst [l, a, b] = lab;\n\tconst fy = (l + 16) / 116;\n\tconst fx = fy + a / 500;\n\tconst fz = fy - b / 200;\n\treturn [\n\t\tfx > delta\n\t\t\t? D65.x * fx * fx * fx\n\t\t\t: (fx - 16 / 116) * 3 * delta * delta * D65.x,\n\t\tfy > delta\n\t\t\t? D65.y * fy * fy * fy\n\t\t\t: (fy - 16 / 116) * 3 * delta * delta * D65.y,\n\t\tfz > delta\n\t\t\t? D65.z * fz * fz * fz\n\t\t\t: (fz - 16 / 116) * 3 * delta * delta * D65.z,\n\t];\n}\n\nexport function rgbToLab(rgb: ColorVec3): ColorVec3 {\n\treturn xyzToLab(rgbToXyz(rgb));\n}\n\nexport function labToRgb(lab: ColorVec3): ColorVec3 {\n\treturn xyzToRgb(labToXyz(lab));\n}\n\nexport function channelToLinear(value: number): number {\n\treturn value <= 0.04045 ? value / 12.92 : ((value + 0.055) / 1.055) ** 2.4;\n}\n\n/**\n * 把 sRGB 颜色转换到 OkLab。\n *\n * 与本文件其它函数不同,入参与返回的分量取值均为 [0, 1]:OkLab 的矩阵本就定义\n * 在归一化的线性 sRGB 上,没必要为了统一风格多做一次 255 的往返。\n *\n * OkLab 是感知均匀的,在它里面对两个颜色取中点不会像 sRGB 那样发暗发浊,所以\n * 需要混色或者做颜色过渡的地方应当先转到这里来。\n *\n * @see https://bottosson.github.io/posts/oklab/\n */\nexport function srgbToOkLab(rgb: ColorVec3): ColorVec3 {\n\tconst [red, green, blue] = rgb;\n\tconst linearRed = channelToLinear(red);\n\tconst linearGreen = channelToLinear(green);\n\tconst linearBlue = channelToLinear(blue);\n\tconst l = Math.cbrt(\n\t\t0.4122214708 * linearRed +\n\t\t\t0.5363325363 * linearGreen +\n\t\t\t0.0514459929 * linearBlue,\n\t);\n\tconst m = Math.cbrt(\n\t\t0.2119034982 * linearRed +\n\t\t\t0.6806995451 * linearGreen +\n\t\t\t0.1073969566 * linearBlue,\n\t);\n\tconst s = Math.cbrt(\n\t\t0.0883024619 * linearRed +\n\t\t\t0.2817188376 * linearGreen +\n\t\t\t0.6299787005 * linearBlue,\n\t);\n\treturn [\n\t\t0.2104542553 * l + 0.793617785 * m - 0.0040720468 * s,\n\t\t1.9779984951 * l - 2.428592205 * m + 0.4505937099 * s,\n\t\t0.0259040371 * l + 0.7827717662 * m - 0.808675766 * s,\n\t];\n}\n\nexport function yToLStar(y: number): number {\n\t// CIE 标准写的是 0.008856 与 903.3,但 216/24389 和 24389/27 才是其本意\n\tif (y <= 216 / 24389) return y * (24389 / 27);\n\treturn Math.cbrt(y) * 116 - 16;\n}\n\nfunction lStar(rgb: ColorVec3): number {\n\tconst [r, g, b] = rgb;\n\tconst y =\n\t\t0.2126 * channelToLinear(r / 255) +\n\t\t0.7152 * channelToLinear(g / 255) +\n\t\t0.0722 * channelToLinear(b / 255);\n\treturn yToLStar(y);\n}\n\n/** 调色板取色时判定「暗色候选」的阈值,比主题色判定更严格。 */\nexport function paletteRgbLStarIsDark(rgb: ColorVec3): boolean {\n\treturn lStar(rgb) <= 40;\n}\n\n/** 调色板取色时判定「亮色候选」的阈值。 */\nexport function paletteRgbLStarIsLight(rgb: ColorVec3): boolean {\n\treturn lStar(rgb) >= 60;\n}\n\n/** 主题色的明暗判定。 */\nexport function rgbLStarIsDark(rgb: ColorVec3): boolean {\n\treturn lStar(rgb) <= 50;\n}\n\n/** 两个颜色向量的欧氏距离平方。 */\nexport function distanceSquared(a: ColorVec3, b: ColorVec3): number {\n\tconst [ax, ay, az] = a;\n\tconst [bx, by, bz] = b;\n\tconst dx = ax - bx;\n\tconst dy = ay - by;\n\tconst dz = az - bz;\n\treturn dx * dx + dy * dy + dz * dz;\n}\n","/**\n * @fileoverview\n * K-Means 取色器。\n *\n * 逐行移植自 Storyteller-Studios/Impressionist(MIT)的\n * `Impressionist/Implementations/KMeansPaletteGenerator.cs`,\n * 其本身衍生自 wieslawsoltes/PaletteGenerator。\n *\n * 与原实现的唯一差异是随机源:原版用全局 `Random`,这里改用按直方图内容播种的\n * mulberry32,使得同一张封面每次都得到完全相同的调色板,避免重启应用后背景配色\n * 发生肉眼可见的漂移。\n *\n * @see https://github.com/Storyteller-Studios/Impressionist/blob/master/Impressionist/Implementations/KMeansPaletteGenerator.cs\n */\n\nimport {\n\tdistanceSquared,\n\tlabToRgb,\n\tpaletteRgbLStarIsDark,\n\tpaletteRgbLStarIsLight,\n\trgbLStarIsDark,\n\trgbToLab,\n} from \"./color-utilities.ts\";\nimport type {\n\tColorCount,\n\tColorVec3,\n\tPaletteIntent,\n\tPaletteResult,\n\tThemeColorResult,\n} from \"./types.ts\";\n\n/** 一个确定性的伪随机数发生器,返回 [0, 1) 区间的浮点数。 */\nexport type RandomSource = () => number;\n\n/** mulberry32,短小且分布足够好。 */\nexport function createRandom(seed: number): RandomSource {\n\tlet state = seed >>> 0;\n\treturn () => {\n\t\tstate = (state + 0x6d2b79f5) >>> 0;\n\t\tlet t = state;\n\t\tt = Math.imul(t ^ (t >>> 15), t | 1);\n\t\tt ^= t + Math.imul(t ^ (t >>> 7), t | 61);\n\t\treturn ((t ^ (t >>> 14)) >>> 0) / 4294967296;\n\t};\n}\n\n/** 由直方图内容派生一个稳定的种子。 */\nexport function seedFromHistogram(entries: readonly ColorCount[]): number {\n\tlet hash = 0x811c9dc5;\n\tfor (const { color, count } of entries) {\n\t\tfor (const value of [...color, count]) {\n\t\t\thash ^= Math.round(value) & 0xffff;\n\t\t\thash = Math.imul(hash, 0x01000193) >>> 0;\n\t\t}\n\t}\n\treturn hash >>> 0;\n}\n\nfunction isNotNearWhite(color: ColorVec3): boolean {\n\treturn color.some((channel) => channel <= 250);\n}\n\nfunction filterOrFallback(\n\tentries: readonly ColorCount[],\n\tpredicate: (entry: ColorCount) => boolean,\n): ColorCount[] {\n\tconst filtered = entries.filter(predicate);\n\treturn filtered.length > 0 ? filtered : [...entries];\n}\n\nfunction clampRgb(color: ColorVec3): ColorVec3 {\n\treturn color.map((channel) =>\n\t\tMath.min(255, Math.max(0, channel)),\n\t) as ColorVec3;\n}\n\n/** 把同色项合并计数,等价于 C# 里的 `GroupBy(...).ToDictionary(...)`。 */\nfunction groupColors(entries: readonly ColorCount[]): ColorCount[] {\n\tconst grouped = new Map<string, ColorCount>();\n\tfor (const entry of entries) {\n\t\tconst key = `${entry.color[0]},${entry.color[1]},${entry.color[2]}`;\n\t\tconst existing = grouped.get(key);\n\t\tif (existing) existing.count += entry.count;\n\t\telse grouped.set(key, { color: [...entry.color], count: entry.count });\n\t}\n\treturn [...grouped.values()];\n}\n\nfunction toLabEntries(entries: readonly ColorCount[]): ColorCount[] {\n\treturn entries.map((entry) => ({\n\t\tcolor: rgbToLab(entry.color),\n\t\tcount: entry.count,\n\t}));\n}\n\nfunction colorsEqual(a: ColorVec3, b: ColorVec3): boolean {\n\treturn a.every((value, i) => value === b[i]);\n}\n\nfunction findNearestCenterIndex(\n\tcolor: ColorVec3,\n\tcenters: readonly ColorVec3[],\n): number {\n\tlet nearestIndex = 0;\n\tlet minDist = Number.POSITIVE_INFINITY;\n\tfor (let i = 0; i < centers.length; i++) {\n\t\tconst dist = distanceSquared(color, centers[i]);\n\t\tif (dist < minDist) {\n\t\t\tnearestIndex = i;\n\t\t\tminDist = dist;\n\t\t}\n\t}\n\treturn nearestIndex;\n}\n\nfunction findFarthestColor(\n\tentries: readonly ColorCount[],\n\tcenters: readonly ColorVec3[],\n): ColorVec3 {\n\tlet farthest: ColorVec3 = [0, 0, 0];\n\tlet maxDistance = Number.NEGATIVE_INFINITY;\n\tfor (const { color } of entries) {\n\t\tlet nearestDistance = Number.POSITIVE_INFINITY;\n\t\tfor (const center of centers) {\n\t\t\tconst dist = distanceSquared(color, center);\n\t\t\tif (dist < nearestDistance) nearestDistance = dist;\n\t\t}\n\t\tif (nearestDistance > maxDistance) {\n\t\t\tmaxDistance = nearestDistance;\n\t\t\tfarthest = color;\n\t\t}\n\t}\n\treturn farthest;\n}\n\nfunction kMeansPlusPlusCenters(\n\tentries: readonly ColorCount[],\n\tclusterCount: number,\n\trandom: RandomSource,\n): ColorVec3[] {\n\tconst firstIndex = Math.floor(random() * entries.length);\n\tconst selectedIndices = new Set([firstIndex]);\n\tconst centers: ColorVec3[] = [entries[firstIndex].color];\n\tfor (let i = 1; i < clusterCount; i++) {\n\t\tlet accumulated = 0;\n\t\tconst accDistances = new Float64Array(entries.length);\n\t\tfor (let vectorId = 0; vectorId < entries.length; vectorId++) {\n\t\t\tconst target = entries[vectorId].color;\n\t\t\tlet minDistanceSquared = distanceSquared(centers[0], target);\n\t\t\tfor (let clusterIdx = 1; clusterIdx < i; clusterIdx++) {\n\t\t\t\tconst current = distanceSquared(centers[clusterIdx], target);\n\t\t\t\tif (current < minDistanceSquared) minDistanceSquared = current;\n\t\t\t}\n\t\t\taccumulated += minDistanceSquared * entries[vectorId].count;\n\t\t\taccDistances[vectorId] = accumulated;\n\t\t}\n\t\tif (accumulated <= Number.EPSILON) {\n\t\t\tconst nextIndex = entries.findIndex(\n\t\t\t\t(_, index) => !selectedIndices.has(index),\n\t\t\t);\n\t\t\tif (nextIndex < 0) break;\n\t\t\tselectedIndices.add(nextIndex);\n\t\t\tcenters.push(entries[nextIndex].color);\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst targetPoint = random() * accumulated;\n\t\tfor (let vectorId = 0; vectorId < entries.length; vectorId++) {\n\t\t\tif (\n\t\t\t\t!selectedIndices.has(vectorId) &&\n\t\t\t\taccDistances[vectorId] >= targetPoint\n\t\t\t) {\n\t\t\t\tselectedIndices.add(vectorId);\n\t\t\t\tcenters.push(entries[vectorId].color);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\tif (centers.length === i) {\n\t\t\tconst nextIndex = entries.findIndex(\n\t\t\t\t(_, index) => !selectedIndices.has(index),\n\t\t\t);\n\t\t\tif (nextIndex < 0) break;\n\t\t\tselectedIndices.add(nextIndex);\n\t\t\tcenters.push(entries[nextIndex].color);\n\t\t}\n\t}\n\treturn centers;\n}\n\nfunction kMeansCluster(\n\tentries: readonly ColorCount[],\n\tnumClusters: number,\n\tuseKMeansPP: boolean,\n\trandom: RandomSource,\n): ColorVec3[] {\n\tconst clusterCount = Math.min(numClusters, entries.length);\n\tif (clusterCount <= 0) return [];\n\n\tlet centers: ColorVec3[];\n\tif (useKMeansPP) {\n\t\tcenters = kMeansPlusPlusCenters(entries, clusterCount, random);\n\t} else {\n\t\t// 等价于 C# 的 OrderByDescending(_ => random.Next()).Take(clusterCount)\n\t\tconst shuffled = entries.map((entry) => entry.color);\n\t\tfor (let i = shuffled.length - 1; i > 0; i--) {\n\t\t\tconst j = Math.floor(random() * (i + 1));\n\t\t\t[shuffled[i], shuffled[j]] = [shuffled[j], shuffled[i]];\n\t\t}\n\t\tcenters = shuffled.slice(0, clusterCount);\n\t}\n\n\tconst assignments = new Int32Array(entries.length);\n\tlet changed = true;\n\tlet iterations = 0;\n\twhile (changed && iterations < 250) {\n\t\tchanged = false;\n\t\titerations++;\n\n\t\tfor (let i = 0; i < entries.length; i++) {\n\t\t\tassignments[i] = findNearestCenterIndex(entries[i].color, centers);\n\t\t}\n\n\t\tfor (let i = 0; i < clusterCount; i++) {\n\t\t\tlet sumX = 0;\n\t\t\tlet sumY = 0;\n\t\t\tlet sumZ = 0;\n\t\t\tlet weight = 0;\n\t\t\tfor (let e = 0; e < entries.length; e++) {\n\t\t\t\tif (assignments[e] !== i) continue;\n\t\t\t\tconst { color, count } = entries[e];\n\t\t\t\tsumX += color[0] * count;\n\t\t\t\tsumY += color[1] * count;\n\t\t\t\tsumZ += color[2] * count;\n\t\t\t\tweight += count;\n\t\t\t}\n\t\t\tif (weight === 0) {\n\t\t\t\t// 空簇:把中心挪到离现有中心最远的颜色上,下一轮重新分配\n\t\t\t\tcenters[i] = findFarthestColor(entries, centers);\n\t\t\t\tchanged = true;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tconst newCenter: ColorVec3 = [\n\t\t\t\tsumX / weight,\n\t\t\t\tsumY / weight,\n\t\t\t\tsumZ / weight,\n\t\t\t];\n\t\t\tif (!colorsEqual(newCenter, centers[i])) {\n\t\t\t\tcenters[i] = newCenter;\n\t\t\t\tchanged = true;\n\t\t\t}\n\t\t}\n\t}\n\n\treturn centers;\n}\n\n/** 计算主题色,对应 C# 的 `KMeansPaletteGenerator.CreateThemeColor`。 */\nexport function createThemeColor(\n\tsourceColors: readonly ColorCount[],\n\tignoreWhite = false,\n\ttoLab = false,\n\trandom: RandomSource = createRandom(seedFromHistogram(sourceColors)),\n): ThemeColorResult {\n\tlet entries = [...sourceColors];\n\tif (ignoreWhite && entries.length > 1) {\n\t\tentries = filterOrFallback(entries, (entry) => isNotNearWhite(entry.color));\n\t}\n\tif (toLab) entries = toLabEntries(entries);\n\tentries = groupColors(entries);\n\n\tconst centers = kMeansCluster(entries, 1, false, random);\n\tconst first = centers[0] ?? ([0, 0, 0] as ColorVec3);\n\tconst color = clampRgb(toLab ? labToRgb(first) : first);\n\treturn { color, colorIsDark: rgbLStarIsDark(color) };\n}\n\n/**\n * 生成调色板,对应 C# 的 `KMeansPaletteGenerator.CreatePalette`。\n *\n * `intent` 见 {@link PaletteIntent}:默认的 `\"accent\"` 沿用 Impressionist 的行为,\n * 铺满全屏的背景应当传 `\"dominant\"`。\n */\nexport function createKMeansPalette(\n\tsourceColors: readonly ColorCount[],\n\tclusterCount: number,\n\tthemeColor: ThemeColorResult,\n\tignoreWhite = false,\n\ttoLab = false,\n\tuseKMeansPP = false,\n\tintent: PaletteIntent = \"accent\",\n\trandom: RandomSource = createRandom(seedFromHistogram(sourceColors)),\n): PaletteResult {\n\tlet effectiveIgnoreWhite = ignoreWhite;\n\tlet effectiveUseKMeansPP = useKMeansPP;\n\tif (sourceColors.length === 1) {\n\t\teffectiveIgnoreWhite = false;\n\t\teffectiveUseKMeansPP = false;\n\t}\n\n\tconst colorIsDark = themeColor.colorIsDark;\n\tlet entries = filterOrFallback(sourceColors, (entry) => {\n\t\t// 明暗过滤是强调色的取向,dominant 下只剩 ignoreWhite 那一层\n\t\tif (intent === \"dominant\") {\n\t\t\treturn !effectiveIgnoreWhite || isNotNearWhite(entry.color);\n\t\t}\n\t\tif (colorIsDark) return paletteRgbLStarIsDark(entry.color);\n\t\tif (!effectiveIgnoreWhite) return paletteRgbLStarIsLight(entry.color);\n\t\treturn paletteRgbLStarIsLight(entry.color) && isNotNearWhite(entry.color);\n\t});\n\tif (toLab) entries = toLabEntries(entries);\n\tentries = groupColors(entries);\n\n\tconst centers = kMeansCluster(\n\t\tentries,\n\t\tclusterCount,\n\t\teffectiveUseKMeansPP,\n\t\trandom,\n\t);\n\tconst dominantColors = centers.map((center) =>\n\t\tclampRgb(toLab ? labToRgb(center) : center),\n\t);\n\n\tconst palette: ColorVec3[] = [];\n\tfor (let i = 0; i < clusterCount; i++) {\n\t\t// 颜色不够时只能重复填充,原实现也是这么处理的\n\t\tpalette.push(\n\t\t\tdominantColors.length > 0\n\t\t\t\t? [...dominantColors[i % dominantColors.length]]\n\t\t\t\t: [0, 0, 0],\n\t\t);\n\t}\n\treturn { palette, paletteIsDark: colorIsDark, themeColor };\n}\n","/**\n * @fileoverview\n * 八叉树量化取色器。\n *\n * 逐行移植自 Storyteller-Studios/Impressionist(MIT)的\n * `Impressionist/Implementations/OctTreePaletteGenerator.cs`,\n * 其本身衍生自 bacowan/cSharpColourQuantization。\n *\n * @see https://github.com/Storyteller-Studios/Impressionist/blob/master/Impressionist/Implementations/OctTreePaletteGenerator.cs\n */\n\nimport {\n\tpaletteRgbLStarIsDark,\n\tpaletteRgbLStarIsLight,\n} from \"./color-utilities.ts\";\nimport { createThemeColor } from \"./kmeans.ts\";\nimport type {\n\tColorCount,\n\tColorVec3,\n\tPaletteIntent,\n\tPaletteResult,\n\tThemeColorResult,\n} from \"./types.ts\";\n\nconst MAX_COLOR_DEPTH = 8;\n\ninterface PaletteEntry {\n\tcolor: ColorVec3;\n\tsampleCount: number;\n}\n\nclass OctreeNode {\n\treadonly children: (OctreeNode | null)[] = [\n\t\tnull,\n\t\tnull,\n\t\tnull,\n\t\tnull,\n\t\tnull,\n\t\tnull,\n\t\tnull,\n\t\tnull,\n\t];\n\tchildCount = 0;\n\tleafNodeCount = 0;\n\tsampleCount = 0;\n\tprivate redSum = 0;\n\tprivate greenSum = 0;\n\tprivate blueSum = 0;\n\n\tconstructor(\n\t\tprivate readonly owner: OctreePaletteQuantizer,\n\t\treadonly parentNode: OctreeNode | null,\n\t\treadonly indexInParent: number,\n\t) {}\n\n\tprivate get averageColor(): ColorVec3 {\n\t\tif (this.sampleCount === 0) return [0, 0, 0];\n\t\treturn [\n\t\t\tthis.redSum / this.sampleCount,\n\t\t\tthis.greenSum / this.sampleCount,\n\t\t\tthis.blueSum / this.sampleCount,\n\t\t];\n\t}\n\n\taddColor(\n\t\tred: number,\n\t\tgreen: number,\n\t\tblue: number,\n\t\tdepth: number,\n\t\tsampleCount: number,\n\t): void {\n\t\tthis.sampleCount += sampleCount;\n\t\tthis.redSum += red * sampleCount;\n\t\tthis.greenSum += green * sampleCount;\n\t\tthis.blueSum += blue * sampleCount;\n\n\t\tif (depth === MAX_COLOR_DEPTH) {\n\t\t\tif (this.leafNodeCount === 0) this.leafNodeCount = 1;\n\t\t\treturn;\n\t\t}\n\n\t\tconst bitShift = 7 - depth;\n\t\tconst childIndex =\n\t\t\t(((red >> bitShift) & 1) << 2) |\n\t\t\t(((green >> bitShift) & 1) << 1) |\n\t\t\t((blue >> bitShift) & 1);\n\t\tlet childNode = this.children[childIndex];\n\t\tif (!childNode) {\n\t\t\tchildNode = new OctreeNode(this.owner, this, childIndex);\n\t\t\tthis.children[childIndex] = childNode;\n\t\t\tthis.childCount++;\n\t\t\tthis.owner.registerNodeAtDepth(childNode, depth);\n\t\t}\n\n\t\tconst previousLeafNodeCount = childNode.leafNodeCount;\n\t\tchildNode.addColor(red, green, blue, depth + 1, sampleCount);\n\t\tthis.leafNodeCount += childNode.leafNodeCount - previousLeafNodeCount;\n\t}\n\n\tcollectPaletteColors(result: PaletteEntry[]): void {\n\t\tif (this.leafNodeCount === 0) return;\n\t\tif (this.childCount === 0) {\n\t\t\tresult.push({ color: this.averageColor, sampleCount: this.sampleCount });\n\t\t\treturn;\n\t\t}\n\t\tfor (const child of this.children) child?.collectPaletteColors(result);\n\t}\n\n\tmergeChildrenIntoThisNode(): void {\n\t\tif (this.childCount === 0 || this.leafNodeCount <= 1) return;\n\n\t\tconst previousLeafNodeCount = this.leafNodeCount;\n\t\tthis.children.fill(null);\n\t\tthis.childCount = 0;\n\t\tthis.leafNodeCount = this.sampleCount > 0 ? 1 : 0;\n\n\t\tconst leafReduction = previousLeafNodeCount - this.leafNodeCount;\n\t\tlet parentNode = this.parentNode;\n\t\twhile (parentNode) {\n\t\t\tparentNode.leafNodeCount -= leafReduction;\n\t\t\tparentNode = parentNode.parentNode;\n\t\t}\n\t}\n\n\t/** 合并会把整棵子树摘掉,被摘掉的节点仍留在深度索引里,需要显式排除。 */\n\tisAttachedToRoot(): boolean {\n\t\tlet currentNode: OctreeNode = this;\n\t\twhile (currentNode.parentNode) {\n\t\t\tif (\n\t\t\t\tcurrentNode.parentNode.children[currentNode.indexInParent] !==\n\t\t\t\tcurrentNode\n\t\t\t) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tcurrentNode = currentNode.parentNode;\n\t\t}\n\t\treturn true;\n\t}\n}\n\nclass OctreePaletteQuantizer {\n\tprivate readonly rootNode: OctreeNode = new OctreeNode(this, null, -1);\n\tprivate readonly nodesByDepth: OctreeNode[][] = Array.from(\n\t\t{ length: MAX_COLOR_DEPTH },\n\t\t() => [],\n\t);\n\n\tregisterNodeAtDepth(node: OctreeNode, depth: number): void {\n\t\tthis.nodesByDepth[depth].push(node);\n\t}\n\n\taddColor(color: ColorVec3, sampleCount: number): void {\n\t\tif (sampleCount <= 0) return;\n\t\tthis.rootNode.addColor(\n\t\t\tcolor[0] & 0xff,\n\t\t\tcolor[1] & 0xff,\n\t\t\tcolor[2] & 0xff,\n\t\t\t0,\n\t\t\tsampleCount,\n\t\t);\n\t}\n\n\tgetPalette(maxColorCount: number): ColorVec3[] {\n\t\tif (maxColorCount <= 0 || this.rootNode.leafNodeCount === 0) return [];\n\n\t\tconst paletteColors: PaletteEntry[] = [];\n\t\tthis.rootNode.collectPaletteColors(paletteColors);\n\n\t\tif (paletteColors.length <= maxColorCount) {\n\t\t\treturn paletteColors.map((entry) => entry.color);\n\t\t}\n\n\t\tpaletteColors.sort((left, right) => {\n\t\t\tconst bySampleCount = right.sampleCount - left.sampleCount;\n\t\t\tif (bySampleCount !== 0) return bySampleCount;\n\t\t\tif (left.color[0] !== right.color[0]) {\n\t\t\t\treturn left.color[0] - right.color[0];\n\t\t\t}\n\t\t\tif (left.color[1] !== right.color[1]) {\n\t\t\t\treturn left.color[1] - right.color[1];\n\t\t\t}\n\t\t\treturn left.color[2] - right.color[2];\n\t\t});\n\n\t\treturn paletteColors\n\t\t\t.slice(0, Math.min(maxColorCount, paletteColors.length))\n\t\t\t.map((entry) => entry.color);\n\t}\n\n\treduceToColorCount(targetColorCount: number): void {\n\t\tif (targetColorCount <= 0) return;\n\n\t\tlet remainingLeafReduction = this.rootNode.leafNodeCount - targetColorCount;\n\t\tif (remainingLeafReduction <= 0) return;\n\n\t\tfor (\n\t\t\tlet depth = MAX_COLOR_DEPTH - 2;\n\t\t\tdepth >= 0 && remainingLeafReduction > 0;\n\t\t\tdepth--\n\t\t) {\n\t\t\tconst nodesAtDepth = this.nodesByDepth[depth];\n\t\t\tnodesAtDepth.sort((left, right) => {\n\t\t\t\tconst byLeafCount = left.leafNodeCount - right.leafNodeCount;\n\t\t\t\tif (byLeafCount !== 0) return byLeafCount;\n\t\t\t\treturn left.sampleCount - right.sampleCount;\n\t\t\t});\n\n\t\t\tfor (\n\t\t\t\tlet i = 0;\n\t\t\t\ti < nodesAtDepth.length && remainingLeafReduction > 0;\n\t\t\t\ti++\n\t\t\t) {\n\t\t\t\tconst candidate = nodesAtDepth[i];\n\t\t\t\tif (candidate.childCount === 0) continue;\n\t\t\t\tconst leafReduction = candidate.leafNodeCount - 1;\n\t\t\t\tif (leafReduction <= 0) continue;\n\t\t\t\tif (leafReduction > remainingLeafReduction) continue;\n\t\t\t\tremainingLeafReduction -= leafReduction;\n\t\t\t\tcandidate.mergeChildrenIntoThisNode();\n\t\t\t}\n\t\t}\n\n\t\twhile (this.rootNode.leafNodeCount > targetColorCount) {\n\t\t\tconst candidate = this.findBestMergeCandidate();\n\t\t\tif (!candidate) break;\n\t\t\tcandidate.mergeChildrenIntoThisNode();\n\t\t}\n\t}\n\n\tprivate findBestMergeCandidate(): OctreeNode | null {\n\t\tlet bestCandidate: OctreeNode | null = null;\n\t\tlet bestLeafReduction = Number.POSITIVE_INFINITY;\n\t\tlet bestSampleCount = Number.POSITIVE_INFINITY;\n\n\t\tfor (let depth = MAX_COLOR_DEPTH - 2; depth >= 0; depth--) {\n\t\t\tfor (const candidate of this.nodesByDepth[depth]) {\n\t\t\t\tif (!candidate.isAttachedToRoot()) continue;\n\t\t\t\tif (candidate.childCount === 0) continue;\n\t\t\t\tconst leafReduction = candidate.leafNodeCount - 1;\n\t\t\t\tif (leafReduction <= 0) continue;\n\t\t\t\tif (\n\t\t\t\t\tleafReduction < bestLeafReduction ||\n\t\t\t\t\t(leafReduction === bestLeafReduction &&\n\t\t\t\t\t\tcandidate.sampleCount < bestSampleCount)\n\t\t\t\t) {\n\t\t\t\t\tbestCandidate = candidate;\n\t\t\t\t\tbestLeafReduction = leafReduction;\n\t\t\t\t\tbestSampleCount = candidate.sampleCount;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn bestCandidate;\n\t}\n}\n\n/**\n * 生成调色板,对应 C# 的 `OctTreePaletteGenerator.CreatePalette`。\n *\n * `intent` 见 {@link PaletteIntent}:默认的 `\"accent\"` 沿用 Impressionist 的行为,\n * 铺满全屏的背景应当传 `\"dominant\"`。\n */\nexport function createOctTreePalette(\n\tsourceColors: readonly ColorCount[],\n\tclusterCount: number,\n\tthemeColor: ThemeColorResult = createThemeColor(sourceColors, false, true),\n\tignoreWhite = false,\n\tintent: PaletteIntent = \"accent\",\n): PaletteResult {\n\tconst quantizer = new OctreePaletteQuantizer();\n\tconst effectiveIgnoreWhite = sourceColors.length === 1 ? false : ignoreWhite;\n\n\tconst filteredEntries = sourceColors.filter((entry) => {\n\t\tconst [r, g, b] = entry.color;\n\t\tif (effectiveIgnoreWhite && r > 250 && g > 250 && b > 250) return false;\n\t\t// 明暗过滤是强调色的取向,dominant 下只剩上面的忽略纯白\n\t\tif (intent === \"dominant\") return true;\n\t\treturn themeColor.colorIsDark\n\t\t\t? paletteRgbLStarIsDark(entry.color)\n\t\t\t: paletteRgbLStarIsLight(entry.color);\n\t});\n\tconst entries = filteredEntries.length > 0 ? filteredEntries : sourceColors;\n\n\tfor (const entry of entries) quantizer.addColor(entry.color, entry.count);\n\tquantizer.reduceToColorCount(clusterCount);\n\tconst quantizeResult = quantizer.getPalette(clusterCount);\n\n\tlet palette: ColorVec3[];\n\tif (quantizeResult.length < clusterCount) {\n\t\tpalette = [];\n\t\tfor (let i = 0; i < clusterCount; i++) {\n\t\t\tpalette.push(\n\t\t\t\tquantizeResult.length > 0\n\t\t\t\t\t? [...quantizeResult[i % quantizeResult.length]]\n\t\t\t\t\t: [0, 0, 0],\n\t\t\t);\n\t\t}\n\t} else {\n\t\tpalette = quantizeResult;\n\t}\n\n\treturn { palette, paletteIsDark: themeColor.colorIsDark, themeColor };\n}\n","/**\n * @fileoverview\n * 自动在 K-Means 与八叉树两种取色结果之间择优。\n *\n * 逐行移植自 Storyteller-Studios/Impressionist(MIT)的\n * `Impressionist/Implementations/AutoPaletteGenerator.cs`。\n *\n * @see https://github.com/Storyteller-Studios/Impressionist/blob/master/Impressionist/Implementations/AutoPaletteGenerator.cs\n */\n\nimport { rgbToLab } from \"./color-utilities.ts\";\nimport {\n\tcreateKMeansPalette,\n\tcreateRandom,\n\tcreateThemeColor,\n\tseedFromHistogram,\n} from \"./kmeans.ts\";\nimport { createOctTreePalette } from \"./octtree.ts\";\nimport type {\n\tColorCount,\n\tColorVec3,\n\tPaletteIntent,\n\tPaletteResult,\n} from \"./types.ts\";\n\n/** 调色板在 LAB 空间里到自身质心的平均平方距离,用来衡量色彩分散程度。 */\nfunction calculateSpatialDiversity(palette: readonly ColorVec3[]): number {\n\tif (palette.length === 0) return 0;\n\n\tconst labVectors = palette.map(rgbToLab);\n\tlet centroidL = 0;\n\tlet centroidA = 0;\n\tlet centroidB = 0;\n\tfor (const [l, a, b] of labVectors) {\n\t\tcentroidL += l;\n\t\tcentroidA += a;\n\t\tcentroidB += b;\n\t}\n\tcentroidL /= labVectors.length;\n\tcentroidA /= labVectors.length;\n\tcentroidB /= labVectors.length;\n\n\tlet sumSquaredDistances = 0;\n\tfor (const [l, a, b] of labVectors) {\n\t\tconst dl = l - centroidL;\n\t\tconst da = a - centroidA;\n\t\tconst db = b - centroidB;\n\t\tsumSquaredDistances += dl * dl + da * da + db * db;\n\t}\n\treturn sumSquaredDistances / labVectors.length;\n}\n\n/**\n * 调色板里互不相同的颜色数量。\n *\n * 两个生成器在候选颜色凑不满 `clusterCount` 时都会用 `i % length` 重复填充,\n * 重复的是精确副本,所以按精确相等去重即可。\n */\nfunction countDistinctColors(palette: readonly ColorVec3[]): number {\n\treturn new Set(palette.map((color) => color.join(\",\"))).size;\n}\n\n/**\n * 同时跑两种取色算法并择优:暗色调色板偏好更分散的结果,亮色调色板反之偏好\n * 更聚拢的结果(八叉树在亮色上容易退化成一片惨白,所以 0 分散度直接判负)。\n *\n * 但分散度只在两者给出同样多的颜色时才有可比性。调用方要几个色就是几个色,被\n * 重复填充凑满的结果对任何按数量取色的用法都是退化的 —— 拿去做多点渐变会直接\n * 塌成两色平铺 —— 而重复恰恰会拉低分散度,于是在亮色分支里被当成「更聚拢」选\n * 中。所以先比互不相同的颜色数,同数时才轮到原本的分散度规则。\n *\n * 「亮色偏好更聚拢」同样是强调色的取向:强调色散得没有章法不好用,但背景要的正\n * 是封面的颜色跨度,更分散才更像那张封面。所以 `intent` 为 `\"dominant\"` 时一律\n * 取更分散的一支,不再分明暗两套。见 {@link PaletteIntent}。\n */\nexport function createAutoPalette(\n\tsourceColors: readonly ColorCount[],\n\tclusterCount: number,\n\tignoreWhite = false,\n\ttoLab = false,\n\tuseKMeansPP = false,\n\tintent: PaletteIntent = \"accent\",\n): PaletteResult {\n\tconst random = createRandom(seedFromHistogram(sourceColors));\n\tconst themeColor = createThemeColor(sourceColors, ignoreWhite, toLab, random);\n\tconst kmeansResult = createKMeansPalette(\n\t\tsourceColors,\n\t\tclusterCount,\n\t\tthemeColor,\n\t\tignoreWhite,\n\t\ttoLab,\n\t\tuseKMeansPP,\n\t\tintent,\n\t\trandom,\n\t);\n\tconst octTreeResult = createOctTreePalette(\n\t\tsourceColors,\n\t\tclusterCount,\n\t\tthemeColor,\n\t\tignoreWhite,\n\t\tintent,\n\t);\n\n\tconst kMeansDistinct = countDistinctColors(kmeansResult.palette);\n\tconst octTreeDistinct = countDistinctColors(octTreeResult.palette);\n\tif (kMeansDistinct !== octTreeDistinct) {\n\t\treturn kMeansDistinct > octTreeDistinct ? kmeansResult : octTreeResult;\n\t}\n\n\tconst kMeansDiversity = calculateSpatialDiversity(kmeansResult.palette);\n\tconst octTreeDiversity = calculateSpatialDiversity(octTreeResult.palette);\n\n\tif (intent === \"dominant\" || kmeansResult.paletteIsDark) {\n\t\treturn kMeansDiversity >= octTreeDiversity ? kmeansResult : octTreeResult;\n\t}\n\treturn kMeansDiversity <= octTreeDiversity || octTreeDiversity === 0\n\t\t? kmeansResult\n\t\t: octTreeResult;\n}\n","/**\n * 创建一个离屏画板,环境不支持 `OffscreenCanvas` 时回落到普通 canvas 元素。\n */\nexport function createOffscreenCanvas(\n\twidth: number,\n\theight: number,\n): OffscreenCanvas | HTMLCanvasElement {\n\tif (typeof OffscreenCanvas !== \"undefined\") {\n\t\treturn new OffscreenCanvas(width, height);\n\t}\n\tconst canvas = document.createElement(\"canvas\");\n\tcanvas.width = width;\n\tcanvas.height = height;\n\treturn canvas;\n}\n","/**\n * @fileoverview\n * 从图像资源构建颜色直方图,作为取色器的输入。\n */\n\nimport { createOffscreenCanvas } from \"#utils/canvas.ts\";\nimport type { ColorCount, ColorVec3 } from \"./types.ts\";\n\n/** 可以用来取色的图像资源。 */\nexport type HistogramSource =\n\t| HTMLImageElement\n\t| HTMLVideoElement\n\t| ImageBitmap\n\t| ImageData;\n\n/**\n * 统计前先把图像缩到这个尺寸。\n *\n * 取色只关心整体色彩分布,64×64 已经足够,而且能把直方图规模压到几千项,\n * 让后续的 K-Means 在几毫秒内跑完。\n */\nconst DEFAULT_SAMPLE_SIZE = 64;\n\nfunction toImageData(\n\tsource: HistogramSource,\n\tsampleSize: number,\n): ImageData | null {\n\tif (source instanceof ImageData) return source;\n\n\tconst [sourceWidth, sourceHeight] =\n\t\tsource instanceof HTMLVideoElement\n\t\t\t? [source.videoWidth, source.videoHeight]\n\t\t\t: source instanceof HTMLImageElement\n\t\t\t\t? [source.naturalWidth, source.naturalHeight]\n\t\t\t\t: [source.width, source.height];\n\tif (sourceWidth <= 0 || sourceHeight <= 0) return null;\n\n\tconst normalizedSampleSize = Math.max(1, Math.floor(sampleSize));\n\tconst scale = Math.min(\n\t\t1,\n\t\tnormalizedSampleSize / Math.max(sourceWidth, sourceHeight),\n\t);\n\tconst width = Math.max(1, Math.round(sourceWidth * scale));\n\tconst height = Math.max(1, Math.round(sourceHeight * scale));\n\n\tconst canvas = createOffscreenCanvas(width, height);\n\tconst ctx = canvas.getContext(\"2d\", {\n\t\twillReadFrequently: true,\n\t}) as OffscreenCanvasRenderingContext2D | CanvasRenderingContext2D | null;\n\tif (!ctx) return null;\n\tctx.drawImage(source, 0, 0, width, height);\n\treturn ctx.getImageData(0, 0, width, height);\n}\n\n/**\n * 构建颜色直方图。全透明像素会被跳过,半透明像素按原色计入。\n *\n * @param source 图像资源\n * @param sampleSize 统计前缩放到的最长边像素数,默认 64\n */\nexport function buildColorHistogram(\n\tsource: HistogramSource,\n\tsampleSize: number = DEFAULT_SAMPLE_SIZE,\n): ColorCount[] {\n\tconst imageData = toImageData(source, sampleSize);\n\tif (!imageData) return [];\n\n\tconst { data } = imageData;\n\tconst counts = new Map<number, number>();\n\tfor (let i = 0; i < data.length; i += 4) {\n\t\tif (data[i + 3] === 0) continue;\n\t\tconst key = (data[i] << 16) | (data[i + 1] << 8) | data[i + 2];\n\t\tcounts.set(key, (counts.get(key) ?? 0) + 1);\n\t}\n\n\treturn Array.from(counts, ([key, count]) => {\n\t\tconst color: ColorVec3 = [\n\t\t\t(key >> 16) & 0xff,\n\t\t\t(key >> 8) & 0xff,\n\t\t\tkey & 0xff,\n\t\t];\n\t\treturn { color, count };\n\t});\n}\n","/**\n * @fileoverview\n * 从专辑封面提取主色调色板。\n *\n * 移植自 Storyteller-Studios/Impressionist(MIT),\n * 详见各实现文件顶部的说明。\n *\n * Isolation 渲染器需要四个主色来构造渐变,这个模块就是它的供色来源;\n * 其它需要「封面主色」的场景也可以直接复用。\n */\n\nexport { createAutoPalette } from \"./auto.ts\";\nexport {\n\tchannelToLinear,\n\thsvToRgb,\n\tlabToRgb,\n\tlabToXyz,\n\tpaletteRgbLStarIsDark,\n\tpaletteRgbLStarIsLight,\n\trgbLStarIsDark,\n\trgbToHsv,\n\trgbToLab,\n\trgbToXyz,\n\tsrgbToOkLab,\n\txyzToLab,\n\txyzToRgb,\n\tyToLStar,\n} from \"./color-utilities.ts\";\nexport type { HistogramSource } from \"./histogram.ts\";\nexport { buildColorHistogram } from \"./histogram.ts\";\nexport { createKMeansPalette, createThemeColor } from \"./kmeans.ts\";\nexport { createOctTreePalette } from \"./octtree.ts\";\nexport type {\n\tColorCount,\n\tColorVec3,\n\tHSVColor,\n\tPaletteIntent,\n\tPaletteResult,\n\tThemeColorResult,\n} from \"./types.ts\";\n\nimport { createAutoPalette } from \"./auto.ts\";\nimport { buildColorHistogram, type HistogramSource } from \"./histogram.ts\";\nimport { createKMeansPalette, createThemeColor } from \"./kmeans.ts\";\nimport { createOctTreePalette } from \"./octtree.ts\";\nimport type { PaletteIntent, PaletteResult } from \"./types.ts\";\n\n/** 取色算法。 */\nexport type PaletteAlgorithm = \"auto\" | \"kmeans\" | \"octtree\";\n\n/** {@link createPaletteFromImage} 的可选项。 */\nexport interface CreatePaletteOptions {\n\t/** 取色算法,默认 `\"auto\"`。 */\n\talgorithm?: PaletteAlgorithm;\n\t/** 是否忽略接近纯白的颜色,默认 `false`。 */\n\tignoreWhite?: boolean;\n\t/** K-Means 是否在 LAB 空间聚类,默认 `false`。 */\n\ttoLab?: boolean;\n\t/** K-Means 是否使用 K-Means++ 初始化,默认 `false`。 */\n\tuseKMeansPP?: boolean;\n\t/** 调色板的用途,默认 `\"accent\"`。见 {@link PaletteIntent}。 */\n\tintent?: PaletteIntent;\n\t/** 统计直方图前缩放到的最长边像素数,默认 64。 */\n\tsampleSize?: number;\n}\n\n/**\n * 从图像资源提取指定数量的主色。\n *\n * 整个流程是同步的:封面会先被缩到 64×64 再统计,因此在主线程上通常只需要几\n * 毫秒,不值得为它单独开一个 Worker。\n *\n * @param source 图像资源,可以是 img/video 元素、`ImageBitmap` 或 `ImageData`\n * @param clusterCount 需要的颜色数量,返回的调色板长度恒等于该值\n */\nexport function createPaletteFromImage(\n\tsource: HistogramSource,\n\tclusterCount: number,\n\toptions: CreatePaletteOptions = {},\n): PaletteResult {\n\tconst normalizedClusterCount = Math.max(0, Math.floor(clusterCount));\n\tconst {\n\t\talgorithm = \"auto\",\n\t\tignoreWhite = false,\n\t\ttoLab = false,\n\t\tuseKMeansPP = false,\n\t\tintent = \"accent\",\n\t\tsampleSize,\n\t} = options;\n\n\tconst entries = buildColorHistogram(source, sampleSize);\n\tif (entries.length === 0) {\n\t\tconst themeColor = {\n\t\t\tcolor: [0, 0, 0] as [number, number, number],\n\t\t\tcolorIsDark: true,\n\t\t};\n\t\treturn {\n\t\t\tpalette: Array.from(\n\t\t\t\t{ length: normalizedClusterCount },\n\t\t\t\t() => [0, 0, 0] as [number, number, number],\n\t\t\t),\n\t\t\tpaletteIsDark: true,\n\t\t\tthemeColor,\n\t\t};\n\t}\n\n\tswitch (algorithm) {\n\t\tcase \"kmeans\": {\n\t\t\tconst themeColor = createThemeColor(entries, ignoreWhite, toLab);\n\t\t\treturn createKMeansPalette(\n\t\t\t\tentries,\n\t\t\t\tnormalizedClusterCount,\n\t\t\t\tthemeColor,\n\t\t\t\tignoreWhite,\n\t\t\t\ttoLab,\n\t\t\t\tuseKMeansPP,\n\t\t\t\tintent,\n\t\t\t);\n\t\t}\n\t\tcase \"octtree\": {\n\t\t\tconst themeColor = createThemeColor(entries, ignoreWhite, true);\n\t\t\treturn createOctTreePalette(\n\t\t\t\tentries,\n\t\t\t\tnormalizedClusterCount,\n\t\t\t\tthemeColor,\n\t\t\t\tignoreWhite,\n\t\t\t\tintent,\n\t\t\t);\n\t\t}\n\t\tdefault:\n\t\t\treturn createAutoPalette(\n\t\t\t\tentries,\n\t\t\t\tnormalizedClusterCount,\n\t\t\t\tignoreWhite,\n\t\t\t\ttoLab,\n\t\t\t\tuseKMeansPP,\n\t\t\t\tintent,\n\t\t\t);\n\t}\n}\n","/**\n * @fileoverview\n * 渲染器的运行环境能力探测。\n *\n * 渲染器的构造函数在拿不到所需上下文时会直接抛错,而 `BackgroundRender.new()`\n * 只是 `new` 一下,没有回落余地。所以选择渲染器的一方(设置界面、从\n * localStorage 恢复配置的地方)应当先问一句支不支持。\n */\n\nlet webgl1Support: boolean | undefined;\nlet webgl2Support: boolean | undefined;\nlet highpFragmentSupport: boolean | undefined;\n\n/**\n * 借一个 1x1 的临时上下文跑一次 `probe`,用完立刻释放。不传 `probe` 就只测能不\n * 能拿到上下文。\n *\n * 拿不到上下文或者探测过程中抛错都算作不支持。\n */\nfunction withProbeContext(\n\tcontextId: \"webgl\" | \"webgl2\",\n\tprobe: (gl: WebGLRenderingContext | WebGL2RenderingContext) => boolean = () =>\n\t\ttrue,\n): boolean {\n\ttry {\n\t\tconst canvas = document.createElement(\"canvas\");\n\t\tcanvas.width = 1;\n\t\tcanvas.height = 1;\n\t\tconst gl = canvas.getContext(contextId) as\n\t\t\t| WebGLRenderingContext\n\t\t\t| WebGL2RenderingContext\n\t\t\t| null;\n\t\tif (!gl) return false;\n\t\ttry {\n\t\t\treturn probe(gl);\n\t\t} finally {\n\t\t\t// 探测用的上下文用完立刻释放,免得白占一个 WebGL 上下文名额\n\t\t\tgl.getExtension(\"WEBGL_lose_context\")?.loseContext();\n\t\t}\n\t} catch {\n\t\treturn false;\n\t}\n}\n\n/** 当前环境是否支持 WebGL1,结果只探测一次。 */\nexport function isWebGL1Supported(): boolean {\n\tif (webgl1Support === undefined) webgl1Support = withProbeContext(\"webgl\");\n\treturn webgl1Support;\n}\n\n/** 当前环境是否支持 WebGL2,结果只探测一次。 */\nexport function isWebGL2Supported(): boolean {\n\tif (webgl2Support === undefined) webgl2Support = withProbeContext(\"webgl2\");\n\treturn webgl2Support;\n}\n\n/**\n * WebGL1 的片元着色器是否支持 highp 浮点,结果只探测一次。\n *\n * 程序化渲染器的着色器里时间项会一直单调累加,噪声哈希又多是\n * `sin(...) * 43758.5453` 这种把误差放大四万倍的写法。mediump 只有 10 位有效\n * 数,播放几分钟后时间项就会量化到肉眼可见的台阶,哈希本身也会退化成条带 ——\n * 与其默默给出破图,不如直接判定为不支持。\n */\nexport function isHighpFragmentSupported(): boolean {\n\tif (highpFragmentSupport === undefined) {\n\t\thighpFragmentSupport = withProbeContext(\"webgl\", (gl) => {\n\t\t\tconst format = gl.getShaderPrecisionFormat(\n\t\t\t\tgl.FRAGMENT_SHADER,\n\t\t\t\tgl.HIGH_FLOAT,\n\t\t\t);\n\t\t\treturn (format?.precision ?? 0) > 0;\n\t\t});\n\t}\n\treturn highpFragmentSupport;\n}\n","/**\n * @fileoverview\n * Isolation 背景渲染器。\n *\n * 使用仓库内实现的四点流动渐变着色器,着色器本体见\n * `isolation.frag.glsl`。\n *\n * 与另外两个渲染器不同,Isolation 完全是程序化的,并不采样封面纹理,而是从封面\n * 里提取四个主色来构造渐变,取色部分见 `../palette/index.ts`。\n */\n\nimport {\n\tloadResourceFromElement,\n\tloadResourceFromUrl,\n} from \"../../utils/resource.ts\";\nimport { BaseRenderer } from \"../base.ts\";\nimport { GLProgram } from \"../gl-program.ts\";\nimport {\n\ttype ColorVec3,\n\tcreatePaletteFromImage,\n\ttype PaletteAlgorithm,\n\tsrgbToOkLab,\n} from \"../palette/index.ts\";\nimport { isHighpFragmentSupported, isWebGL1Supported } from \"../support.ts\";\nimport isolationFragShader from \"./isolation.frag.glsl?raw\";\nimport isolationVertShader from \"./isolation.vert.glsl?raw\";\n\n/** Isolation 渲染器的可调选项。 */\nexport interface IsolationRendererOptions {\n\t/** 是否启用 lightwave 明度调制,默认 `false`。 */\n\tlightWave: boolean;\n\t/** 是否启用屏幕空间抖动,默认 `true`。 */\n\tdithering: boolean;\n\t/** 取色算法,默认 `\"auto\"`。 */\n\tpaletteAlgorithm: PaletteAlgorithm;\n}\n\n/** 换封面时调色板过渡的时长,单位毫秒。 */\nconst PALETTE_TRANSITION_MS = 1000;\n/** 圆周率的两倍,用来给 lightwave 的随机相位取值。 */\nconst TAU = Math.PI * 2;\nconst DEG_TO_RAD = Math.PI / 180;\n/** 渐变用到的颜色数量,也是 {@link colorBuffer} 等缓冲的长度依据。 */\nconst COLOR_COUNT = 4;\n/** 加载封面失败时的重试次数,与其它渲染器保持一致。 */\nconst ALBUM_RETRY_TIMES = 5;\n\n/** 还没拿到封面时用的中性深色配色,分量取值 [0, 1] 的 sRGB。 */\nconst DEFAULT_COLORS: ColorVec3[] = [\n\t[0.09, 0.09, 0.11],\n\t[0.13, 0.13, 0.16],\n\t[0.07, 0.07, 0.09],\n\t[0.11, 0.11, 0.13],\n];\n\nfunction lerp(from: number, to: number, amount: number): number {\n\treturn from + (to - from) * amount;\n}\n\n/**\n * {@link DEFAULT_COLORS} 的 OkLab 形式,四个颜色的分量首尾相接,着色器要的就是\n * 这个。\n *\n * 着色器在 OkLab 空间做感知均匀的混色,而这个转换对整个 draw call 是常量,所以\n * 只在换封面时算一次,不必丢给片元着色器每像素算四次。JS 侧的调色板过渡也因此\n * 和着色器落在同一个色彩空间里,换封面时的中间色不会发暗发浊。\n */\nconst DEFAULT_OKLAB_COLORS = new Float32Array(\n\tDEFAULT_COLORS.flatMap(srgbToOkLab),\n);\n\nexport class IsolationRenderer extends BaseRenderer {\n\t/**\n\t * 新建实例时采用的默认选项。\n\t *\n\t * 该对象也可作为配置界面的初始值;实例创建后的调整统一走\n\t * {@link setOptions}。\n\t */\n\tstatic readonly defaultOptions: Readonly<IsolationRendererOptions> = {\n\t\tlightWave: false,\n\t\tdithering: true,\n\t\tpaletteAlgorithm: \"auto\",\n\t};\n\n\t/** 当前环境是否支持该渲染器,选择渲染器前应先问一句。 */\n\tstatic isSupported(): boolean {\n\t\treturn isWebGL1Supported() && isHighpFragmentSupported();\n\t}\n\n\tprivate gl: WebGLRenderingContext;\n\tprivate program!: GLProgram;\n\tprivate quadBuffer!: WebGLBuffer;\n\tprivate contextLost = false;\n\tprivate _disposed = false;\n\n\tprivate options: IsolationRendererOptions = {\n\t\t...IsolationRenderer.defaultOptions,\n\t};\n\n\tprivate tickHandle = 0;\n\tprivate lastTickTime = 0;\n\tprivate lastFrameTime = 0;\n\tprivate frameTime = 0;\n\tprivate maxFPS = 30;\n\tprivate paused = false;\n\tprivate staticMode = false;\n\n\tprivate targetWidth = 0;\n\tprivate targetHeight = 0;\n\tprivate currentWidth = 0;\n\tprivate currentHeight = 0;\n\n\tprivate albumRequestId = 0;\n\tprivate albumSource?: HTMLImageElement | HTMLVideoElement;\n\n\t/**\n\t * 调色板过渡已经过的毫秒数。\n\t *\n\t * 这里刻意不用 `performance.now()`:过渡必须和渲染时钟走同一套时间,否则\n\t * 暂停、静态模式或限帧的时候过渡进度会和画面对不上。\n\t */\n\tprivate paletteTransitionElapsed = PALETTE_TRANSITION_MS;\n\t/** 过渡起点、终点与当前帧的颜色,均为 OkLab,四个颜色首尾相接。 */\n\tprivate readonly fromColors = new Float32Array(DEFAULT_OKLAB_COLORS);\n\tprivate readonly toColors = new Float32Array(DEFAULT_OKLAB_COLORS);\n\tprivate readonly colorBuffer = new Float32Array(DEFAULT_OKLAB_COLORS);\n\t/** 取色结果的暂存区,避免每次换封面都新建数组。 */\n\tprivate readonly nextColors = new Float32Array(COLOR_COUNT * 3);\n\n\tprivate readonly randomValues = new Float32Array(3);\n\t/**\n\t * 渐变流动参数,依次是波纹频率、波纹幅度、流动速度(已含方向)与渐变轴倾角\n\t * (弧度)。原实现是在片元着色器里用随机哈希现算的,但它们对整个 draw call\n\t * 都是常量,挪到 CPU 上由 {@link rollRandomParameters} 随机一次即可 —— 这里\n\t * 含随机量,若真的逐帧重算,画面会逐帧剧烈跳变。\n\t */\n\tprivate readonly flowParams = new Float32Array(4);\n\t/** 渐变轴叠加在噪声角度上的抖动,单位弧度,同样是整帧常量。 */\n\tprivate angleJitter = 0;\n\tprivate readonly paletteOrder = new Uint8Array(COLOR_COUNT);\n\n\tconstructor(canvas: HTMLCanvasElement) {\n\t\tsuper(canvas);\n\t\tconst gl = canvas.getContext(\"webgl\", {\n\t\t\talpha: false,\n\t\t\tantialias: false,\n\t\t\tdepth: false,\n\t\t\tstencil: false,\n\t\t\tpowerPreference: \"low-power\",\n\t\t});\n\t\tif (!gl) {\n\t\t\tthis.disconnectResizeObserver();\n\t\t\tthrow new Error(\"WebGL not supported\");\n\t\t}\n\t\tthis.gl = gl;\n\t\ttry {\n\t\t\tthis.rollRandomParameters();\n\t\t\tthis.initializeGLResources();\n\t\t} catch (e) {\n\t\t\tthis.program?.dispose();\n\t\t\tgl.getExtension(\"WEBGL_lose_context\")?.loseContext();\n\t\t\tthis.disconnectResizeObserver();\n\t\t\tthrow e;\n\t\t}\n\t\tcanvas.addEventListener(\"webglcontextlost\", this.onContextLost);\n\t\tcanvas.addEventListener(\"webglcontextrestored\", this.onContextRestored);\n\t\tthis.requestTick();\n\t}\n\n\tprivate initializeGLResources(): void {\n\t\tconst gl = this.gl;\n\t\tthis.program = new GLProgram(\n\t\t\tgl,\n\t\t\tisolationVertShader,\n\t\t\tisolationFragShader,\n\t\t\t\"isolation\",\n\t\t);\n\t\tconst buffer = gl.createBuffer();\n\t\tif (!buffer) throw new Error(\"Failed to create quad buffer\");\n\t\tthis.quadBuffer = buffer;\n\t\tgl.bindBuffer(gl.ARRAY_BUFFER, buffer);\n\t\tgl.bufferData(\n\t\t\tgl.ARRAY_BUFFER,\n\t\t\tnew Float32Array([-1, -1, 1, -1, -1, 1, -1, 1, 1, -1, 1, 1]),\n\t\t\tgl.STATIC_DRAW,\n\t\t);\n\t\t// 全程只有这一个程序、这一个缓冲,顶点属性绑好之后不必逐帧重设\n\t\tconst position = this.program.attrs.a_position;\n\t\tgl.enableVertexAttribArray(position);\n\t\tgl.vertexAttribPointer(position, 2, gl.FLOAT, false, 0, 0);\n\t}\n\n\tprivate readonly onContextLost = (event: Event): void => {\n\t\tevent.preventDefault();\n\t\tthis.contextLost = true;\n\t\tif (this.tickHandle) {\n\t\t\tcancelAnimationFrame(this.tickHandle);\n\t\t\tthis.tickHandle = 0;\n\t\t}\n\t};\n\n\tprivate readonly onContextRestored = (): void => {\n\t\tif (this._disposed) return;\n\t\ttry {\n\t\t\tthis.initializeGLResources();\n\t\t} catch (e) {\n\t\t\tthis.program?.dispose();\n\t\t\tconsole.error(\"Failed to restore WebGL resources\", e);\n\t\t\treturn;\n\t\t}\n\t\tthis.contextLost = false;\n\t\tthis.currentWidth = 0;\n\t\tthis.currentHeight = 0;\n\t\t// 丢失期间没有走过帧循环,不重置的话恢复后第一帧的 frameDelta 会被钳到\n\t\t// 上限,让 frameTime 与调色板过渡进度一起突跳\n\t\tthis.resetFrameClock();\n\t\tthis.requestTick();\n\t};\n\n\t/** 重掷整张封面期间保持不变的随机参数,避免画面逐帧跳变。 */\n\tprivate rollRandomParameters(): void {\n\t\tfor (let i = 0; i < this.randomValues.length; i++) {\n\t\t\tthis.randomValues[i] = Math.random() * TAU;\n\t\t}\n\t\tconst direction = Math.random() < 0.5 ? -1 : 1;\n\t\tthis.flowParams[0] = lerp(4.5, 5.5, Math.random());\n\t\tthis.flowParams[1] = lerp(22, 29, Math.random());\n\t\tthis.flowParams[2] = lerp(0.65, 0.85, Math.random()) * direction;\n\t\tthis.flowParams[3] = (-5 + (Math.random() - 0.5) * 12) * DEG_TO_RAD;\n\t\tthis.angleJitter = (Math.random() - 0.5) * 0.3;\n\t\tfor (let i = 0; i < this.paletteOrder.length; i++) {\n\t\t\tthis.paletteOrder[i] = i;\n\t\t}\n\t\tfor (let i = this.paletteOrder.length - 1; i > 0; i--) {\n\t\t\tconst swapIndex = Math.floor(Math.random() * (i + 1));\n\t\t\t[this.paletteOrder[i], this.paletteOrder[swapIndex]] = [\n\t\t\t\tthis.paletteOrder[swapIndex],\n\t\t\t\tthis.paletteOrder[i],\n\t\t\t];\n\t\t}\n\t}\n\n\t/** 调整渲染器选项,会立即生效。 */\n\tsetOptions(patch: Partial<IsolationRendererOptions>): void {\n\t\t// 逐字段取值而不是对象展开:展开会把 `{ lightWave: undefined }` 里的\n\t\t// undefined 也照搬过来,把已有配置抹成空值\n\t\tconst previous = this.options;\n\t\tconst next: IsolationRendererOptions = {\n\t\t\tlightWave: patch.lightWave ?? previous.lightWave,\n\t\t\tdithering: patch.dithering ?? previous.dithering,\n\t\t\tpaletteAlgorithm: patch.paletteAlgorithm ?? previous.paletteAlgorithm,\n\t\t};\n\t\tconst algorithmChanged =\n\t\t\tnext.paletteAlgorithm !== previous.paletteAlgorithm;\n\t\tthis.options = next;\n\t\tif (algorithmChanged && this.albumSource) {\n\t\t\tthis.updatePaletteFromSource(this.albumSource, true);\n\t\t}\n\t\tthis.requestTick();\n\t}\n\n\tprivate updatePaletteFromSource(\n\t\tsource: HTMLImageElement | HTMLVideoElement,\n\t\timmediate = false,\n\t): void {\n\t\tlet palette: [number, number, number][];\n\t\ttry {\n\t\t\tpalette = createPaletteFromImage(source, COLOR_COUNT, {\n\t\t\t\talgorithm: this.options.paletteAlgorithm,\n\t\t\t\t// 取色默认按强调色的取向来:只留与主题色明暗一致的候选(L* 在\n\t\t\t\t// (40, 60) 的中间调会被整段丢掉,封面的标志色落在那儿就没了),\n\t\t\t\t// 亮色封面还偏好更聚拢的一支。背景要的是封面本身的颜色跨度,\n\t\t\t\t// 不是和界面的对比度\n\t\t\t\tintent: \"dominant\",\n\t\t\t}).palette;\n\t\t} catch (err) {\n\t\t\t// 跨域封面会让 getImageData 抛安全错误,此时保持现有配色\n\t\t\tconsole.warn(\"Failed to extract palette from album\", err);\n\t\t\treturn;\n\t\t}\n\t\tfor (let i = 0; i < COLOR_COUNT; i++) {\n\t\t\tconst [red, green, blue] = palette[this.paletteOrder[i]];\n\t\t\tthis.nextColors.set(\n\t\t\t\tsrgbToOkLab([red / 255, green / 255, blue / 255]),\n\t\t\t\ti * 3,\n\t\t\t);\n\t\t}\n\t\tthis.transitionToColors(this.nextColors, immediate);\n\t\tthis.requestTick();\n\t}\n\n\tprivate transitionToColors(next: Float32Array, immediate: boolean): void {\n\t\tif (immediate) {\n\t\t\tthis.fromColors.set(next);\n\t\t} else {\n\t\t\t// 从当前这一帧的实际颜色接着往下过渡,免得连续换封面时颜色回跳\n\t\t\tthis.updateColorBuffer();\n\t\t\tthis.fromColors.set(this.colorBuffer);\n\t\t}\n\t\tthis.toColors.set(next);\n\t\tthis.paletteTransitionElapsed = immediate ? PALETTE_TRANSITION_MS : 0;\n\t}\n\n\t/** 按当前过渡进度就地更新 {@link colorBuffer},不产生任何中间数组。 */\n\tprivate updateColorBuffer(): void {\n\t\tif (this.paletteTransitionElapsed >= PALETTE_TRANSITION_MS) {\n\t\t\tthis.colorBuffer.set(this.toColors);\n\t\t\treturn;\n\t\t}\n\t\tconst progress = this.paletteTransitionElapsed / PALETTE_TRANSITION_MS;\n\t\t// 平滑一下,避免过渡首尾出现颜色突变\n\t\tconst eased = progress * progress * (3 - 2 * progress);\n\t\tfor (let i = 0; i < this.colorBuffer.length; i++) {\n\t\t\tthis.colorBuffer[i] = lerp(this.fromColors[i], this.toColors[i], eased);\n\t\t}\n\t}\n\n\tprivate checkIfResize(): void {\n\t\tif (\n\t\t\tthis.targetWidth === this.currentWidth &&\n\t\t\tthis.targetHeight === this.currentHeight\n\t\t) {\n\t\t\treturn;\n\t\t}\n\t\tsuper.onResize(this.targetWidth, this.targetHeight);\n\t\tthis.currentWidth = this.targetWidth;\n\t\tthis.currentHeight = this.targetHeight;\n\t\tthis.gl.viewport(0, 0, this.targetWidth, this.targetHeight);\n\t}\n\n\tprivate onRedraw(frameTime: number, frameDelta: number): boolean {\n\t\tthis.checkIfResize();\n\t\tif (this.currentWidth <= 0 || this.currentHeight <= 0) return false;\n\n\t\tif (this.paletteTransitionElapsed < PALETTE_TRANSITION_MS) {\n\t\t\tthis.paletteTransitionElapsed += frameDelta;\n\t\t}\n\t\tthis.updateColorBuffer();\n\n\t\tthis.program.use();\n\t\tthis.program.setUniform2f(\n\t\t\t\"u_resolution\",\n\t\t\tthis.currentWidth,\n\t\t\tthis.currentHeight,\n\t\t);\n\t\tthis.program.setUniform1f(\"u_time\", frameTime / 1000);\n\t\tthis.program.setUniform3fv(\"u_colors[0]\", this.colorBuffer);\n\t\tthis.program.setUniform3fv(\"u_random\", this.randomValues);\n\t\tthis.program.setUniform4f(\n\t\t\t\"u_flowParams\",\n\t\t\tthis.flowParams[0],\n\t\t\tthis.flowParams[1],\n\t\t\tthis.flowParams[2],\n\t\t\tthis.flowParams[3],\n\t\t);\n\t\tthis.program.setUniform1f(\"u_angleJitter\", this.angleJitter);\n\t\tthis.program.setUniform1i(\n\t\t\t\"u_enableLightWave\",\n\t\t\tthis.options.lightWave ? 1 : 0,\n\t\t);\n\t\tthis.program.setUniform1i(\n\t\t\t\"u_enableDithering\",\n\t\t\tthis.options.dithering ? 1 : 0,\n\t\t);\n\n\t\tconst gl = this.gl;\n\t\tgl.drawArrays(gl.TRIANGLES, 0, 6);\n\n\t\t// 调色板过渡跑完之后才允许静态模式停下来\n\t\treturn this.paletteTransitionElapsed >= PALETTE_TRANSITION_MS;\n\t}\n\n\tprivate onTick(tickTime: number): void {\n\t\tthis.tickHandle = 0;\n\t\tif (this.paused || this._disposed || this.contextLost) return;\n\n\t\tconst interval = 1000 / this.maxFPS;\n\t\tconst delta = tickTime - this.lastTickTime;\n\t\tif (delta < interval) {\n\t\t\tthis.requestTick();\n\t\t\treturn;\n\t\t}\n\n\t\tif (Number.isNaN(this.lastFrameTime)) this.lastFrameTime = tickTime;\n\t\t// 切后台回来时 delta 会很大,封个顶,否则调色板过渡会一帧跳完\n\t\tconst frameDelta = Math.min(tickTime - this.lastFrameTime, 250);\n\t\tthis.lastFrameTime = tickTime;\n\t\tthis.lastTickTime = tickTime - (delta % interval);\n\n\t\tthis.frameTime += frameDelta * this.flowSpeed;\n\n\t\tif (!(this.onRedraw(this.frameTime, frameDelta) && this.staticMode)) {\n\t\t\tthis.requestTick();\n\t\t} else {\n\t\t\tthis.lastFrameTime = Number.NaN;\n\t\t}\n\t}\n\n\tprivate readonly onTickBinded = this.onTick.bind(this);\n\n\tprivate requestTick(): void {\n\t\tif (this._disposed || this.paused || this.contextLost) return;\n\t\t// 写成 `!(maxFPS > 0)` 而不是 `maxFPS <= 0`,是为了连 NaN 一起挡掉\n\t\tif (!(this.maxFPS > 0)) return;\n\t\tif (this.tickHandle === 0) {\n\t\t\tthis.tickHandle = requestAnimationFrame(this.onTickBinded);\n\t\t}\n\t}\n\n\tprotected override onResize(width: number, height: number): void {\n\t\tthis.targetWidth = Math.ceil(width);\n\t\tthis.targetHeight = Math.ceil(height);\n\t\tthis.requestTick();\n\t}\n\n\toverride setStaticMode(enable: boolean): void {\n\t\tthis.staticMode = enable;\n\t\tthis.resetFrameClock();\n\t\tthis.requestTick();\n\t}\n\n\toverride setFPS(fps: number): void {\n\t\tthis.maxFPS = fps;\n\t\tthis.resetFrameClock();\n\t\tthis.requestTick();\n\t}\n\n\toverride pause(): void {\n\t\tif (this.tickHandle) {\n\t\t\tcancelAnimationFrame(this.tickHandle);\n\t\t\tthis.tickHandle = 0;\n\t\t}\n\t\tthis.paused = true;\n\t}\n\n\toverride resume(): void {\n\t\tthis.paused = false;\n\t\tthis.resetFrameClock();\n\t\tthis.requestTick();\n\t}\n\n\tprivate resetFrameClock(): void {\n\t\tconst now = performance.now();\n\t\tthis.lastFrameTime = now;\n\t\tthis.lastTickTime = now;\n\t}\n\n\t/**\n\t * 该次 `setAlbum` 是否还是最新的一次。\n\t *\n\t * 与 `MeshGradientRenderer` 不同,这里不看 `contextLost`:取色全在 CPU\n\t * 上做,上下文丢了也照样能把调色板算完存着,等上下文恢复直接就能画。\n\t */\n\tprivate isCurrentAlbumRequest(requestId: number): boolean {\n\t\treturn !this._disposed && requestId === this.albumRequestId;\n\t}\n\n\toverride async setAlbum(\n\t\talbumSource?: string | HTMLImageElement | HTMLVideoElement,\n\t\tisVideo?: boolean,\n\t): Promise<void> {\n\t\tconst requestId = ++this.albumRequestId;\n\t\tif (\n\t\t\talbumSource === undefined ||\n\t\t\t(typeof albumSource === \"string\" && albumSource.trim().length === 0)\n\t\t) {\n\t\t\tthis.albumSource = undefined;\n\t\t\tthis.transitionToColors(DEFAULT_OKLAB_COLORS, false);\n\t\t\tthis.requestTick();\n\t\t\treturn;\n\t\t}\n\n\t\tlet source: HTMLImageElement | HTMLVideoElement | null = null;\n\t\tlet remainRetryTimes = ALBUM_RETRY_TIMES;\n\t\twhile (!source && remainRetryTimes > 0) {\n\t\t\ttry {\n\t\t\t\tsource =\n\t\t\t\t\ttypeof albumSource === \"string\"\n\t\t\t\t\t\t? await loadResourceFromUrl(albumSource, isVideo)\n\t\t\t\t\t\t: await loadResourceFromElement(albumSource);\n\t\t\t} catch (error) {\n\t\t\t\tif (!this.isCurrentAlbumRequest(requestId)) return;\n\t\t\t\tremainRetryTimes--;\n\t\t\t\tconsole.warn(\n\t\t\t\t\t`failed on loading album resource, retrying (${remainRetryTimes})`,\n\t\t\t\t\t{ albumSource, error },\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t\tif (!this.isCurrentAlbumRequest(requestId)) return;\n\t\tif (!source) {\n\t\t\tconsole.error(\"Failed to load album resource\", albumSource);\n\t\t\treturn;\n\t\t}\n\n\t\tthis.albumSource = source;\n\t\tthis.rollRandomParameters();\n\t\t// 视频封面只取首帧的主色:取色是同步的重活,按秒重复跑会在主线程上留下\n\t\t// 周期性卡顿,MeshGradientRenderer 也是这么处理的\n\t\tthis.updatePaletteFromSource(source);\n\t}\n\n\toverride setLowFreqVolume(_volume: number): void {\n\t\t// Isolation 是纯程序化的渐变,不随音量变化\n\t}\n\n\toverride setHasLyric(_hasLyric: boolean): void {\n\t\t// Isolation 的观感与是否有歌词无关,这里不做处理\n\t}\n\n\toverride dispose(): void {\n\t\tif (this._disposed) return;\n\t\tthis._disposed = true;\n\t\tif (this.tickHandle) {\n\t\t\tcancelAnimationFrame(this.tickHandle);\n\t\t\tthis.tickHandle = 0;\n\t\t}\n\t\tthis.canvas.removeEventListener(\"webglcontextlost\", this.onContextLost);\n\t\tthis.canvas.removeEventListener(\n\t\t\t\"webglcontextrestored\",\n\t\t\tthis.onContextRestored,\n\t\t);\n\t\tthis.program.dispose();\n\t\tthis.gl.deleteBuffer(this.quadBuffer);\n\t\tthis.gl.getExtension(\"WEBGL_lose_context\")?.loseContext();\n\t\tsuper.dispose();\n\t}\n}\n","export function clamp(x: number, min: number, max: number): number {\n\treturn Math.min(Math.max(x, min), max);\n}\n\nexport function clamp01(x: number): number {\n\treturn clamp(x, 0, 1);\n}\n\nexport function clampPositive(x: number): number {\n\treturn Math.max(0, x);\n}\n","export function blurImage(\n\timageData: ImageData,\n\tradius: number,\n\tquality: number,\n): void {\n\tconst pixels = imageData.data;\n\tconst width = imageData.width;\n\tconst height = imageData.height;\n\n\tlet rsum: number;\n\tlet gsum: number;\n\tlet bsum: number;\n\tlet asum: number;\n\tlet x: number;\n\tlet y: number;\n\tlet i: number;\n\tlet p: number;\n\tlet p1: number;\n\tlet p2: number;\n\tlet yp: number;\n\tlet yi: number;\n\tlet yw: number;\n\tconst wm = width - 1;\n\tconst hm = height - 1;\n\tconst rad1x = radius + 1;\n\tconst divx = radius + rad1x;\n\tconst rad1y = radius + 1;\n\tconst divy = radius + rad1y;\n\tconst div2 = 1 / (divx * divy);\n\n\tconst r: number[] = [];\n\tconst g: number[] = [];\n\tconst b: number[] = [];\n\tconst a: number[] = [];\n\n\tconst vmin: number[] = [];\n\tconst vmax: number[] = [];\n\n\twhile (quality-- > 0) {\n\t\tyw = yi = 0;\n\n\t\tfor (y = 0; y < height; y++) {\n\t\t\trsum = pixels[yw] * rad1x;\n\t\t\tgsum = pixels[yw + 1] * rad1x;\n\t\t\tbsum = pixels[yw + 2] * rad1x;\n\t\t\tasum = pixels[yw + 3] * rad1x;\n\n\t\t\tfor (i = 1; i <= radius; i++) {\n\t\t\t\tp = yw + ((i > wm ? wm : i) << 2);\n\t\t\t\trsum += pixels[p++];\n\t\t\t\tgsum += pixels[p++];\n\t\t\t\tbsum += pixels[p++];\n\t\t\t\tasum += pixels[p];\n\t\t\t}\n\n\t\t\tfor (x = 0; x < width; x++) {\n\t\t\t\tr[yi] = rsum;\n\t\t\t\tg[yi] = gsum;\n\t\t\t\tb[yi] = bsum;\n\t\t\t\ta[yi] = asum;\n\n\t\t\t\tif (y === 0) {\n\t\t\t\t\tvmin[x] = Math.min(x + rad1x, wm) << 2;\n\t\t\t\t\tvmax[x] = Math.max(x - radius, 0) << 2;\n\t\t\t\t}\n\n\t\t\t\tp1 = yw + vmin[x];\n\t\t\t\tp2 = yw + vmax[x];\n\n\t\t\t\trsum += pixels[p1++] - pixels[p2++];\n\t\t\t\tgsum += pixels[p1++] - pixels[p2++];\n\t\t\t\tbsum += pixels[p1++] - pixels[p2++];\n\t\t\t\tasum += pixels[p1] - pixels[p2];\n\n\t\t\t\tyi++;\n\t\t\t}\n\t\t\tyw += width << 2;\n\t\t}\n\n\t\tfor (x = 0; x < width; x++) {\n\t\t\typ = x;\n\t\t\trsum = r[yp] * rad1y;\n\t\t\tgsum = g[yp] * rad1y;\n\t\t\tbsum = b[yp] * rad1y;\n\t\t\tasum = a[yp] * rad1y;\n\n\t\t\tfor (i = 1; i <= radius; i++) {\n\t\t\t\typ += i > hm ? 0 : width;\n\t\t\t\trsum += r[yp];\n\t\t\t\tgsum += g[yp];\n\t\t\t\tbsum += b[yp];\n\t\t\t\tasum += a[yp];\n\t\t\t}\n\n\t\t\tyi = x << 2;\n\t\t\tfor (y = 0; y < height; y++) {\n\t\t\t\tpixels[yi] = (rsum * div2 + 0.5) | 0;\n\t\t\t\tpixels[yi + 1] = (gsum * div2 + 0.5) | 0;\n\t\t\t\tpixels[yi + 2] = (bsum * div2 + 0.5) | 0;\n\t\t\t\tpixels[yi + 3] = (asum * div2 + 0.5) | 0;\n\n\t\t\t\tif (x === 0) {\n\t\t\t\t\tvmin[y] = Math.min(y + rad1y, hm) * width;\n\t\t\t\t\tvmax[y] = Math.max(y - radius, 0) * width;\n\t\t\t\t}\n\n\t\t\t\tp1 = x + vmin[y];\n\t\t\t\tp2 = x + vmax[y];\n\n\t\t\t\trsum += r[p1] - r[p2];\n\t\t\t\tgsum += g[p1] - g[p2];\n\t\t\t\tbsum += b[p1] - b[p2];\n\t\t\t\tasum += a[p1] - a[p2];\n\n\t\t\t\tyi += width << 2;\n\t\t\t}\n\t\t}\n\t}\n}\n\nexport function saturateImage(imageData: ImageData, saturation: number): void {\n\tconst pixels = imageData.data;\n\n\tfor (let i = 0; i < pixels.length; i += 4) {\n\t\tconst r = pixels[i];\n\t\tconst g = pixels[i + 1];\n\t\tconst b = pixels[i + 2];\n\t\tconst a = pixels[i + 3];\n\t\tconst gray = r * 0.3 + g * 0.59 + b * 0.11;\n\t\tpixels[i] = gray * (1 - saturation) + r * saturation;\n\t\tpixels[i + 1] = gray * (1 - saturation) + g * saturation;\n\t\tpixels[i + 2] = gray * (1 - saturation) + b * saturation;\n\t\tpixels[i + 3] = a;\n\t}\n}\n\nexport function brightnessImage(\n\timageData: ImageData,\n\tbrightness: number,\n): void {\n\tconst pixels = imageData.data;\n\n\tfor (let i = 0; i < pixels.length; i += 4) {\n\t\tconst r = pixels[i];\n\t\tconst g = pixels[i + 1];\n\t\tconst b = pixels[i + 2];\n\t\tconst a = pixels[i + 3];\n\t\tpixels[i] = r * brightness;\n\t\tpixels[i + 1] = g * brightness;\n\t\tpixels[i + 2] = b * brightness;\n\t\tpixels[i + 3] = a;\n\t}\n}\n\nexport function contrastImage(imageData: ImageData, contrast: number): void {\n\tconst pixels = imageData.data;\n\n\tfor (let i = 0; i < pixels.length; i += 4) {\n\t\tconst r = pixels[i];\n\t\tconst g = pixels[i + 1];\n\t\tconst b = pixels[i + 2];\n\t\tconst a = pixels[i + 3];\n\t\tpixels[i] = (r - 128) * contrast + 128;\n\t\tpixels[i + 1] = (g - 128) * contrast + 128;\n\t\tpixels[i + 2] = (b - 128) * contrast + 128;\n\t\tpixels[i + 3] = a;\n\t}\n}\n","/** @internal */\nexport interface ControlPointConf {\n\tcx: number;\n\tcy: number;\n\tx: number;\n\ty: number;\n\tur: number;\n\tvr: number;\n\tup: number;\n\tvp: number;\n}\n\n/** @internal */\nexport interface ControlPointPreset {\n\twidth: number;\n\theight: number;\n\tconf: ControlPointConf[];\n}\n\n/** @internal */\nexport const p = (\n\tcx: number,\n\tcy: number,\n\tx: number,\n\ty: number,\n\tur = 0,\n\tvr = 0,\n\tup = 1,\n\tvp = 1,\n) => Object.freeze({ cx, cy, x, y, ur, vr, up, vp }) as ControlPointConf;\n/** @internal */\nexport const preset = (\n\twidth: number,\n\theight: number,\n\tconf: ControlPointConf[],\n) => Object.freeze({ width, height, conf }) as ControlPointPreset;\n\nexport const CONTROL_POINT_PRESETS: ControlPointPreset[] = [\n\t// TODO: 竖屏推荐\n\tpreset(5, 5, [\n\t\tp(0, 0, -1, -1, 0, 0, 1, 1),\n\t\tp(1, 0, -0.5, -1, 0, 0, 1, 1),\n\t\tp(2, 0, 0, -1, 0, 0, 1, 1),\n\t\tp(3, 0, 0.5, -1, 0, 0, 1, 1),\n\t\tp(4, 0, 1, -1, 0, 0, 1, 1),\n\t\tp(0, 1, -1, -0.5, 0, 0, 1, 1),\n\t\tp(1, 1, -0.5, -0.5, 0, 0, 1, 1),\n\t\tp(2, 1, -0.0052029684413368305, -0.6131420587090777, 0, 0, 1, 1),\n\t\tp(3, 1, 0.5884227308309977, -0.3990805107556692, 0, 0, 1, 1),\n\t\tp(4, 1, 1, -0.5, 0, 0, 1, 1),\n\t\tp(0, 2, -1, 0, 0, 0, 1, 1),\n\t\tp(1, 2, -0.4210024670505933, -0.11895058380429502, 0, 0, 1, 1),\n\t\tp(2, 2, -0.1019613423315412, -0.023812118047224606, 0, -47, 0.629, 0.849),\n\t\tp(3, 2, 0.40275125660925437, -0.06345314544600389, 0, 0, 1, 1),\n\t\tp(4, 2, 1, 0, 0, 0, 1, 1),\n\t\tp(0, 3, -1, 0.5, 0, 0, 1, 1),\n\t\tp(1, 3, 0.06801958477287173, 0.5205913248960121, -31, -45, 1, 1),\n\t\tp(2, 3, 0.21446469120128908, 0.29331610114301043, 6, -56, 0.566, 1.321),\n\t\tp(3, 3, 0.5, 0.5, 0, 0, 1, 1),\n\t\tp(4, 3, 1, 0.5, 0, 0, 1, 1),\n\t\tp(0, 4, -1, 1, 0, 0, 1, 1),\n\t\tp(1, 4, -0.31378372841550195, 1, 0, 0, 1, 1),\n\t\tp(2, 4, 0.26153633255328046, 1, 0, 0, 1, 1),\n\t\tp(3, 4, 0.5, 1, 0, 0, 1, 1),\n\t\tp(4, 4, 1, 1, 0, 0, 1, 1),\n\t]),\n\t// TODO: 横屏推荐\n\tpreset(4, 4, [\n\t\tp(0, 0, -1, -1, 0, 0, 1, 1),\n\t\tp(1, 0, -0.33333333333333337, -1, 0, 0, 1, 1),\n\t\tp(2, 0, 0.33333333333333326, -1, 0, 0, 1, 1),\n\t\tp(3, 0, 1, -1, 0, 0, 1, 1),\n\t\tp(0, 1, -1, -0.04495399932657351, 0, 0, 1, 1),\n\t\tp(1, 1, -0.24056117520129328, -0.22465999020104, 0, 0, 1, 1),\n\t\tp(2, 1, 0.334758885767489, -0.00531297192779423, 0, 0, 1, 1),\n\t\tp(3, 1, 0.9989920470678106, -0.3382976020775408, 8, 0, 0.566, 1.792),\n\t\tp(0, 2, -1, 0.33333333333333326, 0, 0, 1, 1),\n\t\tp(1, 2, -0.3425497314639411, -0.000027501607956947893, 0, 0, 1, 1),\n\t\tp(2, 2, 0.3321437945812673, 0.1981776353859399, 0, 0, 1, 1),\n\t\tp(3, 2, 1, 0.0766118180296832, 0, 0, 1, 1),\n\t\tp(0, 3, -1, 1, 0, 0, 1, 1),\n\t\tp(1, 3, -0.33333333333333337, 1, 0, 0, 1, 1),\n\t\tp(2, 3, 0.33333333333333326, 1, 0, 0, 1, 1),\n\t\tp(3, 3, 1, 1, 0, 0, 1, 1),\n\t]),\n\tpreset(4, 4, [\n\t\tp(0, 0, -1, -1, 0, 0, 1, 2.075),\n\t\tp(1, 0, -0.33333333333333337, -1, 0, 0, 1, 1),\n\t\tp(2, 0, 0.33333333333333326, -1, 0, 0, 1, 1),\n\t\tp(3, 0, 1, -1, 0, 0, 1, 1),\n\t\tp(0, 1, -1, -0.4545779491139603, 0, 0, 1, 1),\n\t\tp(1, 1, -0.33333333333333337, -0.33333333333333337, 0, 0, 1, 1),\n\t\tp(2, 1, 0.0889403142626457, -0.6025711180694033, -32, 45, 1, 1),\n\t\tp(3, 1, 1, -0.33333333333333337, 0, 0, 1, 1),\n\t\tp(0, 2, -1, -0.07402408608567845, 1, 0, 1, 0.094),\n\t\tp(1, 2, -0.2719422694359541, 0.09775369930903222, 25, -18, 1.321, 0),\n\t\tp(2, 2, 0.19877414408395877, 0.4307383294587789, 48, -40, 0.755, 0.975),\n\t\tp(3, 2, 1, 0.33333333333333326, -37, 0, 1, 1),\n\t\tp(0, 3, -1, 1, 0, 0, 1, 1),\n\t\tp(1, 3, -0.33333333333333337, 1, 0, 0, 1, 1),\n\t\tp(2, 3, 0.5125850864305672, 1, -20, -18, 0, 1.604),\n\t\tp(3, 3, 1, 1, 0, 0, 1, 1),\n\t]),\n\tpreset(5, 5, [\n\t\tp(0, 0, -1, -1, 0, 0, 1, 1),\n\t\tp(1, 0, -0.4501953125, -1, 0, 55, 1, 2.075),\n\t\tp(2, 0, 0.1953125, -1, 0, 0, 1, 1),\n\t\tp(3, 0, 0.4580078125, -1, 0, -25, 1, 1),\n\t\tp(4, 0, 1, -1, 0, 0, 1, 1),\n\t\tp(0, 1, -1, -0.2514475377525607, -16, 0, 2.327, 0.943),\n\t\tp(1, 1, -0.55859375, -0.6609325945787148, 47, 0, 2.358, 0.377),\n\t\tp(2, 1, 0.232421875, -0.5244375756366635, -66, -25, 1.855, 1.164),\n\t\tp(3, 1, 0.685546875, -0.3753706470552125, 0, 0, 1, 1),\n\t\tp(4, 1, 1, -0.6699125300354287, 0, 0, 1, 1),\n\t\tp(0, 2, -1, 0.035910396862284255, 0, 0, 1, 1),\n\t\tp(1, 2, -0.4921875, 0.005378616309457018, 90, 23, 1, 1.981),\n\t\tp(2, 2, 0.021484375, -0.1365043639066228, 0, 42, 1, 1),\n\t\tp(3, 2, 0.4765625, 0.05925822904974043, -30, 0, 1.95, 0.44),\n\t\tp(4, 2, 1, 0.251428847823418, 0, 0, 1, 1),\n\t\tp(0, 3, -1, 0.6968336464764276, -68, 0, 1, 0.786),\n\t\tp(1, 3, -0.6904296875, 0.5890744209958608, -68, 0, 1, 1),\n\t\tp(2, 3, 0.1845703125, 0.3879238667654693, 61, 0, 1, 1),\n\t\tp(3, 3, 0.60546875, 0.4633553246018661, -47, -59, 0.849, 1.73),\n\t\tp(4, 3, 1, 0.6214021886400309, -33, 0, 0.377, 1.604),\n\t\tp(0, 4, -1, 1, 0, 0, 1, 1),\n\t\tp(1, 4, -0.5, 1, 0, -73, 1, 1),\n\t\tp(2, 4, -0.3271484375, 1, 0, -24, 0.314, 2.704),\n\t\tp(3, 4, 0.5, 1, 0, 0, 1, 1),\n\t\tp(4, 4, 1, 1, 0, 0, 1, 1),\n\t]),\n\tpreset(5, 5, [\n\t\tp(0, 0, -1, -1),\n\t\tp(1, 0, -0.6393, -1, 0, 0, 1, 2.3884),\n\t\tp(2, 0, 0, -1),\n\t\tp(3, 0, 0.5, -1),\n\t\tp(4, 0, 1, -1),\n\t\tp(0, 1, -1, -0.2301),\n\t\tp(1, 1, -0.6934, -0.331, 0, -0.7188, 1, 1.063),\n\t\tp(2, 1, -0.0082, -0.6814, -0.2583, 0, 1.0964, 1),\n\t\tp(3, 1, 0.5836, -0.531, 0.7029, 0, 1.5466, 1),\n\t\tp(4, 1, 1, -0.6407),\n\t\tp(0, 2, -1, 0.2973, 0, 0, 1.8352, 1),\n\t\tp(1, 2, -0.4082, 0.0602),\n\t\tp(2, 2, -0.1803, -0.3646, -0.2998, 0, 1.1513, 1),\n\t\tp(3, 2, 0.477, -0.1027, 0.8903, -0.1882, 1.0807, 0.8551),\n\t\tp(4, 2, 1, -0.2973),\n\t\tp(0, 3, -1, 0.7628, 0, 0, 2.3868, 1),\n\t\tp(1, 3, -0.2525, 0.4814, -0.8406, -1.6199, 1.4093, 1.2215),\n\t\tp(2, 3, 0.3607, 0.2814, -1.0713, -0.0529, 1.0025, 0.7611),\n\t\tp(3, 3, 0.4885, 0.623, 0, 0.8184, 1, 1.2876),\n\t\tp(4, 3, 1, 0.5),\n\t\tp(0, 4, -1, 1),\n\t\tp(1, 4, -0.4033, 1),\n\t\tp(2, 4, 0.2672, 1),\n\t\tp(3, 4, 0.5967, 1),\n\t\tp(4, 4, 1, 1),\n\t]),\n\tpreset(5, 5, [\n\t\tp(0, 0, -1, -1),\n\t\tp(1, 0, -0.2197, -1),\n\t\tp(2, 0, 0.0197, -1),\n\t\tp(3, 0, 0.8033, -1),\n\t\tp(4, 0, 1, -1),\n\t\tp(0, 1, -1, -0.5451),\n\t\tp(1, 1, -0.4885, -0.4035, -1.0246, -0.2268, 1.1936, 0.8005),\n\t\tp(2, 1, -0.1213, -0.2867, 0, -0.6981, 1, 0.809),\n\t\tp(3, 1, 0.3246, -0.5628, 0, -1.2188, 1, 1.044),\n\t\tp(4, 1, 1, -0.3292),\n\t\tp(0, 2, -1, 0.1416),\n\t\tp(1, 2, -0.341, -0.0142, 0, -0.4004, 1, 1.1293),\n\t\tp(2, 2, -0.0393, -0.023, 0.2915, -0.373, 1.044, 0.9879),\n\t\tp(3, 2, 0.3148, -0.0673, -0.7853, -0.8962, 1.4709, 1.0247),\n\t\tp(4, 2, 1, 0.1912),\n\t\tp(0, 3, -1, 0.5),\n\t\tp(1, 3, -0.2689, 0.2743, 0.3404, -0.5248, 1.0184, 0.4391),\n\t\tp(2, 3, 0.0721, 0.269, 0.5302, 0.1244, 0.6723, 0.3225),\n\t\tp(3, 3, 0.4148, 0.3894, -0.6977, -0.6783, 0.8094, 0.9247),\n\t\tp(4, 3, 1, 0.446),\n\t\tp(0, 4, -1, 1),\n\t\tp(1, 4, -0.7311, 1),\n\t\tp(2, 4, 0.323, 1),\n\t\tp(3, 4, 0.6393, 1),\n\t\tp(4, 4, 1, 1),\n\t]),\n] as const;\n","/**\n * @fileoverview\n * 实验性的随机控制点生成函数算法\n * 目的是取代原先大量的预设控制点代码\n */\n\nimport { clamp01 } from \"#utils/clamp.ts\";\nimport {\n\ttype ControlPointConf,\n\ttype ControlPointPreset,\n\tp,\n\tpreset,\n} from \"./cp-presets.ts\";\n\nconst randomRange = (min: number, max: number): number =>\n\tMath.random() * (max - min) + min;\n\nfunction smoothstep(edge0: number, edge1: number, x: number): number {\n\tconst t = clamp01((x - edge0) / (edge1 - edge0));\n\treturn t * t * (3 - 2 * t);\n}\n\nfunction smoothifyControlPoints(\n\tconf: ControlPointConf[],\n\tw: number,\n\th: number,\n\titerations = 2,\n\tfactor = 0.5,\n\tfactorIterationModifier = 0.1,\n): void {\n\tlet grid: ControlPointConf[][] = [];\n\tlet f = factor;\n\n\tfor (let j = 0; j < h; j++) {\n\t\tgrid[j] = [];\n\t\tfor (let i = 0; i < w; i++) {\n\t\t\tgrid[j][i] = conf[j * w + i];\n\t\t}\n\t}\n\n\tconst kernel = [\n\t\t[1, 2, 1],\n\t\t[2, 4, 2],\n\t\t[1, 2, 1],\n\t];\n\tconst kernelSum = 16;\n\n\tfor (let iter = 0; iter < iterations; iter++) {\n\t\tconst newGrid: ControlPointConf[][] = [];\n\t\tfor (let j = 0; j < h; j++) {\n\t\t\tnewGrid[j] = [];\n\t\t\tfor (let i = 0; i < w; i++) {\n\t\t\t\tif (i === 0 || i === w - 1 || j === 0 || j === h - 1) {\n\t\t\t\t\tnewGrid[j][i] = grid[j][i];\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tlet sumX = 0;\n\t\t\t\tlet sumY = 0;\n\t\t\t\tlet sumUR = 0;\n\t\t\t\tlet sumVR = 0;\n\t\t\t\tlet sumUP = 0;\n\t\t\t\tlet sumVP = 0;\n\t\t\t\tfor (let dj = -1; dj <= 1; dj++) {\n\t\t\t\t\tfor (let di = -1; di <= 1; di++) {\n\t\t\t\t\t\tconst weight = kernel[dj + 1][di + 1];\n\t\t\t\t\t\tconst nb = grid[j + dj][i + di];\n\t\t\t\t\t\tsumX += nb.x * weight;\n\t\t\t\t\t\tsumY += nb.y * weight;\n\t\t\t\t\t\tsumUR += nb.ur * weight;\n\t\t\t\t\t\tsumVR += nb.vr * weight;\n\t\t\t\t\t\tsumUP += nb.up * weight;\n\t\t\t\t\t\tsumVP += nb.vp * weight;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tconst avgX = sumX / kernelSum;\n\t\t\t\tconst avgY = sumY / kernelSum;\n\t\t\t\tconst avgUR = sumUR / kernelSum;\n\t\t\t\tconst avgVR = sumVR / kernelSum;\n\t\t\t\tconst avgUP = sumUP / kernelSum;\n\t\t\t\tconst avgVP = sumVP / kernelSum;\n\n\t\t\t\tconst cur = grid[j][i];\n\t\t\t\tconst newX = cur.x * (1 - f) + avgX * f;\n\t\t\t\tconst newY = cur.y * (1 - f) + avgY * f;\n\t\t\t\tconst newUR = cur.ur * (1 - f) + avgUR * f;\n\t\t\t\tconst newVR = cur.vr * (1 - f) + avgVR * f;\n\t\t\t\tconst newUP = cur.up * (1 - f) + avgUP * f;\n\t\t\t\tconst newVP = cur.vp * (1 - f) + avgVP * f;\n\t\t\t\tnewGrid[j][i] = p(i, j, newX, newY, newUR, newVR, newUP, newVP);\n\t\t\t}\n\t\t}\n\t\tgrid = newGrid;\n\t\tf = clamp01(f + factorIterationModifier);\n\t}\n\n\tfor (let j = 0; j < h; j++) {\n\t\tfor (let i = 0; i < w; i++) {\n\t\t\tconf[j * w + i] = grid[j][i];\n\t\t}\n\t}\n}\n\nfunction noise(x: number, y: number): number {\n\treturn fract(Math.sin(x * 12.9898 + y * 78.233) * 43758.5453);\n}\n\nfunction fract(x: number): number {\n\treturn x - Math.floor(x);\n}\n\nfunction smoothNoise(x: number, y: number): number {\n\tconst x0 = Math.floor(x);\n\tconst y0 = Math.floor(y);\n\tconst x1 = x0 + 1;\n\tconst y1 = y0 + 1;\n\n\tconst xf = x - x0;\n\tconst yf = y - y0;\n\n\tconst u = xf * xf * (3 - 2 * xf);\n\tconst v = yf * yf * (3 - 2 * yf);\n\n\tconst n00 = noise(x0, y0);\n\tconst n10 = noise(x1, y0);\n\tconst n01 = noise(x0, y1);\n\tconst n11 = noise(x1, y1);\n\n\tconst nx0 = n00 * (1 - u) + n10 * u;\n\tconst nx1 = n01 * (1 - u) + n11 * u;\n\n\treturn nx0 * (1 - v) + nx1 * v;\n}\n\nfunction computeNoiseGradient(\n\tperlinFn: (x: number, y: number) => number,\n\tx: number,\n\ty: number,\n\tepsilon = 0.001,\n): [number, number] {\n\tconst n1 = perlinFn(x + epsilon, y);\n\tconst n2 = perlinFn(x - epsilon, y);\n\tconst n3 = perlinFn(x, y + epsilon);\n\tconst n4 = perlinFn(x, y - epsilon);\n\tconst dx = (n1 - n2) / (2 * epsilon);\n\tconst dy = (n3 - n4) / (2 * epsilon);\n\tconst len = Math.sqrt(dx * dx + dy * dy) || 1;\n\treturn [dx / len, dy / len];\n}\n\nexport function generateControlPoints(\n\twidth: number,\n\theight: number,\n\tvariationFraction: number = randomRange(0.4, 0.6), // = 0.2,\n\tnormalOffset: number = randomRange(0.3, 0.6), // = 0.3,\n\tblendFactor = 0.8,\n\tsmoothIters: number = Math.floor(randomRange(3, 5)), // = 3,\n\tsmoothFactor: number = randomRange(0.2, 0.3), // = 0.3,\n\tsmoothModifier: number = randomRange(-0.1, -0.05), // = -0.05,\n): ControlPointPreset {\n\tconst w = width ?? Math.floor(randomRange(3, 6));\n\tconst h = height ?? Math.floor(randomRange(3, 6));\n\n\tconst conf: ControlPointConf[] = [];\n\tconst dx = w === 1 ? 0 : 2 / (w - 1);\n\tconst dy = h === 1 ? 0 : 2 / (h - 1);\n\n\tfor (let j = 0; j < h; j++) {\n\t\tfor (let i = 0; i < w; i++) {\n\t\t\tconst baseX = (w === 1 ? 0 : i / (w - 1)) * 2 - 1;\n\t\t\tconst baseY = (h === 1 ? 0 : j / (h - 1)) * 2 - 1;\n\n\t\t\tconst isBorder = i === 0 || i === w - 1 || j === 0 || j === h - 1;\n\t\t\tconst pertX = isBorder\n\t\t\t\t? 0\n\t\t\t\t: randomRange(-variationFraction * dx, variationFraction * dx);\n\t\t\tconst pertY = isBorder\n\t\t\t\t? 0\n\t\t\t\t: randomRange(-variationFraction * dy, variationFraction * dy);\n\t\t\tlet x = baseX + pertX;\n\t\t\tlet y = baseY + pertY;\n\n\t\t\tconst ur = isBorder ? 0 : randomRange(-60, 60);\n\t\t\tconst vr = isBorder ? 0 : randomRange(-60, 60);\n\t\t\tconst up = isBorder ? 1 : randomRange(0.8, 1.2);\n\t\t\tconst vp = isBorder ? 1 : randomRange(0.8, 1.2);\n\n\t\t\tif (!isBorder) {\n\t\t\t\tconst uNorm = (baseX + 1) / 2;\n\t\t\t\tconst vNorm = (baseY + 1) / 2;\n\n\t\t\t\tconst [nx, ny] = computeNoiseGradient(smoothNoise, uNorm, vNorm, 0.001);\n\t\t\t\tlet offsetX = nx * normalOffset;\n\t\t\t\tlet offsetY = ny * normalOffset;\n\n\t\t\t\tconst distToBorder = Math.min(uNorm, 1 - uNorm, vNorm, 1 - vNorm); // in [0,0.5]\n\n\t\t\t\tconst weight = smoothstep(0, 1.0, distToBorder);\n\t\t\t\toffsetX *= weight;\n\t\t\t\toffsetY *= weight;\n\n\t\t\t\tx = x * (1 - blendFactor) + (x + offsetX) * blendFactor;\n\t\t\t\ty = y * (1 - blendFactor) + (y + offsetY) * blendFactor;\n\t\t\t}\n\t\t\tconf.push(p(i, j, x, y, ur, vr, up, vp));\n\t\t}\n\t}\n\n\tsmoothifyControlPoints(conf, w, h, smoothIters, smoothFactor, smoothModifier);\n\n\treturn preset(w, h, conf);\n}\n","/**\n * @fileoverview\n * 基于 Mesh Gradient 渐变渲染的渲染器\n * 此渲染应该是 Apple Music 使用的背景渲染方式了\n * 参考内容 https://movingparts.io/gradient-meshes\n */\n\nimport { Mat4, Vec2, Vec3, Vec4 } from \"gl-matrix\";\nimport { createOffscreenCanvas } from \"#utils/canvas.ts\";\nimport { clamp01 } from \"#utils/clamp.ts\";\nimport type { Disposable } from \"../../interfaces.ts\";\nimport {\n\tloadResourceFromElement,\n\tloadResourceFromUrl,\n} from \"../../utils/resource.ts\";\nimport { BaseRenderer } from \"../base.ts\";\nimport { GLProgram } from \"../gl-program.ts\";\nimport { blurImage } from \"../img.ts\";\nimport { isWebGL1Supported } from \"../support.ts\";\nimport { generateControlPoints } from \"./cp-generate.ts\";\nimport { CONTROL_POINT_PRESETS } from \"./cp-presets.ts\";\nimport meshFragShader from \"./mesh.frag.glsl?raw\";\nimport meshVertShader from \"./mesh.vert.glsl?raw\";\n\nconst quadVertShader = `\nattribute vec2 a_pos;\nvarying vec2 v_uv;\nvoid main() {\n gl_Position = vec4(a_pos, 0.0, 1.0);\n v_uv = a_pos * 0.5 + 0.5;\n}\n`;\n\nconst quadFragShader = `\nprecision mediump float;\nvarying vec2 v_uv;\nuniform sampler2D u_texture;\nuniform float u_alpha;\nvoid main() {\n vec4 color = texture2D(u_texture, v_uv);\n gl_FragColor = vec4(color.rgb, color.a * u_alpha);\n}\n`;\n\nfunction easeInOutSine(x: number): number {\n\treturn -(Math.cos(Math.PI * x) - 1) / 2;\n}\n\ntype RenderingContext = WebGLRenderingContext;\n\nclass Mesh implements Disposable {\n\tprotected vertexWidth = 0;\n\tprotected vertexHeight = 0;\n\tprivate vertexBuffer: WebGLBuffer;\n\tprivate indexBuffer: WebGLBuffer;\n\tprivate vertexData: Float32Array;\n\tprivate indexData: Uint16Array;\n\tprivate vertexIndexLength = 0;\n\t// 调试用途,开启线框模式\n\tprivate wireFrame = false;\n\tconstructor(\n\t\tprivate readonly gl: RenderingContext,\n\t\tprivate readonly attrPos: number | undefined,\n\t\tprivate readonly attrColor: number | undefined,\n\t\tprivate readonly attrUV: number | undefined,\n\t) {\n\t\tconst vertexBuf = gl.createBuffer();\n\t\tif (!vertexBuf) throw new Error(\"Failed to create vertex buffer\");\n\t\tthis.vertexBuffer = vertexBuf;\n\t\tconst indexBuf = gl.createBuffer();\n\t\tif (!indexBuf) throw new Error(\"Failed to create index buffer\");\n\t\tthis.indexBuffer = indexBuf;\n\n\t\tthis.bind();\n\n\t\tthis.vertexData = new Float32Array(0);\n\t\tthis.indexData = new Uint16Array(0);\n\n\t\tthis.resize(2, 2);\n\t\tthis.update();\n\t}\n\n\tsetWireFrame(enable: boolean) {\n\t\tthis.wireFrame = enable;\n\t\tthis.resize(this.vertexWidth, this.vertexHeight);\n\t}\n\n\tsetVertexPos(vx: number, vy: number, x: number, y: number): void {\n\t\tconst idx = (vx + vy * this.vertexWidth) * 7;\n\t\tif (idx >= this.vertexData.length - 1) {\n\t\t\tconsole.warn(\"Vertex position out of range\", idx, this.vertexData.length);\n\t\t\treturn;\n\t\t}\n\t\tthis.vertexData[idx] = x;\n\t\tthis.vertexData[idx + 1] = y;\n\t}\n\n\tsetVertexColor(\n\t\tvx: number,\n\t\tvy: number,\n\t\tr: number,\n\t\tg: number,\n\t\tb: number,\n\t): void {\n\t\tconst idx = (vx + vy * this.vertexWidth) * 7 + 2;\n\t\tif (idx >= this.vertexData.length - 2) {\n\t\t\tconsole.warn(\"Vertex color out of range\", idx, this.vertexData.length);\n\t\t\treturn;\n\t\t}\n\t\tthis.vertexData[idx] = r;\n\t\tthis.vertexData[idx + 1] = g;\n\t\tthis.vertexData[idx + 2] = b;\n\t}\n\n\tsetVertexUV(vx: number, vy: number, x: number, y: number): void {\n\t\tconst idx = (vx + vy * this.vertexWidth) * 7 + 5;\n\t\tif (idx >= this.vertexData.length - 1) {\n\t\t\tconsole.warn(\"Vertex UV out of range\", idx, this.vertexData.length);\n\t\t\treturn;\n\t\t}\n\t\tthis.vertexData[idx] = x;\n\t\tthis.vertexData[idx + 1] = y;\n\t}\n\n\t// 批量设置顶点数据的优化方法\n\tsetVertexData(\n\t\tvx: number,\n\t\tvy: number,\n\t\tx: number,\n\t\ty: number,\n\t\tr: number,\n\t\tg: number,\n\t\tb: number,\n\t\tu: number,\n\t\tv: number,\n\t): void {\n\t\tconst idx = (vx + vy * this.vertexWidth) * 7;\n\t\tif (idx >= this.vertexData.length - 6) {\n\t\t\tconsole.warn(\"Vertex data out of range\", idx, this.vertexData.length);\n\t\t\treturn;\n\t\t}\n\t\tconst data = this.vertexData;\n\t\tdata[idx] = x;\n\t\tdata[idx + 1] = y;\n\t\tdata[idx + 2] = r;\n\t\tdata[idx + 3] = g;\n\t\tdata[idx + 4] = b;\n\t\tdata[idx + 5] = u;\n\t\tdata[idx + 6] = v;\n\t}\n\n\tgetVertexIndexLength(): number {\n\t\treturn this.vertexIndexLength;\n\t}\n\n\tdraw() {\n\t\tconst gl = this.gl;\n\n\t\tif (this.wireFrame) {\n\t\t\tgl.drawElements(gl.LINES, this.vertexIndexLength, gl.UNSIGNED_SHORT, 0);\n\t\t} else {\n\t\t\tgl.drawElements(\n\t\t\t\tgl.TRIANGLES,\n\t\t\t\tthis.vertexIndexLength,\n\t\t\t\tgl.UNSIGNED_SHORT,\n\t\t\t\t0,\n\t\t\t);\n\t\t}\n\t}\n\n\tresize(vertexWidth: number, vertexHeight: number): void {\n\t\tthis.vertexWidth = vertexWidth;\n\t\tthis.vertexHeight = vertexHeight;\n\t\t// 2 个顶点坐标 + 3 个颜色值 + 2 个 UV 坐标\n\t\tthis.vertexIndexLength = vertexWidth * vertexHeight * 6;\n\t\tif (this.wireFrame) {\n\t\t\tthis.vertexIndexLength = vertexWidth * vertexHeight * 10;\n\t\t}\n\t\tconst vertexData = new Float32Array(\n\t\t\tvertexWidth * vertexHeight * (2 + 3 + 2),\n\t\t);\n\t\tconst indexData = new Uint16Array(this.vertexIndexLength);\n\t\tthis.vertexData = vertexData;\n\t\tthis.indexData = indexData;\n\t\tfor (let y = 0; y < vertexHeight; y++) {\n\t\t\tfor (let x = 0; x < vertexWidth; x++) {\n\t\t\t\tconst px = (x / (vertexWidth - 1)) * 2 - 1;\n\t\t\t\tconst py = (y / (vertexHeight - 1)) * 2 - 1;\n\t\t\t\tthis.setVertexPos(x, y, px || 0, py || 0);\n\t\t\t\tthis.setVertexColor(x, y, 1, 1, 1);\n\t\t\t\tthis.setVertexUV(x, y, x / (vertexWidth - 1), y / (vertexHeight - 1));\n\t\t\t}\n\t\t}\n\t\tfor (let y = 0; y < vertexHeight - 1; y++) {\n\t\t\tfor (let x = 0; x < vertexWidth - 1; x++) {\n\t\t\t\tif (this.wireFrame) {\n\t\t\t\t\tconst idx = (y * vertexWidth + x) * 10;\n\n\t\t\t\t\tindexData[idx] = y * vertexWidth + x;\n\t\t\t\t\tindexData[idx + 1] = y * vertexWidth + x + 1;\n\n\t\t\t\t\tindexData[idx + 2] = y * vertexWidth + x + 1;\n\t\t\t\t\tindexData[idx + 3] = (y + 1) * vertexWidth + x;\n\n\t\t\t\t\tindexData[idx + 4] = (y + 1) * vertexWidth + x;\n\t\t\t\t\tindexData[idx + 5] = (y + 1) * vertexWidth + x + 1;\n\n\t\t\t\t\tindexData[idx + 6] = (y + 1) * vertexWidth + x + 1;\n\t\t\t\t\tindexData[idx + 7] = y * vertexWidth + x + 1;\n\n\t\t\t\t\tindexData[idx + 8] = y * vertexWidth + x;\n\t\t\t\t\tindexData[idx + 9] = (y + 1) * vertexWidth + x;\n\t\t\t\t} else {\n\t\t\t\t\tconst idx = (y * vertexWidth + x) * 6;\n\t\t\t\t\tindexData[idx] = y * vertexWidth + x;\n\t\t\t\t\tindexData[idx + 1] = y * vertexWidth + x + 1;\n\t\t\t\t\tindexData[idx + 2] = (y + 1) * vertexWidth + x;\n\t\t\t\t\tindexData[idx + 3] = y * vertexWidth + x + 1;\n\t\t\t\t\tindexData[idx + 4] = (y + 1) * vertexWidth + x + 1;\n\t\t\t\t\tindexData[idx + 5] = (y + 1) * vertexWidth + x;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tconst gl = this.gl;\n\t\tgl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.indexBuffer);\n\t\tgl.bufferData(gl.ELEMENT_ARRAY_BUFFER, this.indexData, gl.STATIC_DRAW);\n\t}\n\n\tbind() {\n\t\tconst gl = this.gl;\n\t\tgl.bindBuffer(gl.ARRAY_BUFFER, this.vertexBuffer);\n\t\tgl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.indexBuffer);\n\n\t\tif (this.attrPos !== undefined) {\n\t\t\tgl.vertexAttribPointer(this.attrPos, 2, gl.FLOAT, false, 4 * 7, 0);\n\t\t\tgl.enableVertexAttribArray(this.attrPos);\n\t\t}\n\t\tif (this.attrColor !== undefined) {\n\t\t\tgl.vertexAttribPointer(this.attrColor, 3, gl.FLOAT, false, 4 * 7, 4 * 2);\n\t\t\tgl.enableVertexAttribArray(this.attrColor);\n\t\t}\n\t\tif (this.attrUV !== undefined) {\n\t\t\tgl.vertexAttribPointer(this.attrUV, 2, gl.FLOAT, false, 4 * 7, 4 * 5);\n\t\t\tgl.enableVertexAttribArray(this.attrUV);\n\t\t}\n\t}\n\n\tupdate() {\n\t\tconst gl = this.gl;\n\t\tgl.bindBuffer(gl.ARRAY_BUFFER, this.vertexBuffer);\n\t\tgl.bufferData(gl.ARRAY_BUFFER, this.vertexData, gl.DYNAMIC_DRAW);\n\t}\n\n\tdispose(): void {\n\t\tthis.gl.deleteBuffer(this.vertexBuffer);\n\t\tthis.gl.deleteBuffer(this.indexBuffer);\n\t}\n}\n\nclass ControlPoint {\n\tcolor: Vec3 = Vec3.fromValues(1, 1, 1);\n\tlocation: Vec2 = Vec2.fromValues(0, 0);\n\tuTangent: Vec2 = Vec2.fromValues(0, 0);\n\tvTangent: Vec2 = Vec2.fromValues(0, 0);\n\tprivate _uRot = 0;\n\tprivate _vRot = 0;\n\tprivate _uScale = 1;\n\tprivate _vScale = 1;\n\n\tconstructor() {\n\t\tObject.seal(this);\n\t}\n\n\tget uRot() {\n\t\treturn this._uRot;\n\t}\n\n\tget vRot() {\n\t\treturn this._vRot;\n\t}\n\n\tset uRot(value: number) {\n\t\tthis._uRot = value;\n\t\tthis.updateUTangent();\n\t}\n\n\tset vRot(value: number) {\n\t\tthis._vRot = value;\n\t\tthis.updateVTangent();\n\t}\n\n\tget uScale() {\n\t\treturn this._uScale;\n\t}\n\n\tget vScale() {\n\t\treturn this._vScale;\n\t}\n\n\tset uScale(value: number) {\n\t\tthis._uScale = value;\n\t\tthis.updateUTangent();\n\t}\n\n\tset vScale(value: number) {\n\t\tthis._vScale = value;\n\t\tthis.updateVTangent();\n\t}\n\n\tprivate updateUTangent() {\n\t\tthis.uTangent[0] = Math.cos(this._uRot) * this._uScale;\n\t\tthis.uTangent[1] = Math.sin(this._uRot) * this._uScale;\n\t}\n\n\tprivate updateVTangent() {\n\t\tthis.vTangent[0] = -Math.sin(this._vRot) * this._vScale;\n\t\tthis.vTangent[1] = Math.cos(this._vRot) * this._vScale;\n\t}\n}\n\nconst H = Mat4.fromValues(2, -2, 1, 1, -3, 3, -2, -1, 0, 0, 1, 0, 1, 0, 0, 0);\nconst H_T = Mat4.clone(H).transpose();\n\nfunction meshCoefficients(\n\tp00: ControlPoint,\n\tp01: ControlPoint,\n\tp10: ControlPoint,\n\tp11: ControlPoint,\n\taxis: \"x\" | \"y\",\n\toutput = Mat4.create(),\n): Mat4 {\n\tconst l = (p: ControlPoint) => p.location[axis];\n\tconst u = (p: ControlPoint) => p.uTangent[axis];\n\tconst v = (p: ControlPoint) => p.vTangent[axis];\n\n\toutput[0] = l(p00);\n\toutput[1] = l(p01);\n\toutput[2] = v(p00);\n\toutput[3] = v(p01);\n\toutput[4] = l(p10);\n\toutput[5] = l(p11);\n\toutput[6] = v(p10);\n\toutput[7] = v(p11);\n\toutput[8] = u(p00);\n\toutput[9] = u(p01);\n\toutput[10] = 0;\n\toutput[11] = 0;\n\toutput[12] = u(p10);\n\toutput[13] = u(p11);\n\toutput[14] = 0;\n\toutput[15] = 0;\n\n\treturn output;\n}\n\nfunction colorCoefficients(\n\tp00: ControlPoint,\n\tp01: ControlPoint,\n\tp10: ControlPoint,\n\tp11: ControlPoint,\n\taxis: \"r\" | \"g\" | \"b\",\n\toutput = Mat4.create(),\n): Mat4 {\n\tconst c = (p: ControlPoint) => p.color[axis];\n\toutput.fill(0);\n\toutput[0] = c(p00);\n\toutput[1] = c(p01);\n\toutput[4] = c(p10);\n\toutput[5] = c(p11);\n\t// return Mat4.fromValues(\n\t// c(p00), c(p01), 0, 0,\n\t// c(p10), c(p11), 0, 0,\n\t// 0, 0, 0, 0,\n\t// 0, 0, 0, 0,\n\t// );\n\treturn output;\n}\n\nclass Map2D<T> {\n\tprivate _width = 0;\n\tprivate _height = 0;\n\tprivate _data: T[] = [];\n\tconstructor(width: number, height: number) {\n\t\tthis.resize(width, height);\n\t\tObject.seal(this);\n\t}\n\tresize(width: number, height: number) {\n\t\tthis._width = width;\n\t\tthis._height = height;\n\t\tthis._data = new Array(width * height).fill(0);\n\t}\n\tset(x: number, y: number, value: T) {\n\t\tthis._data[x + y * this._width] = value;\n\t}\n\tget(x: number, y: number) {\n\t\treturn this._data[x + y * this._width];\n\t}\n\tget width() {\n\t\treturn this._width;\n\t}\n\tget height() {\n\t\treturn this._height;\n\t}\n}\n\n// Bicubic Hermite Patch Mesh\nclass BHPMesh extends Mesh {\n\t/**\n\t * 细分级别,越大曲线越平滑,但是性能消耗也越大\n\t */\n\tprivate _subDivisions = 10;\n\tprivate _controlPoints: Map2D<ControlPoint> = new Map2D(3, 3);\n\n\tconstructor(\n\t\tgl: RenderingContext,\n\t\tattrPos: number,\n\t\tattrColor: number,\n\t\tattrUV: number,\n\t) {\n\t\tsuper(gl, attrPos, attrColor, attrUV);\n\t\tthis.resizeControlPoints(3, 3);\n\t\tObject.seal(this);\n\t}\n\toverride setWireFrame(enable: boolean) {\n\t\tsuper.setWireFrame(enable);\n\t\tthis.updateMesh();\n\t}\n\t/**\n\t * 以当前的控制点矩阵大小和细分级别为参考重新设置细分级别,此操作不会重设控制点数据\n\t * @param subDivisions 细分级别\n\t */\n\tresetSubdivition(subDivisions: number) {\n\t\tthis._subDivisions = subDivisions;\n\t\tsuper.resize(\n\t\t\t(this._controlPoints.width - 1) * subDivisions,\n\t\t\t(this._controlPoints.height - 1) * subDivisions,\n\t\t);\n\t}\n\t/**\n\t * 重设控制点矩阵尺寸,将会重置所有控制点的颜色和坐标数据\n\t * 请在调用此方法后重新设置颜色和坐标,并调用 updateMesh 方法更新网格\n\t * @param width 控制点宽度数量,必须大于等于 2\n\t * @param height 控制点高度数量,必须大于等于 2\n\t */\n\tresizeControlPoints(width: number, height: number) {\n\t\tif (!(width >= 2 && height >= 2)) {\n\t\t\tthrow new Error(\"Control points must be larger than 3x3 or equal\");\n\t\t}\n\t\tthis._controlPoints.resize(width, height);\n\t\tfor (let y = 0; y < height; y++) {\n\t\t\tfor (let x = 0; x < width; x++) {\n\t\t\t\tconst point = new ControlPoint();\n\t\t\t\tpoint.location.x = (x / (width - 1)) * 2 - 1;\n\t\t\t\tpoint.location.y = (y / (height - 1)) * 2 - 1;\n\t\t\t\tpoint.uTangent.x = 2 / (width - 1);\n\t\t\t\tpoint.vTangent.y = 2 / (height - 1);\n\t\t\t\tthis._controlPoints.set(x, y, point);\n\t\t\t}\n\t\t}\n\t\tthis.resetSubdivition(this._subDivisions);\n\t}\n\t/**\n\t * 获取指定位置的控制点,然后可以设置颜色和坐标属性\n\t * 留意颜色属性和坐标属性的值范围均参考 WebGL 的定义\n\t * 即颜色各个组件取值 [0-1],坐标取值 [-1, 1]\n\t * 点的位置以画面左下角为原点 (0,0)\n\t * @param x 需要获取的控制点的 x 坐标\n\t * @param y 需要获取的控制点的 y 坐标\n\t * @returns 控制点对象\n\t */\n\tgetControlPoint(x: number, y: number) {\n\t\treturn this._controlPoints.get(x, y);\n\t}\n\t// 预分配重复使用的矩阵,避免频繁创建\n\tprivate tempX = Mat4.create();\n\tprivate tempY = Mat4.create();\n\tprivate tempR = Mat4.create();\n\tprivate tempG = Mat4.create();\n\tprivate tempB = Mat4.create();\n\n\tprivate tempXAcc = Mat4.create();\n\tprivate tempYAcc = Mat4.create();\n\tprivate tempRAcc = Mat4.create();\n\tprivate tempGAcc = Mat4.create();\n\tprivate tempBAcc = Mat4.create();\n\n\tprivate tempUx = Vec4.create();\n\tprivate tempUy = Vec4.create();\n\tprivate tempUr = Vec4.create();\n\tprivate tempUg = Vec4.create();\n\tprivate tempUb = Vec4.create();\n\n\tprivate precomputeMatrix(M: Mat4, output: Mat4) {\n\t\toutput.copy(M).transpose();\n\t\tMat4.mul(output, output, H);\n\t\tMat4.mul(output, H_T, output);\n\t\treturn output;\n\t}\n\n\t/**\n\t * 更新最终呈现的网格数据,此方法应在所有控制点或细分参数的操作完成后调用\n\t */\n\tupdateMesh() {\n\t\tconst subDivM1 = this._subDivisions - 1;\n\t\tconst tW = subDivM1 * (this._controlPoints.height - 1);\n\t\tconst tH = subDivM1 * (this._controlPoints.width - 1);\n\t\tconst controlPointsWidth = this._controlPoints.width;\n\t\tconst controlPointsHeight = this._controlPoints.height;\n\t\tconst subDivisions = this._subDivisions;\n\n\t\t// 预计算常用值\n\t\tconst invSubDivM1 = 1 / subDivM1;\n\t\tconst invTH = 1 / tH;\n\t\tconst invTW = 1 / tW;\n\n\t\t// 预计算 u 和 v 的幂次\n\t\tconst normPowers = new Float32Array(subDivisions * 4);\n\t\tfor (let i = 0; i < subDivisions; i++) {\n\t\t\tconst norm = i * invSubDivM1;\n\t\t\tconst idx = i * 4;\n\t\t\tnormPowers[idx] = norm ** 3;\n\t\t\tnormPowers[idx + 1] = norm ** 2;\n\t\t\tnormPowers[idx + 2] = norm;\n\t\t\tnormPowers[idx + 3] = 1;\n\t\t}\n\n\t\tfor (let x = 0; x < controlPointsWidth - 1; x++) {\n\t\t\tfor (let y = 0; y < controlPointsHeight - 1; y++) {\n\t\t\t\tconst p00 = this._controlPoints.get(x, y);\n\t\t\t\tconst p01 = this._controlPoints.get(x, y + 1);\n\t\t\t\tconst p10 = this._controlPoints.get(x + 1, y);\n\t\t\t\tconst p11 = this._controlPoints.get(x + 1, y + 1);\n\n\t\t\t\t// 复用预分配的矩阵\n\t\t\t\tmeshCoefficients(p00, p01, p10, p11, \"x\", this.tempX);\n\t\t\t\tmeshCoefficients(p00, p01, p10, p11, \"y\", this.tempY);\n\t\t\t\tcolorCoefficients(p00, p01, p10, p11, \"r\", this.tempR);\n\t\t\t\tcolorCoefficients(p00, p01, p10, p11, \"g\", this.tempG);\n\t\t\t\tcolorCoefficients(p00, p01, p10, p11, \"b\", this.tempB);\n\n\t\t\t\t// 预计算累加矩阵\n\t\t\t\tthis.precomputeMatrix(this.tempX, this.tempXAcc);\n\t\t\t\tthis.precomputeMatrix(this.tempY, this.tempYAcc);\n\t\t\t\tthis.precomputeMatrix(this.tempR, this.tempRAcc);\n\t\t\t\tthis.precomputeMatrix(this.tempG, this.tempGAcc);\n\t\t\t\tthis.precomputeMatrix(this.tempB, this.tempBAcc);\n\n\t\t\t\tconst sX = x / (controlPointsWidth - 1);\n\t\t\t\tconst sY = y / (controlPointsHeight - 1);\n\t\t\t\tconst baseVx = y * subDivisions;\n\t\t\t\tconst baseVy = x * subDivisions;\n\n\t\t\t\tfor (let u = 0; u < subDivisions; u++) {\n\t\t\t\t\tconst vxOffset = baseVx + u;\n\t\t\t\t\tconst uIdx = u * 4;\n\n\t\t\t\t\tthis.tempUx[0] = normPowers[uIdx];\n\t\t\t\t\tthis.tempUx[1] = normPowers[uIdx + 1];\n\t\t\t\t\tthis.tempUx[2] = normPowers[uIdx + 2];\n\t\t\t\t\tthis.tempUx[3] = normPowers[uIdx + 3];\n\t\t\t\t\tVec4.transformMat4(this.tempUx, this.tempUx, this.tempXAcc);\n\n\t\t\t\t\tthis.tempUy[0] = normPowers[uIdx];\n\t\t\t\t\tthis.tempUy[1] = normPowers[uIdx + 1];\n\t\t\t\t\tthis.tempUy[2] = normPowers[uIdx + 2];\n\t\t\t\t\tthis.tempUy[3] = normPowers[uIdx + 3];\n\t\t\t\t\tVec4.transformMat4(this.tempUy, this.tempUy, this.tempYAcc);\n\n\t\t\t\t\tthis.tempUr[0] = normPowers[uIdx];\n\t\t\t\t\tthis.tempUr[1] = normPowers[uIdx + 1];\n\t\t\t\t\tthis.tempUr[2] = normPowers[uIdx + 2];\n\t\t\t\t\tthis.tempUr[3] = normPowers[uIdx + 3];\n\t\t\t\t\tVec4.transformMat4(this.tempUr, this.tempUr, this.tempRAcc);\n\n\t\t\t\t\tthis.tempUg[0] = normPowers[uIdx];\n\t\t\t\t\tthis.tempUg[1] = normPowers[uIdx + 1];\n\t\t\t\t\tthis.tempUg[2] = normPowers[uIdx + 2];\n\t\t\t\t\tthis.tempUg[3] = normPowers[uIdx + 3];\n\t\t\t\t\tVec4.transformMat4(this.tempUg, this.tempUg, this.tempGAcc);\n\n\t\t\t\t\tthis.tempUb[0] = normPowers[uIdx];\n\t\t\t\t\tthis.tempUb[1] = normPowers[uIdx + 1];\n\t\t\t\t\tthis.tempUb[2] = normPowers[uIdx + 2];\n\t\t\t\t\tthis.tempUb[3] = normPowers[uIdx + 3];\n\t\t\t\t\tVec4.transformMat4(this.tempUb, this.tempUb, this.tempBAcc);\n\n\t\t\t\t\tfor (let v = 0; v < subDivisions; v++) {\n\t\t\t\t\t\tconst vy = baseVy + v;\n\t\t\t\t\t\tconst vIdx = v * 4;\n\n\t\t\t\t\t\tconst v0 = normPowers[vIdx];\n\t\t\t\t\t\tconst v1 = normPowers[vIdx + 1];\n\t\t\t\t\t\tconst v2 = normPowers[vIdx + 2];\n\t\t\t\t\t\tconst v3 = normPowers[vIdx + 3];\n\n\t\t\t\t\t\tconst px =\n\t\t\t\t\t\t\tv0 * this.tempUx[0] +\n\t\t\t\t\t\t\tv1 * this.tempUx[1] +\n\t\t\t\t\t\t\tv2 * this.tempUx[2] +\n\t\t\t\t\t\t\tv3 * this.tempUx[3];\n\t\t\t\t\t\tconst py =\n\t\t\t\t\t\t\tv0 * this.tempUy[0] +\n\t\t\t\t\t\t\tv1 * this.tempUy[1] +\n\t\t\t\t\t\t\tv2 * this.tempUy[2] +\n\t\t\t\t\t\t\tv3 * this.tempUy[3];\n\t\t\t\t\t\tconst pr =\n\t\t\t\t\t\t\tv0 * this.tempUr[0] +\n\t\t\t\t\t\t\tv1 * this.tempUr[1] +\n\t\t\t\t\t\t\tv2 * this.tempUr[2] +\n\t\t\t\t\t\t\tv3 * this.tempUr[3];\n\t\t\t\t\t\tconst pg =\n\t\t\t\t\t\t\tv0 * this.tempUg[0] +\n\t\t\t\t\t\t\tv1 * this.tempUg[1] +\n\t\t\t\t\t\t\tv2 * this.tempUg[2] +\n\t\t\t\t\t\t\tv3 * this.tempUg[3];\n\t\t\t\t\t\tconst pb =\n\t\t\t\t\t\t\tv0 * this.tempUb[0] +\n\t\t\t\t\t\t\tv1 * this.tempUb[1] +\n\t\t\t\t\t\t\tv2 * this.tempUb[2] +\n\t\t\t\t\t\t\tv3 * this.tempUb[3];\n\n\t\t\t\t\t\tconst uvX = sX + v * invTH;\n\t\t\t\t\t\tconst uvY = 1 - sY - u * invTW;\n\n\t\t\t\t\t\t// 使用批量设置方法减少数组访问次数\n\t\t\t\t\t\tthis.setVertexData(vxOffset, vy, px, py, pr, pg, pb, uvX, uvY);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tthis.update();\n\t}\n}\n\nclass GLTexture implements Disposable {\n\treadonly tex: WebGLTexture;\n\n\tconstructor(\n\t\tprivate gl: WebGLRenderingContext,\n\t\talbumImageData: ImageData,\n\t) {\n\t\tconst albumTexture = gl.createTexture();\n\t\tif (!albumTexture) throw new Error(\"Failed to create texture\");\n\t\tthis.tex = albumTexture;\n\t\tgl.activeTexture(gl.TEXTURE0);\n\t\tgl.bindTexture(gl.TEXTURE_2D, albumTexture);\n\t\tgl.texImage2D(\n\t\t\tgl.TEXTURE_2D,\n\t\t\t0,\n\t\t\tgl.RGBA,\n\t\t\tgl.RGBA,\n\t\t\tgl.UNSIGNED_BYTE,\n\t\t\talbumImageData,\n\t\t);\n\t\tgl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);\n\t\tgl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);\n\t\tgl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.MIRRORED_REPEAT);\n\t\tgl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.MIRRORED_REPEAT);\n\t}\n\n\tbind() {\n\t\tthis.gl.bindTexture(this.gl.TEXTURE_2D, this.tex);\n\t}\n\n\tdispose(): void {\n\t\tthis.gl.deleteTexture(this.tex);\n\t}\n}\n\ninterface MeshState {\n\tmesh: BHPMesh;\n\ttexture: GLTexture;\n\talpha: number;\n}\n\nexport class MeshGradientRenderer extends BaseRenderer {\n\t/**\n\t * 当前环境是否支持此渲染器\n\t */\n\tstatic isSupported(): boolean {\n\t\treturn isWebGL1Supported();\n\t}\n\n\tprivate gl: RenderingContext;\n\tprivate contextLost = false;\n\tprivate albumRequestId = 0;\n\tprivate albumLoadController?: AbortController;\n\tprivate lastImageData?: ImageData;\n\tprivate lastFrameTime = 0;\n\tprivate frameTime = 0;\n\t// private currentImageData?: ImageData;\n\tprivate lastTickTime = 0;\n\tprivate smoothedVolume = 0;\n\tprivate volume = 0;\n\tprivate tickHandle = 0;\n\tprivate maxFPS = 60;\n\tprivate paused = false;\n\tprivate staticMode = false;\n\tprivate mainProgram!: GLProgram;\n\tprivate quadProgram!: GLProgram;\n\tprivate quadBuffer!: WebGLBuffer;\n\tprivate fbo: WebGLFramebuffer | null = null;\n\tprivate fboTexture: WebGLTexture | null = null;\n\tprivate manualControl = false;\n\tprivate reduceImageSizeCanvas = createOffscreenCanvas(\n\t\t32,\n\t\t32,\n\t) as HTMLCanvasElement;\n\tprivate targetSize = Vec2.fromValues(0, 0);\n\tprivate currentSize = Vec2.fromValues(0, 0);\n\tprivate isNoCover = true;\n\tprivate meshStates: MeshState[] = [];\n\tprivate _disposed = false;\n\t// 性能监控\n\tprivate frameCount = 0;\n\tprivate lastFPSUpdate = 0;\n\tprivate currentFPS = 0;\n\tprivate enablePerformanceMonitoring = false;\n\n\tprivate isCurrentAlbumRequest(requestId: number): boolean {\n\t\treturn (\n\t\t\t!this._disposed && !this.contextLost && requestId === this.albumRequestId\n\t\t);\n\t}\n\n\tprivate initializeGLResources(): void {\n\t\tconst gl = this.gl;\n\t\tif (!gl.getExtension(\"EXT_color_buffer_float\"))\n\t\t\tconsole.warn(\"EXT_color_buffer_float not supported\");\n\t\tif (!gl.getExtension(\"EXT_float_blend\")) {\n\t\t\tconsole.warn(\"EXT_float_blend not supported\");\n\t\t\t// this.supportTextureFloat = false;\n\t\t}\n\t\tif (!gl.getExtension(\"OES_texture_float_linear\"))\n\t\t\tconsole.warn(\"OES_texture_float_linear not supported\");\n\t\tif (!gl.getExtension(\"OES_texture_float\")) {\n\t\t\t// this.supportTextureFloat = false;\n\t\t\tconsole.warn(\"OES_texture_float not supported\");\n\t\t}\n\n\t\tgl.enable(gl.BLEND);\n\t\tgl.blendFuncSeparate(\n\t\t\tgl.SRC_ALPHA,\n\t\t\tgl.ONE_MINUS_SRC_ALPHA,\n\t\t\tgl.ONE,\n\t\t\tgl.ONE_MINUS_SRC_ALPHA,\n\t\t);\n\t\tgl.enable(gl.DEPTH_TEST);\n\t\tgl.depthFunc(gl.ALWAYS);\n\n\t\tthis.mainProgram = new GLProgram(\n\t\t\tgl,\n\t\t\tmeshVertShader,\n\t\t\tmeshFragShader,\n\t\t\t\"main-program-mg\",\n\t\t);\n\n\t\tthis.quadProgram = new GLProgram(\n\t\t\tgl,\n\t\t\tquadVertShader,\n\t\t\tquadFragShader,\n\t\t\t\"quad-program\",\n\t\t);\n\t\tconst quadBuffer = gl.createBuffer();\n\t\tif (!quadBuffer) throw new Error(\"Failed to create quad buffer\");\n\t\tthis.quadBuffer = quadBuffer;\n\t\tgl.bindBuffer(gl.ARRAY_BUFFER, this.quadBuffer);\n\t\tgl.bufferData(\n\t\t\tgl.ARRAY_BUFFER,\n\t\t\tnew Float32Array([-1, -1, 1, -1, -1, 1, -1, 1, 1, -1, 1, 1]),\n\t\t\tgl.STATIC_DRAW,\n\t\t);\n\t}\n\n\tprivate createMeshState(imageData: ImageData): MeshState {\n\t\tconst newMesh = new BHPMesh(\n\t\t\tthis.gl,\n\t\t\tthis.mainProgram.attrs.a_pos,\n\t\t\tthis.mainProgram.attrs.a_color,\n\t\t\tthis.mainProgram.attrs.a_uv,\n\t\t);\n\t\tnewMesh.resetSubdivition(50);\n\n\t\tconst chosenPreset =\n\t\t\tMath.random() > 0.8\n\t\t\t\t? generateControlPoints(6, 6)\n\t\t\t\t: CONTROL_POINT_PRESETS[\n\t\t\t\t\t\tMath.floor(Math.random() * CONTROL_POINT_PRESETS.length)\n\t\t\t\t\t];\n\n\t\tnewMesh.resizeControlPoints(chosenPreset.width, chosenPreset.height);\n\t\tconst uPower = 2 / (chosenPreset.width - 1);\n\t\tconst vPower = 2 / (chosenPreset.height - 1);\n\t\tfor (const cp of chosenPreset.conf) {\n\t\t\tconst p = newMesh.getControlPoint(cp.cx, cp.cy);\n\t\t\tp.location.x = cp.x;\n\t\t\tp.location.y = cp.y;\n\t\t\tp.uRot = (cp.ur * Math.PI) / 180;\n\t\t\tp.vRot = (cp.vr * Math.PI) / 180;\n\t\t\tp.uScale = uPower * cp.up;\n\t\t\tp.vScale = vPower * cp.vp;\n\t\t}\n\n\t\tnewMesh.updateMesh();\n\t\treturn {\n\t\t\tmesh: newMesh,\n\t\t\ttexture: new GLTexture(this.gl, imageData),\n\t\t\talpha: 0,\n\t\t};\n\t}\n\n\tprivate onContextLost = (event: Event): void => {\n\t\tevent.preventDefault();\n\t\tthis.contextLost = true;\n\t\tthis.albumLoadController?.abort();\n\t\tif (this.tickHandle) {\n\t\t\tcancelAnimationFrame(this.tickHandle);\n\t\t\tthis.tickHandle = 0;\n\t\t}\n\t};\n\n\tprivate onContextRestored = (): void => {\n\t\tif (this._disposed) return;\n\n\t\tthis.contextLost = false;\n\t\tthis.meshStates = [];\n\t\tthis.fbo = null;\n\t\tthis.fboTexture = null;\n\t\tthis.currentSize = Vec2.fromValues(0, 0);\n\t\tthis.initializeGLResources();\n\t\tthis.lastFrameTime = performance.now();\n\t\tthis.isNoCover = !this.lastImageData;\n\n\t\tif (this.lastImageData) {\n\t\t\tthis.meshStates.push(this.createMeshState(this.lastImageData));\n\t\t}\n\t\tthis.requestTick();\n\t};\n\n\tsetManualControl(enable: boolean): void {\n\t\tthis.manualControl = enable;\n\t}\n\n\tsetWireFrame(enable: boolean): void {\n\t\tfor (const state of this.meshStates) {\n\t\t\tstate.mesh.setWireFrame(enable);\n\t\t}\n\t}\n\n\tgetControlPoint(x: number, y: number): ControlPoint | undefined {\n\t\treturn this.meshStates[this.meshStates.length - 1]?.mesh?.getControlPoint(\n\t\t\tx,\n\t\t\ty,\n\t\t);\n\t}\n\n\tresizeControlPoints(width: number, height: number): void {\n\t\tthis.meshStates[this.meshStates.length - 1]?.mesh?.resizeControlPoints(\n\t\t\twidth,\n\t\t\theight,\n\t\t);\n\t}\n\n\tresetSubdivition(subDivisions: number): void {\n\t\tthis.meshStates[this.meshStates.length - 1]?.mesh?.resetSubdivition(\n\t\t\tsubDivisions,\n\t\t);\n\t}\n\n\tprivate onTick(tickTime: number) {\n\t\tthis.tickHandle = 0;\n\t\tif (this.paused) return;\n\t\tif (this._disposed) return;\n\t\tif (this.contextLost) return;\n\n\t\t// 更新性能统计\n\t\tthis.updatePerformanceStats(tickTime);\n\n\t\tconst interval = 1000 / this.maxFPS;\n\t\tconst delta = tickTime - this.lastTickTime;\n\t\tif (delta < interval) {\n\t\t\tthis.requestTick();\n\t\t\treturn;\n\t\t}\n\n\t\tif (Number.isNaN(this.lastFrameTime)) {\n\t\t\tthis.lastFrameTime = tickTime;\n\t\t}\n\t\tconst frameDelta = tickTime - this.lastFrameTime;\n\t\tthis.lastFrameTime = tickTime;\n\t\t// 减去多余的时间,避免帧率漂移(例如高刷显示器限制低帧率时)\n\t\tthis.lastTickTime = tickTime - (delta % interval);\n\n\t\tthis.frameTime += frameDelta * this.flowSpeed;\n\n\t\tif (!(this.onRedraw(this.frameTime, frameDelta) && this.staticMode)) {\n\t\t\tthis.requestTick();\n\t\t} else if (this.staticMode) {\n\t\t\tthis.lastFrameTime = Number.NaN;\n\t\t}\n\t}\n\n\tprivate checkIfResize() {\n\t\tconst [tW, tH] = [this.targetSize.x, this.targetSize.y];\n\t\tconst [cW, cH] = [this.currentSize.x, this.currentSize.y];\n\t\tif (tW !== cW || tH !== cH) {\n\t\t\tsuper.onResize(tW, tH);\n\t\t\tconst gl = this.gl;\n\t\t\tgl.bindFramebuffer(gl.FRAMEBUFFER, null);\n\t\t\tgl.viewport(0, 0, tW, tH);\n\t\t\tthis.currentSize.x = tW;\n\t\t\tthis.currentSize.y = tH;\n\t\t\tif (tW > 0 && tH > 0) {\n\t\t\t\tthis.updateFBO(tW, tH);\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate updateFBO(width: number, height: number) {\n\t\tconst gl = this.gl;\n\t\tif (this.fbo) gl.deleteFramebuffer(this.fbo);\n\t\tif (this.fboTexture) gl.deleteTexture(this.fboTexture);\n\n\t\tthis.fboTexture = gl.createTexture();\n\t\tgl.bindTexture(gl.TEXTURE_2D, this.fboTexture);\n\t\tgl.texImage2D(\n\t\t\tgl.TEXTURE_2D,\n\t\t\t0,\n\t\t\tgl.RGBA,\n\t\t\twidth,\n\t\t\theight,\n\t\t\t0,\n\t\t\tgl.RGBA,\n\t\t\tgl.UNSIGNED_BYTE,\n\t\t\tnull,\n\t\t);\n\t\tgl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);\n\t\tgl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);\n\t\tgl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);\n\t\tgl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);\n\n\t\tthis.fbo = gl.createFramebuffer();\n\t\tgl.bindFramebuffer(gl.FRAMEBUFFER, this.fbo);\n\t\tgl.framebufferTexture2D(\n\t\t\tgl.FRAMEBUFFER,\n\t\t\tgl.COLOR_ATTACHMENT0,\n\t\t\tgl.TEXTURE_2D,\n\t\t\tthis.fboTexture,\n\t\t\t0,\n\t\t);\n\n\t\tgl.bindFramebuffer(gl.FRAMEBUFFER, null);\n\t}\n\n\tprivate onRedraw(tickTime: number, delta: number) {\n\t\tconst latestMeshState = this.meshStates[this.meshStates.length - 1];\n\t\tlet canBeStatic = false;\n\n\t\t// 预计算常用值\n\t\tconst deltaFactor = delta / 500;\n\n\t\tif (latestMeshState) {\n\t\t\tlatestMeshState.mesh.bind();\n\t\t\t// 考虑到我们并不逐帧更新网格控制点,因此也不需要重复调用 updateMesh\n\t\t\tif (this.manualControl) latestMeshState.mesh.updateMesh();\n\n\t\t\tif (this.isNoCover) {\n\t\t\t\t// 批量处理alpha更新,减少循环开销\n\t\t\t\tlet hasActiveStates = false;\n\t\t\t\tfor (let i = this.meshStates.length - 1; i >= 0; i--) {\n\t\t\t\t\tconst state = this.meshStates[i];\n\t\t\t\t\t// 增加一个小的容错范围,避免浮点误差导致的过早删除\n\t\t\t\t\tif (state.alpha <= -0.1) {\n\t\t\t\t\t\t// 立即释放资源\n\t\t\t\t\t\tstate.mesh.dispose();\n\t\t\t\t\t\tstate.texture.dispose();\n\t\t\t\t\t\tthis.meshStates.splice(i, 1);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tstate.alpha = Math.max(-0.1, state.alpha - deltaFactor);\n\t\t\t\t\t\thasActiveStates = true;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tcanBeStatic = !hasActiveStates;\n\t\t\t} else {\n\t\t\t\t// 同样增加容错范围,允许稍微超过1以确保完全过渡完成\n\t\t\t\tif (latestMeshState.alpha >= 1.1) {\n\t\t\t\t\t// 批量清理旧状态\n\t\t\t\t\tconst deleted = this.meshStates.splice(0, this.meshStates.length - 1);\n\t\t\t\t\tfor (const state of deleted) {\n\t\t\t\t\t\tstate.mesh.dispose();\n\t\t\t\t\t\tstate.texture.dispose();\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tlatestMeshState.alpha = Math.min(\n\t\t\t\t\t\t1.1,\n\t\t\t\t\t\tlatestMeshState.alpha + deltaFactor,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tcanBeStatic =\n\t\t\t\t\tthis.meshStates.length === 1 && latestMeshState.alpha >= 1.1;\n\t\t\t}\n\t\t}\n\n\t\tconst gl = this.gl;\n\t\tthis.checkIfResize();\n\n\t\tif (!this.fbo) return canBeStatic;\n\n\t\tgl.bindFramebuffer(gl.FRAMEBUFFER, null);\n\t\tgl.clearColor(0, 0, 0, 0);\n\t\tgl.clear(gl.COLOR_BUFFER_BIT);\n\n\t\tconst lerpFactor = Math.min(1.0, delta / 100.0);\n\t\tthis.smoothedVolume += (this.volume - this.smoothedVolume) * lerpFactor;\n\n\t\t// 渲染所有网格状态\n\t\tfor (const state of this.meshStates) {\n\t\t\t// 1. 渲染到 FBO\n\t\t\tgl.bindFramebuffer(gl.FRAMEBUFFER, this.fbo);\n\t\t\tgl.disable(gl.BLEND);\n\t\t\tgl.clearColor(0, 0, 0, 0);\n\t\t\tgl.clear(gl.COLOR_BUFFER_BIT);\n\n\t\t\tthis.mainProgram.use();\n\t\t\tgl.activeTexture(gl.TEXTURE0);\n\t\t\tconst uTime = tickTime / 10000;\n\t\t\tthis.mainProgram.setUniform1f(\n\t\t\t\t\"u_aspect\",\n\t\t\t\tthis.manualControl ? 1 : this.canvas.width / this.canvas.height,\n\t\t\t);\n\t\t\tthis.mainProgram.setUniform1i(\"u_texture\", 0);\n\t\t\tthis.mainProgram.setUniform1f(\"u_volume\", this.volume);\n\t\t\tthis.mainProgram.setUniform1f(\"u_alpha\", 1.0);\n\t\t\tconst angle = (uTime + this.volume) * 2.0;\n\t\t\tthis.mainProgram.setUniform1f(\"u_sinAngle\", Math.sin(angle));\n\t\t\tthis.mainProgram.setUniform1f(\"u_cosAngle\", Math.cos(angle));\n\n\t\t\tstate.texture.bind();\n\t\t\tstate.mesh.bind();\n\t\t\tstate.mesh.draw();\n\n\t\t\t// 2. 渲染 FBO 到屏幕\n\t\t\tgl.bindFramebuffer(gl.FRAMEBUFFER, null);\n\t\t\tgl.enable(gl.BLEND);\n\t\t\tgl.blendFuncSeparate(\n\t\t\t\tgl.SRC_ALPHA,\n\t\t\t\tgl.ONE_MINUS_SRC_ALPHA,\n\t\t\t\tgl.ONE,\n\t\t\t\tgl.ONE_MINUS_SRC_ALPHA,\n\t\t\t);\n\t\t\tthis.quadProgram.use();\n\t\t\tthis.quadProgram.setUniform1i(\"u_texture\", 0);\n\t\t\tthis.quadProgram.setUniform1f(\n\t\t\t\t\"u_alpha\",\n\t\t\t\teaseInOutSine(clamp01(state.alpha)),\n\t\t\t);\n\n\t\t\tgl.activeTexture(gl.TEXTURE0);\n\t\t\tgl.bindTexture(gl.TEXTURE_2D, this.fboTexture);\n\n\t\t\tgl.bindBuffer(gl.ARRAY_BUFFER, this.quadBuffer);\n\t\t\tconst a_pos = this.quadProgram.attrs.a_pos;\n\t\t\tgl.vertexAttribPointer(a_pos, 2, gl.FLOAT, false, 0, 0);\n\t\t\tgl.enableVertexAttribArray(a_pos);\n\n\t\t\tgl.drawArrays(gl.TRIANGLES, 0, 6);\n\t\t\tgl.disableVertexAttribArray(a_pos);\n\t\t}\n\n\t\tgl.flush();\n\n\t\treturn canBeStatic;\n\t}\n\n\tprivate onTickBinded = this.onTick.bind(this);\n\n\tprivate requestTick() {\n\t\tif (this._disposed) return;\n\t\tif (this.tickHandle === 0)\n\t\t\tthis.tickHandle = requestAnimationFrame(this.onTickBinded);\n\t}\n\n\t// private supportTextureFloat = true;\n\n\tconstructor(canvas: HTMLCanvasElement) {\n\t\tsuper(canvas);\n\n\t\tconst gl = canvas.getContext(\"webgl\", { antialias: true });\n\t\tif (!gl) throw new Error(\"WebGL not supported\");\n\t\tthis.gl = gl;\n\t\tthis.initializeGLResources();\n\t\tcanvas.addEventListener(\"webglcontextlost\", this.onContextLost);\n\t\tcanvas.addEventListener(\"webglcontextrestored\", this.onContextRestored);\n\n\t\tthis.requestTick();\n\t}\n\n\tprotected override onResize(width: number, height: number): void {\n\t\tthis.targetSize.x = Math.ceil(width);\n\t\tthis.targetSize.y = Math.ceil(height);\n\t\tthis.requestTick();\n\t}\n\n\toverride setStaticMode(enable: boolean): void {\n\t\tthis.staticMode = enable;\n\t\tthis.lastFrameTime = performance.now();\n\t\tthis.requestTick();\n\t}\n\toverride setFPS(fps: number): void {\n\t\tthis.maxFPS = fps;\n\t}\n\toverride pause(): void {\n\t\tif (this.tickHandle) {\n\t\t\tcancelAnimationFrame(this.tickHandle);\n\t\t\tthis.tickHandle = 0;\n\t\t}\n\t\tthis.paused = true;\n\t}\n\toverride resume(): void {\n\t\tthis.paused = false;\n\t\tthis.requestTick();\n\t}\n\toverride async setAlbum(\n\t\talbumSource?: string | HTMLImageElement | HTMLVideoElement,\n\t\tisVideo?: boolean,\n\t): Promise<void> {\n\t\tconst requestId = ++this.albumRequestId;\n\t\tthis.albumLoadController?.abort();\n\t\tconst loadController = new AbortController();\n\t\tthis.albumLoadController = loadController;\n\n\t\tif (\n\t\t\talbumSource === undefined ||\n\t\t\t(typeof albumSource === \"string\" && albumSource.trim().length === 0)\n\t\t) {\n\t\t\tthis.isNoCover = true;\n\t\t\tthis.lastImageData = undefined;\n\t\t\treturn;\n\t\t}\n\t\tlet res: HTMLImageElement | HTMLVideoElement | null = null;\n\t\tlet blob: Blob | null = null;\n\t\tlet objectUrl: string | undefined;\n\t\tlet remainRetryTimes = 5;\n\t\twhile (!res && remainRetryTimes > 0) {\n\t\t\ttry {\n\t\t\t\tif (typeof albumSource === \"string\") {\n\t\t\t\t\tif (!isVideo && \"createImageBitmap\" in window) {\n\t\t\t\t\t\t// 如果支持 createImageBitmap 且是图片,直接 fetch blob\n\t\t\t\t\t\tconst response = await fetch(albumSource, {\n\t\t\t\t\t\t\tsignal: loadController.signal,\n\t\t\t\t\t\t});\n\t\t\t\t\t\tblob = await response.blob();\n\t\t\t\t\t\tif (!this.isCurrentAlbumRequest(requestId)) return;\n\t\t\t\t\t\t// 仍然需要一个 HTMLImageElement 来获取原始宽高(如果后续需要)\n\t\t\t\t\t\t// 但这里我们主要依赖 blob 来创建 bitmap\n\t\t\t\t\t\tobjectUrl = URL.createObjectURL(blob);\n\t\t\t\t\t\tres = await loadResourceFromUrl(objectUrl, false);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tres = await loadResourceFromUrl(albumSource, isVideo);\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tres = await loadResourceFromElement(albumSource);\n\t\t\t\t}\n\t\t\t\tif (!this.isCurrentAlbumRequest(requestId)) {\n\t\t\t\t\tif (objectUrl) URL.revokeObjectURL(objectUrl);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t} catch (error) {\n\t\t\t\tif (objectUrl) {\n\t\t\t\t\tURL.revokeObjectURL(objectUrl);\n\t\t\t\t\tobjectUrl = undefined;\n\t\t\t\t}\n\t\t\t\tif (!this.isCurrentAlbumRequest(requestId)) return;\n\t\t\t\tconsole.warn(\n\t\t\t\t\t`failed on loading album resource, retrying (${remainRetryTimes})`,\n\t\t\t\t\t{\n\t\t\t\t\t\talbumSource,\n\t\t\t\t\t\terror,\n\t\t\t\t\t},\n\t\t\t\t);\n\t\t\t\tremainRetryTimes--;\n\t\t\t}\n\t\t}\n\t\tif (!res) {\n\t\t\tif (!this.isCurrentAlbumRequest(requestId)) return;\n\t\t\tconsole.error(\"Failed to load album resource\", albumSource);\n\t\t\treturn;\n\t\t}\n\t\t// resize image\n\t\tconst c = this.reduceImageSizeCanvas;\n\t\tconst ctx = c.getContext(\"2d\", {\n\t\t\twillReadFrequently: true,\n\t\t});\n\t\tif (!ctx) throw new Error(\"Failed to create canvas context\");\n\t\tctx.clearRect(0, 0, c.width, c.height);\n\t\t// Safari 不支持 filter\n\t\t// ctx.filter = baseFilter;\n\t\tconst imgw =\n\t\t\tres instanceof HTMLVideoElement ? res.videoWidth : res.naturalWidth;\n\t\tconst imgh =\n\t\t\tres instanceof HTMLVideoElement ? res.videoHeight : res.naturalHeight;\n\t\tif (imgw * imgh === 0) throw new Error(\"Invalid image size\");\n\n\t\tlet bitmap: ImageBitmap | null = null;\n\t\ttry {\n\t\t\tif (\"createImageBitmap\" in window) {\n\t\t\t\t// 避免在主线程进行同步解码,使用 fetch 获取 blob 后再创建 ImageBitmap\n\t\t\t\tif (blob) {\n\t\t\t\t\tbitmap = await createImageBitmap(blob, {\n\t\t\t\t\t\tresizeWidth: c.width,\n\t\t\t\t\t\tresizeHeight: c.height,\n\t\t\t\t\t\tresizeQuality: \"low\",\n\t\t\t\t\t});\n\t\t\t\t} else {\n\t\t\t\t\tbitmap = await createImageBitmap(res, {\n\t\t\t\t\t\tresizeWidth: c.width,\n\t\t\t\t\t\tresizeHeight: c.height,\n\t\t\t\t\t\tresizeQuality: \"low\",\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\t\t} catch (e) {\n\t\t\tconsole.warn(\"createImageBitmap failed\", e);\n\t\t}\n\t\tif (!this.isCurrentAlbumRequest(requestId)) {\n\t\t\tbitmap?.close();\n\t\t\tif (objectUrl) URL.revokeObjectURL(objectUrl);\n\t\t\treturn;\n\t\t}\n\n\t\tif (bitmap) {\n\t\t\tctx.drawImage(bitmap, 0, 0);\n\t\t\tbitmap.close();\n\t\t} else {\n\t\t\tctx.drawImage(res, 0, 0, imgw, imgh, 0, 0, c.width, c.height);\n\t\t}\n\n\t\tconst imageData = ctx.getImageData(0, 0, c.width, c.height);\n\n\t\t// 合并对比度、饱和度、亮度的处理,减少循环次数\n\t\tconst pixels = imageData.data;\n\t\tfor (let i = 0; i < pixels.length; i += 4) {\n\t\t\tlet r = pixels[i];\n\t\t\tlet g = pixels[i + 1];\n\t\t\tlet b = pixels[i + 2];\n\n\t\t\t// contrast 0.4\n\t\t\tr = (r - 128) * 0.4 + 128;\n\t\t\tg = (g - 128) * 0.4 + 128;\n\t\t\tb = (b - 128) * 0.4 + 128;\n\n\t\t\t// saturate 3.0\n\t\t\tconst gray = r * 0.3 + g * 0.59 + b * 0.11;\n\t\t\tr = gray * -2.0 + r * 3.0;\n\t\t\tg = gray * -2.0 + g * 3.0;\n\t\t\tb = gray * -2.0 + b * 3.0;\n\n\t\t\t// contrast 1.7\n\t\t\tr = (r - 128) * 1.7 + 128;\n\t\t\tg = (g - 128) * 1.7 + 128;\n\t\t\tb = (b - 128) * 1.7 + 128;\n\n\t\t\t// brightness 0.75\n\t\t\tpixels[i] = r * 0.75;\n\t\t\tpixels[i + 1] = g * 0.75;\n\t\t\tpixels[i + 2] = b * 0.75;\n\t\t}\n\n\t\tblurImage(imageData, 2, 4);\n\n\t\tif (this.manualControl && this.meshStates.length > 0) {\n\t\t\tthis.meshStates[0].texture.dispose();\n\t\t\tthis.meshStates[0].texture = new GLTexture(this.gl, imageData);\n\t\t} else {\n\t\t\tthis.meshStates.push(this.createMeshState(imageData));\n\t\t}\n\n\t\tthis.isNoCover = false;\n\t\tthis.lastImageData = imageData;\n\t\tif (objectUrl) URL.revokeObjectURL(objectUrl);\n\t\tthis.requestTick();\n\t}\n\toverride setLowFreqVolume(volume: number): void {\n\t\tthis.volume = volume / 10;\n\t}\n\toverride setHasLyric(_hasLyric: boolean): void {\n\t\t// 不再考虑实现\n\t}\n\n\toverride dispose(): void {\n\t\tsuper.dispose();\n\t\tthis.albumLoadController?.abort();\n\t\tthis.canvas.removeEventListener(\"webglcontextlost\", this.onContextLost);\n\t\tthis.canvas.removeEventListener(\n\t\t\t\"webglcontextrestored\",\n\t\t\tthis.onContextRestored,\n\t\t);\n\t\tif (this.tickHandle) {\n\t\t\tcancelAnimationFrame(this.tickHandle);\n\t\t\tthis.tickHandle = 0;\n\t\t}\n\t\tthis._disposed = true;\n\t\tthis.mainProgram.dispose();\n\t\tthis.quadProgram.dispose();\n\t\tthis.gl.deleteBuffer(this.quadBuffer);\n\t\tif (this.fbo) this.gl.deleteFramebuffer(this.fbo);\n\t\tif (this.fboTexture) this.gl.deleteTexture(this.fboTexture);\n\t\tfor (const state of this.meshStates) {\n\t\t\tstate.mesh.dispose();\n\t\t\tstate.texture.dispose();\n\t\t}\n\t}\n\n\tenablePerformanceMonitor(enable: boolean): void {\n\t\tthis.enablePerformanceMonitoring = enable;\n\t\tif (enable) {\n\t\t\tthis.frameCount = 0;\n\t\t\tthis.lastFPSUpdate = performance.now();\n\t\t}\n\t}\n\n\tgetCurrentFPS(): number {\n\t\treturn this.currentFPS;\n\t}\n\n\tprivate updatePerformanceStats(tickTime: number) {\n\t\tif (!this.enablePerformanceMonitoring) return;\n\n\t\tthis.frameCount++;\n\t\tif (tickTime - this.lastFPSUpdate > 1000) {\n\t\t\tthis.currentFPS = this.frameCount;\n\t\t\tthis.frameCount = 0;\n\t\t\tthis.lastFPSUpdate = tickTime;\n\t\t}\n\t}\n}\n","import { Application } from \"@pixi/app\";\nimport { Texture, utils } from \"@pixi/core\";\nimport { Container } from \"@pixi/display\";\nimport { BlurFilter } from \"@pixi/filter-blur\";\nimport { BulgePinchFilter } from \"@pixi/filter-bulge-pinch\";\nimport { ColorMatrixFilter } from \"@pixi/filter-color-matrix\";\nimport { Sprite } from \"@pixi/sprite\";\nimport { clampPositive } from \"#utils/clamp.ts\";\nimport {\n\tloadResourceFromElement,\n\tloadResourceFromUrl,\n} from \"../utils/resource\";\nimport { BaseRenderer } from \"./base\";\n\nclass TimedContainer extends Container {\n\tpublic time = 0;\n}\n\nexport class PixiRenderer extends BaseRenderer {\n\t/**\n\t * 当前环境是否支持此渲染器\n\t */\n\tstatic isSupported(): boolean {\n\t\t// 询问 Pixi 是否支持而不是仓库内的 WebGL 检测,因为 Pixi 有额外的模板缓冲区要求\n\t\treturn utils.isWebGLSupported();\n\t}\n\n\tprivate app: Application;\n\tprivate curContainer?: TimedContainer;\n\tprivate staticMode = false;\n\tprivate lastContainer: Set<TimedContainer> = new Set();\n\tprivate onTick = (delta: number): void => {\n\t\tfor (const lastContainer of this.lastContainer) {\n\t\t\tlastContainer.alpha = clampPositive(lastContainer.alpha - delta / 60);\n\t\t\tif (lastContainer.alpha <= 0) {\n\t\t\t\tthis.app.stage.removeChild(lastContainer);\n\t\t\t\tthis.lastContainer.delete(lastContainer);\n\t\t\t\tlastContainer.destroy(true);\n\t\t\t}\n\t\t}\n\n\t\tif (this.curContainer) {\n\t\t\tthis.curContainer.alpha = Math.min(\n\t\t\t\t1,\n\t\t\t\tthis.curContainer.alpha + delta / 60,\n\t\t\t);\n\t\t\tconst [s1, s2, s3, s4] = this.curContainer.children as Sprite[];\n\t\t\tconst maxSize = Math.max(this.app.screen.width, this.app.screen.height);\n\t\t\ts1.position.set(this.app.screen.width / 2, this.app.screen.height / 2);\n\t\t\ts2.position.set(\n\t\t\t\tthis.app.screen.width / 2.5,\n\t\t\t\tthis.app.screen.height / 2.5,\n\t\t\t);\n\t\t\ts3.position.set(this.app.screen.width / 2, this.app.screen.height / 2);\n\t\t\ts4.position.set(this.app.screen.width / 2, this.app.screen.height / 2);\n\t\t\ts1.width = maxSize * Math.sqrt(2);\n\t\t\ts1.height = s1.width;\n\t\t\ts2.width = maxSize * 0.8;\n\t\t\ts2.height = s2.width;\n\t\t\ts3.width = maxSize * 0.5;\n\t\t\ts3.height = s3.width;\n\t\t\ts4.width = maxSize * 0.25;\n\t\t\ts4.height = s4.width;\n\n\t\t\tthis.curContainer.time += delta * this.flowSpeed;\n\n\t\t\ts1.rotation += (delta / 1000) * this.flowSpeed;\n\t\t\ts2.rotation -= (delta / 500) * this.flowSpeed;\n\t\t\ts3.rotation += (delta / 1000) * this.flowSpeed;\n\t\t\ts4.rotation -= (delta / 750) * this.flowSpeed;\n\n\t\t\ts3.x =\n\t\t\t\tthis.app.screen.width / 2 +\n\t\t\t\t(this.app.screen.width / 4) *\n\t\t\t\t\tMath.cos((this.curContainer.time / 1000) * 0.75);\n\t\t\ts3.y =\n\t\t\t\tthis.app.screen.height / 2 +\n\t\t\t\t(this.app.screen.width / 4) *\n\t\t\t\t\tMath.cos((this.curContainer.time / 1000) * 0.75);\n\n\t\t\ts4.x =\n\t\t\t\tthis.app.screen.width / 2 +\n\t\t\t\t(this.app.screen.width / 4) * 0.1 +\n\t\t\t\tMath.cos(this.curContainer.time * 0.006 * 0.75);\n\t\t\ts4.y =\n\t\t\t\tthis.app.screen.height / 2 +\n\t\t\t\t(this.app.screen.width / 4) * 0.1 +\n\t\t\t\tMath.cos(this.curContainer.time * 0.006 * 0.75);\n\n\t\t\tif (\n\t\t\t\tthis.curContainer.alpha >= 1 &&\n\t\t\t\tthis.lastContainer.size === 0 &&\n\t\t\t\tthis.staticMode\n\t\t\t) {\n\t\t\t\tthis.app.ticker.stop();\n\t\t\t}\n\t\t}\n\t};\n\tconstructor(protected override canvas: HTMLCanvasElement) {\n\t\tsuper(canvas);\n\t\tthis.app = new Application({\n\t\t\tview: canvas,\n\t\t\tresizeTo: this.canvas,\n\t\t\tpowerPreference: \"low-power\",\n\t\t\tbackgroundAlpha: 1,\n\t\t});\n\t\tthis.rebuildFilters();\n\t\tthis.app.ticker.maxFPS = 30;\n\t\tthis.app.ticker.add(this.onTick);\n\t\tthis.app.ticker.start();\n\t}\n\n\tprotected override onResize(width: number, height: number): void {\n\t\tsuper.onResize(width, height);\n\t\tthis.app.resize();\n\t\tthis.rebuildFilters();\n\t}\n\n\toverride setRenderScale(scale: number): void {\n\t\tsuper.setRenderScale(scale);\n\t\tthis.rebuildFilters();\n\t}\n\tprivate rebuildFilters() {\n\t\tconst minBorder = Math.min(this.canvas.width, this.canvas.height);\n\t\tconst maxBorder = Math.max(this.canvas.width, this.canvas.height);\n\t\tconst c0 = new ColorMatrixFilter();\n\t\tc0.saturate(1.2, false);\n\t\tconst c1 = new ColorMatrixFilter();\n\t\tc1.brightness(0.6, false);\n\t\tconst c2 = new ColorMatrixFilter();\n\t\tc2.contrast(0.3, true);\n\t\tfor (const filter of this.app.stage.filters ?? []) {\n\t\t\tfilter.destroy();\n\t\t}\n\t\tthis.app.stage.filters = [];\n\t\tthis.app.stage.filters.push(new BlurFilter(5, 1));\n\t\tthis.app.stage.filters.push(new BlurFilter(10, 1));\n\t\tthis.app.stage.filters.push(new BlurFilter(20, 2));\n\t\tthis.app.stage.filters.push(new BlurFilter(40, 2));\n\t\tthis.app.stage.filters.push(new BlurFilter(80, 2));\n\t\tif (minBorder > 768) this.app.stage.filters.push(new BlurFilter(160, 4));\n\t\tif (minBorder > 768 * 2)\n\t\t\tthis.app.stage.filters.push(new BlurFilter(320, 4));\n\n\t\tthis.app.stage.filters.push(c0, c1, c2);\n\t\tthis.app.stage.filters.push(new BlurFilter(5, 1));\n\t\tif (Math.random() > 0.5) {\n\t\t\tthis.app.stage.filters.push(\n\t\t\t\tnew BulgePinchFilter({\n\t\t\t\t\tradius: (maxBorder + minBorder) / 2,\n\t\t\t\t\tstrength: 1,\n\t\t\t\t\tcenter: [0.25, 1],\n\t\t\t\t}),\n\t\t\t);\n\t\t\tthis.app.stage.filters.push(\n\t\t\t\tnew BulgePinchFilter({\n\t\t\t\t\tradius: (maxBorder + minBorder) / 2,\n\t\t\t\t\tstrength: 1,\n\t\t\t\t\tcenter: [0.75, 0],\n\t\t\t\t}),\n\t\t\t);\n\t\t} else {\n\t\t\tthis.app.stage.filters.push(\n\t\t\t\tnew BulgePinchFilter({\n\t\t\t\t\tradius: (maxBorder + minBorder) / 2,\n\t\t\t\t\tstrength: 1,\n\t\t\t\t\tcenter: [0.75, 1],\n\t\t\t\t}),\n\t\t\t);\n\t\t\tthis.app.stage.filters.push(\n\t\t\t\tnew BulgePinchFilter({\n\t\t\t\t\tradius: (maxBorder + minBorder) / 2,\n\t\t\t\t\tstrength: 1,\n\t\t\t\t\tcenter: [0.25, 0],\n\t\t\t\t}),\n\t\t\t);\n\t\t}\n\t}\n\n\toverride setStaticMode(enable = false): void {\n\t\tthis.staticMode = enable;\n\t\tthis.app.ticker.start();\n\t}\n\n\toverride setFPS(fps: number): void {\n\t\tthis.app.ticker.maxFPS = fps;\n\t}\n\n\toverride pause(): void {\n\t\tthis.app.ticker.stop();\n\t\tthis.app.render();\n\t}\n\n\toverride resume(): void {\n\t\tthis.app.ticker.start();\n\t}\n\n\toverride setLowFreqVolume(_volume: number): void {\n\t\t// NOOP\n\t}\n\n\toverride setHasLyric(_hasLyric: boolean): void {\n\t\t// NOOP\n\t}\n\n\toverride async setAlbum(\n\t\talbumSource?: string | HTMLImageElement | HTMLVideoElement,\n\t\tisVideo?: boolean,\n\t): Promise<void> {\n\t\tif (\n\t\t\t!albumSource ||\n\t\t\t(typeof albumSource === \"string\" && albumSource.trim().length === 0)\n\t\t)\n\t\t\treturn;\n\t\tlet res: HTMLImageElement | HTMLVideoElement | null = null;\n\t\tlet remainRetryTimes = 5;\n\t\tlet tex: Texture | null = null;\n\t\twhile (!tex?.baseTexture?.resource?.valid && remainRetryTimes > 0) {\n\t\t\ttry {\n\t\t\t\tif (typeof albumSource === \"string\") {\n\t\t\t\t\tres = await loadResourceFromUrl(albumSource, isVideo);\n\t\t\t\t} else {\n\t\t\t\t\tres = await loadResourceFromElement(albumSource);\n\t\t\t\t}\n\t\t\t\ttex = Texture.from(res, {\n\t\t\t\t\tresourceOptions: {\n\t\t\t\t\t\tautoLoad: false,\n\t\t\t\t\t},\n\t\t\t\t});\n\t\t\t\tawait tex.baseTexture.resource.load();\n\t\t\t} catch (error) {\n\t\t\t\tconsole.warn(\n\t\t\t\t\t`failed on loading album image, retrying (${remainRetryTimes})`,\n\t\t\t\t\talbumSource,\n\t\t\t\t\terror,\n\t\t\t\t);\n\t\t\t\ttex = null;\n\t\t\t\tremainRetryTimes--;\n\t\t\t}\n\t\t}\n\t\tif (!tex) return;\n\t\tconst container = new TimedContainer();\n\t\tconst s1 = new Sprite(tex);\n\t\tconst s2 = new Sprite(tex);\n\t\tconst s3 = new Sprite(tex);\n\t\tconst s4 = new Sprite(tex);\n\t\ts1.anchor.set(0.5, 0.5);\n\t\ts2.anchor.set(0.5, 0.5);\n\t\ts3.anchor.set(0.5, 0.5);\n\t\ts4.anchor.set(0.5, 0.5);\n\t\ts1.rotation = Math.random() * Math.PI * 2;\n\t\ts2.rotation = Math.random() * Math.PI * 2;\n\t\ts3.rotation = Math.random() * Math.PI * 2;\n\t\ts4.rotation = Math.random() * Math.PI * 2;\n\t\tcontainer.addChild(s1, s2, s3, s4);\n\t\tif (this.curContainer) this.lastContainer.add(this.curContainer);\n\t\tthis.curContainer = container;\n\t\tthis.app.stage.addChild(container);\n\t\tthis.curContainer.alpha = 0;\n\t\tthis.app.ticker.start();\n\t}\n\n\toverride dispose(): void {\n\t\tsuper.dispose();\n\t\tthis.app.ticker.remove(this.onTick);\n\t\tthis.app.destroy(true);\n\t}\n\n\toverride getElement(): HTMLElement {\n\t\treturn this.canvas;\n\t}\n}\n","/**\n * @fileoverview\n * 一个播放歌词的组件\n * @author SteveXMH\n */\n\nexport { AbstractBaseRenderer, BaseRenderer } from \"./base.ts\";\nexport type { GLRenderingContext } from \"./gl-program.ts\";\nexport { GLProgram } from \"./gl-program.ts\";\nexport type { IsolationRendererOptions } from \"./isolation/index.ts\";\nexport { IsolationRenderer } from \"./isolation/index.ts\";\nexport { MeshGradientRenderer } from \"./mesh-renderer/index.ts\";\nexport * from \"./palette/index.ts\";\nexport { PixiRenderer } from \"./pixi-renderer.ts\";\n\nimport type { AbstractBaseRenderer, BaseRenderer } from \"./base.ts\";\n\nexport class BackgroundRender<Renderer extends BaseRenderer>\n\timplements AbstractBaseRenderer\n{\n\tprivate element: HTMLCanvasElement;\n\tprivate renderer: Renderer;\n\tconstructor(renderer: Renderer, canvas: HTMLCanvasElement) {\n\t\tthis.renderer = renderer;\n\n\t\tthis.element = canvas;\n\t\tcanvas.style.pointerEvents = \"none\";\n\t\tcanvas.style.zIndex = \"-1\";\n\t\tcanvas.style.contain = \"strict\";\n\t}\n\n\t/**\n\t * 获取被包装的渲染器实例。\n\t *\n\t * 各个渲染器有自己特有的可调项(例如 {@link IsolationRenderer.setOptions}),\n\t * 这些项没法通过统一的 `AbstractBaseRenderer` 接口下发,需要拿到实例本体。\n\t */\n\tgetRenderer(): Renderer {\n\t\treturn this.renderer;\n\t}\n\n\tstatic new<Renderer extends BaseRenderer>(type: {\n\t\tnew (canvas: HTMLCanvasElement): Renderer;\n\t}): BackgroundRender<Renderer> {\n\t\tconst newCanvas = document.createElement(\"canvas\");\n\t\treturn new BackgroundRender(new type(newCanvas), newCanvas);\n\t}\n\n\tsetRenderScale(scale: number): void {\n\t\tthis.renderer.setRenderScale(scale);\n\t}\n\n\tsetFlowSpeed(speed: number): void {\n\t\tthis.renderer.setFlowSpeed(speed);\n\t}\n\tsetStaticMode(enable: boolean): void {\n\t\tthis.renderer.setStaticMode(enable);\n\t}\n\tsetFPS(fps: number): void {\n\t\tthis.renderer.setFPS(fps);\n\t}\n\tpause(): void {\n\t\tthis.renderer.pause();\n\t}\n\tresume(): void {\n\t\tthis.renderer.resume();\n\t}\n\tsetLowFreqVolume(volume: number): void {\n\t\tthis.renderer.setLowFreqVolume(volume);\n\t}\n\tsetHasLyric(hasLyric: boolean): void {\n\t\tthis.renderer.setHasLyric(hasLyric);\n\t}\n\tsetAlbum(\n\t\talbumSource: string | HTMLImageElement | HTMLVideoElement,\n\t\tisVideo?: boolean,\n\t): Promise<void> {\n\t\treturn this.renderer.setAlbum(albumSource, isVideo);\n\t}\n\tgetElement(): HTMLCanvasElement {\n\t\treturn this.element;\n\t}\n\tdispose(): void {\n\t\tthis.renderer.dispose();\n\t\tthis.element.remove();\n\t}\n}\n","declare const DURATION_BRAND: unique symbol;\ndeclare const MEDIA_TIME_BRAND: unique symbol;\n\n/**\n * 一段时长,内部以毫秒浮点数表示\n */\nexport type Duration = { readonly [DURATION_BRAND]: true };\n\n/**\n * 媒体时间轴上的一个时间点,内部以毫秒浮点数表示\n *\n * 原点为歌曲起始 0ms\n */\nexport type MediaTime = { readonly [MEDIA_TIME_BRAND]: true };\n\nconst toD = (ms: number): Duration => ms as unknown as Duration;\nconst toM = (ms: number): MediaTime => ms as unknown as MediaTime;\nconst toNum = (t: Duration | MediaTime): number => t as unknown as number;\n\nexport const Duration = {\n\tZERO: toD(0) as Duration,\n\tfromMillis: (ms: number): Duration => toD(ms),\n\tfromSecs: (s: number): Duration => toD(s * 1000),\n\tasMillis: (d: Duration): number => toNum(d),\n\tasSecsF64: (d: Duration): number => toNum(d) / 1000,\n\tadd: (a: Duration, b: Duration): Duration => toD(toNum(a) + toNum(b)),\n\tsub: (a: Duration, b: Duration): Duration => toD(toNum(a) - toNum(b)),\n\tsaturatingSub: (a: Duration, b: Duration): Duration =>\n\t\ttoD(Math.max(0, toNum(a) - toNum(b))),\n\tmulF64: (d: Duration, factor: number): Duration => toD(toNum(d) * factor),\n\tdivDuration: (a: Duration, b: Duration): number => toNum(a) / toNum(b),\n\tmin: (a: Duration, b: Duration): Duration => (a < b ? a : b),\n\tmax: (a: Duration, b: Duration): Duration => (a > b ? a : b),\n\tclampPositive: (d: Duration): Duration => toD(Math.max(0, toNum(d))),\n\tisZero: (d: Duration): boolean => toNum(d) === 0,\n\tisFinite: (d: Duration): boolean => Number.isFinite(toNum(d)),\n} as const;\n\nexport const MediaTime = {\n\tZERO: toM(0) as MediaTime,\n\tfromMillis: (ms: number): MediaTime => toM(ms),\n\tasMillis: (t: MediaTime): number => toNum(t),\n\tsince: (a: MediaTime, b: MediaTime): Duration => toD(toNum(a) - toNum(b)),\n\tsaturatingSince: (a: MediaTime, b: MediaTime): Duration =>\n\t\ttoD(Math.max(0, toNum(a) - toNum(b))),\n\tadd: (t: MediaTime, d: Duration): MediaTime => toM(toNum(t) + toNum(d)),\n\tsub: (t: MediaTime, d: Duration): MediaTime => toM(toNum(t) - toNum(d)),\n\tmin: (a: MediaTime, b: MediaTime): MediaTime => (a < b ? a : b),\n\tmax: (a: MediaTime, b: MediaTime): MediaTime => (a > b ? a : b),\n\tcmp: (a: MediaTime, b: MediaTime): number => toNum(a) - toNum(b),\n\tround: (t: MediaTime): MediaTime => toM(Math.round(toNum(t))),\n} as const;\n","import { Duration } from \"#utils/time.ts\";\n\ntype ValueOf<T extends Record<PropertyKey, unknown>> = T[keyof T];\n\n/** 歌词中不雅用语的掩码模式 */\nexport const MaskObsceneWordsMode = {\n\t/** 禁用任何不雅用语掩码 */\n\tDisabled: \"\",\n\t/** 完全掩码所有不雅用语 */\n\tFullMask: \"full-mask\",\n\t/** 保留首尾字符,屏蔽中间字符 */\n\tPartialMask: \"partial-mask\",\n} as const;\n\n/** 歌词中不雅用语的掩码模式枚举类型,见 {@link MaskObsceneWordsMode} */\nexport type MaskObsceneWordsMode = ValueOf<typeof MaskObsceneWordsMode>;\n\n/**\n * 歌词行的渲染模式\n * @internal\n */\nexport const LyricLineRenderMode = {\n\tSOLID: 0,\n\tGRADIENT: 1,\n} as const;\n\n/**\n * 歌词行的渲染模式枚举类型,见 {@link LyricLineRenderMode}\n * @internal\n */\nexport type LyricLineRenderMode = ValueOf<typeof LyricLineRenderMode>;\n\n/** 布局对齐锚点 */\nexport const LayoutAlignAnchor = {\n\tTop: \"top\",\n\tCenter: \"center\",\n\tBottom: \"bottom\",\n} as const;\n\n/** 布局对齐锚点枚举类型,见 {@link LayoutAlignAnchor} */\nexport type LayoutAlignAnchor = ValueOf<typeof LayoutAlignAnchor>;\n\n/**\n * 触发排版布局更新的原因场景\n */\nexport const LayoutReason = {\n\t/** 正常播放时间推进 */\n\tPlaybackTick: \"playback-tick\",\n\t/** 容器或窗口尺寸调整 */\n\tResize: \"resize\",\n\t/** 用户交互挂起开始(触摸/滚轮触发) */\n\tInteractionStart: \"interaction-start\",\n\t/** 连续高频滚动(手指触摸滑动或松手后的 RAF 惯性滑动) */\n\tContinuousScroll: \"continuous-scroll\",\n\t/** 离散单步滚动(鼠标滚轮单次滚动) */\n\tDiscreteScroll: \"discrete-scroll\",\n\t/** 跳转播放进度 */\n\tSeek: \"seek\",\n\t/** 重新构建歌词视图 */\n\tRebuildView: \"rebuild-view\",\n\t/** 视图结构或样式配置改变 */\n\tConfigChange: \"config-change\",\n} as const;\n\n/** 触发排版布局更新的原因场景枚举类型,见 {@link LayoutReason} */\nexport type LayoutReason = ValueOf<typeof LayoutReason>;\n\n/**\n * 对应各个 LayoutReason 的排版执行策略定义\n */\nexport interface LayoutStrategy {\n\t/** 是否禁用阶梯交错动画 */\n\tdisableStagger: boolean;\n\t/** 是否重置间奏圆点动画 */\n\tresetInterlude: boolean;\n\t/**\n\t * 是否瞬移 Y 轴位置而不经过弹簧动画\n\t *\n\t * 一般用于触摸拖动中,避免弹簧动画导致拖动不跟手\n\t */\n\tsnapPosY: boolean;\n}\n\n/**\n * 排版原因到排版执行策略的映射字典\n */\nexport const LayoutReasonStrategyMap: Record<LayoutReason, LayoutStrategy> = {\n\t[LayoutReason.PlaybackTick]: {\n\t\tdisableStagger: false,\n\t\tresetInterlude: false,\n\t\tsnapPosY: false,\n\t},\n\t[LayoutReason.ContinuousScroll]: {\n\t\tdisableStagger: true,\n\t\tresetInterlude: false,\n\t\tsnapPosY: true,\n\t},\n\t[LayoutReason.DiscreteScroll]: {\n\t\tdisableStagger: true,\n\t\tresetInterlude: false,\n\t\tsnapPosY: false,\n\t},\n\t[LayoutReason.InteractionStart]: {\n\t\tdisableStagger: true,\n\t\tresetInterlude: false,\n\t\tsnapPosY: false,\n\t},\n\t[LayoutReason.Seek]: {\n\t\tdisableStagger: true,\n\t\tresetInterlude: true,\n\t\tsnapPosY: false,\n\t},\n\t// RebuildView 时也不应该瞬移 Y 轴,因为载入歌词时有一个歌词行从底部远处飞入的动画,需要弹簧来动画\n\t[LayoutReason.RebuildView]: {\n\t\tdisableStagger: true,\n\t\tresetInterlude: true,\n\t\tsnapPosY: false,\n\t},\n\t[LayoutReason.Resize]: {\n\t\tdisableStagger: true,\n\t\tresetInterlude: false,\n\t\tsnapPosY: false,\n\t},\n\t[LayoutReason.ConfigChange]: {\n\t\tdisableStagger: true,\n\t\tresetInterlude: false,\n\t\tsnapPosY: false,\n\t},\n};\n\n/**\n * 单帧动画时长的钳制上限,用于页面挂起等场景\n *\n * 此时首帧 update 的 delta 携带整个挂起时长,直接透传会导致动画以数秒的时长过冲\n */\nexport const MAX_FRAME_DELTA: Duration = Duration.fromMillis(100);\n","@property --bright-mask-alpha {\n\tsyntax: \"<number>\";\n\tinherits: true;\n\tinitial-value: 1;\n}\n\n@property --dark-mask-alpha {\n\tsyntax: \"<number>\";\n\tinherits: true;\n\tinitial-value: 0.2;\n}\n\n.lyricLineWrapper {\n\tposition: absolute;\n\ttop: 0;\n\tleft: 0;\n\tdisplay: flex;\n\tflex-direction: column;\n\talign-items: flex-start;\n\twidth: 100%;\n\tbox-sizing: border-box;\n\tpadding: 0.4em var(--lyric-line-padding-x);\n\tborder-radius: 0.25em;\n\n\tgap: 0.3em;\n\n\twill-change: transform;\n\ttransition:\n\t\topacity 0.4s ease,\n\t\tfilter 0.4s ease,\n\t\tbackground-color 0.25s ease;\n\n\t&:not(.bottomLineWrapper):hover {\n\t\tbackground-color: var(--amll-lp-hover-bg-color, #fff1);\n\t}\n\n\t&:not(.bottomLineWrapper):active {\n\t\tbackground-color: var(--amll-lp-hover-bg-color, #ffffff05);\n\t}\n}\n\n.lyricLine {\n\tposition: relative;\n\tbox-sizing: border-box;\n\twidth: var(--amll-lp-width, 100%);\n\tmin-width: var(--amll-lp-width, 100%);\n\tmax-width: var(--amll-lp-width, 100%);\n\theight: fit-content;\n\n\tpadding: 0.2em;\n\tmargin: -0.2em;\n\n\tcontain: layout style paint;\n\tcontent-visibility: auto;\n\tcontain-intrinsic-size: auto 40px;\n\tbackface-visibility: hidden;\n\ttransform-origin: left;\n\n\t--mask-alpha-duration: 0.45s;\n\t--bright-mask-alpha: 0.2;\n\t--dark-mask-alpha: 0.2;\n\n\ttransition:\n\t\tbox-shadow 0.25s,\n\t\t--bright-mask-alpha var(--mask-alpha-duration) ease-out,\n\t\t--dark-mask-alpha var(--mask-alpha-duration) ease-out;\n\n\t&.gradientMask {\n\t\t--mask-alpha-duration: 0.3s;\n\t\t--bright-mask-alpha: 1;\n\t\t--dark-mask-alpha: 0.4;\n\t}\n}\n\n.lyricDuetLine {\n\ttext-align: right;\n\ttransform-origin: right;\n}\n\n.lyricMainLine {\n\tmargin: -1em;\n\tpadding: 1em;\n\ttransition: opacity 0.3s 0.1s;\n\tcontain: layout style;\n\n\t& span {\n\t\tdisplay: inline-block;\n\t\ttext-align: start;\n\t\tvertical-align: bottom;\n\t}\n\n\t.romanWord {\n\t\tdisplay: flex;\n\t\tpadding-inline-end: 0.3em;\n\t\tfont-size: 0.5em;\n\t\tline-height: 1em;\n\t}\n\n\t.rubyWord {\n\t\tdisplay: flex;\n\t\tjustify-content: center;\n\t\tmin-height: 1em;\n\t\tfont-size: 0.5em;\n\t\tline-height: 1em;\n\t}\n\n\t.wordWithRuby {\n\t\tdisplay: inline-flex;\n\t\tflex-direction: column;\n\t\talign-items: center;\n\t\tvertical-align: bottom;\n\t}\n\n\t.wordBody {\n\t\tdisplay: flex;\n\t\tflex-direction: column;\n\t}\n\n\t.rubyBaseWord {\n\t\tdisplay: inline-flex;\n\t\tflex-wrap: nowrap;\n\t\twhite-space: nowrap;\n\t\tjustify-content: center;\n\t}\n\n\t& > span,\n\tspan.emphasizeWrapper {\n\t\tdisplay: inline-block;\n\t\tmargin: -1em;\n\t\tpadding: 1em;\n\t\twhite-space: pre-wrap;\n\t\tvertical-align: bottom;\n\t\tcontain: layout style;\n\n\t\t& > span {\n\t\t\tmargin: -1em;\n\t\t\tpadding: 1em;\n\t\t}\n\n\t\t&.emphasize,\n\t\tspan.emphasize {\n\t\t\tbackface-visibility: hidden;\n\n\t\t\t& > span {\n\t\t\t\tmargin: -1em;\n\t\t\t\tpadding: 1em;\n\t\t\t\tbackface-visibility: hidden;\n\t\t\t}\n\t\t}\n\t}\n}\n\n.lyricBgLine {\n\topacity: 0.4;\n\tfont-size: max(calc(1em * var(--amll-lp-bg-line-scale, 0.7)), 10px);\n\ttransition:\n\t\tbackground-color 0.25s,\n\t\tbox-shadow 0.25s,\n\t\t--bright-mask-alpha var(--mask-alpha-duration) ease-out,\n\t\t--dark-mask-alpha var(--mask-alpha-duration) ease-out;\n\n\t.lyricMainLine {\n\t\tpadding: 1.2em 1em;\n\t}\n\n\t&.active {\n\t\topacity: 0.4;\n\t\ttransition:\n\t\t\tbackground-color 0.25s,\n\t\t\tbox-shadow 0.25s,\n\t\t\t--bright-mask-alpha var(--mask-alpha-duration) ease-out,\n\t\t\t--dark-mask-alpha var(--mask-alpha-duration) ease-out;\n\t}\n}\n\n.lyricSubLine {\n\topacity: 0.3;\n\tfont-size: max(0.5em, 10px);\n\tline-height: 1.5em;\n\ttransition: opacity 0.2s 0.25s;\n\n\t@supports (mix-blend-mode: plus-lighter) {\n\t\topacity: 0.3;\n\t}\n}\n\n.bottomLine {\n\tpadding-top: 0;\n\tpadding-bottom: 0;\n\tfont-size: var(--amll-lp-bottom-line-font-size, max(0.7em, 10px));\n\tline-height: 1.8em;\n\tcursor: default;\n\topacity: 0.2;\n\ttransition: opacity 0.4s ease;\n\n\t&.gradientMask {\n\t\topacity: 0.85;\n\t}\n\n\t&:empty {\n\t\tdisplay: none;\n\t\theight: 0;\n\t\tmargin: 0;\n\t\tpadding: 0;\n\t}\n}\n\n.bgWrapper {\n\tposition: absolute;\n\ttop: 100%;\n\tleft: var(--lyric-line-padding-x);\n\tz-index: -1;\n\tdisplay: flex;\n\tflex-direction: column;\n\talign-items: inherit;\n\twidth: calc(100% - var(--lyric-line-padding-x) * 2);\n\n\tvisibility: visible;\n\tpointer-events: auto;\n\topacity: 0;\n\ttransform-origin: left top;\n\ttransition: opacity 0.3s ease;\n}\n\n.bgWrapperTop {\n\tposition: relative;\n\tleft: 0;\n\twidth: 100%;\n\ttop: auto;\n\tbottom: auto;\n\ttransform-origin: left bottom;\n}\n\n.bgWrapperActive {\n\tposition: relative;\n\tleft: 0;\n\twidth: 100%;\n\ttop: auto;\n\tbottom: auto;\n\topacity: 1;\n}\n\n.bgWrapperHidden {\n\tvisibility: hidden;\n\tpointer-events: none;\n}\n\n.interludeDots {\n\tposition: absolute;\n\tleft: 0;\n\tdisplay: flex;\n\talign-items: center;\n\t/* gap 应和圆点直径保持 0.6:1 的比例 */\n\tgap: 0.18em;\n\twidth: fit-content;\n\theight: clamp(0.5em, 1vh, 3em);\n\tpadding: 0.4em var(--lyric-line-padding-x);\n\n\ttransform-origin: center;\n\n\t& > * {\n\t\tdisplay: inline-block;\n\t\twidth: 0.3em;\n\t\theight: 0.3em;\n\t\tborder-radius: 50%;\n\t\tbackground-color: var(--amll-lp-color, white);\n\t\taspect-ratio: 1 / 1;\n\t}\n}\n\n.disableSpring > *,\n.disableSpring .lyricLine {\n\ttransition:\n\t\tfilter 0.25s,\n\t\ttransform 0.5s,\n\t\tbackground-color 0.25s,\n\t\tbox-shadow 0.25s;\n}\n\n.tmpDisableTransition {\n\t/* biome-ignore lint/complexity/noImportantStyles: 覆盖内联样式 */\n\ttransition: none !important;\n}\n\n:global(.amll-lyric-player) {\n\t--lyric-line-padding-x: 1em;\n\n\ttouch-action: pan-x;\n\n\t@media screen and (max-width: 500px) {\n\t\t--lyric-line-padding-x: 20px;\n\t}\n\n\t&:hover .lyricLine,\n\t&:hover .lyricLineWrapper {\n\t\t/* biome-ignore lint/complexity/noImportantStyles: 覆盖内联样式 */\n\t\tfilter: unset !important;\n\t}\n\n\t&:not(.playing) .bgWrapper {\n\t\tposition: relative;\n\t\ttop: auto;\n\t\tbottom: auto;\n\t\topacity: 1;\n\t\tleft: 0;\n\t\twidth: 100%;\n\t}\n\n\t&.hasDuetLine {\n\t\t.lyricLine:not(.lyricDuetLine) {\n\t\t\tpadding-right: 15%;\n\t\t}\n\n\t\t.lyricDuetLine {\n\t\t\tpadding-left: 15%;\n\t\t}\n\n\t\t.isDuetWrapper {\n\t\t\talign-items: flex-end;\n\n\t\t\t.bgWrapper {\n\t\t\t\ttransform-origin: right top;\n\t\t\t}\n\n\t\t\t.bgWrapperTop {\n\t\t\t\ttransform-origin: right bottom;\n\t\t\t}\n\t\t}\n\t}\n}\n","import type { LyricLine, OptimizeLyricOptions } from \"../interfaces.ts\";\n\nconst DEFAULT_OPTIMIZE_OPTIONS: OptimizeLyricOptions = {\n\tnormalizeSpaces: true,\n\tresetLineTimestamps: true,\n\tsyncMainAndBackgroundLines: true,\n\tcleanUnintentionalOverlaps: true,\n\ttryAdvanceStartTime: true,\n};\n\n/**\n * 规范化歌词中的空格,将多个连续空格替换为一个空格\n */\nfunction normalizeSpaces(lines: LyricLine[]) {\n\tfor (const line of lines) {\n\t\tfor (const word of line.words) {\n\t\t\tword.word = word.word.replace(/\\s+/g, \" \");\n\t\t}\n\t}\n}\n\n/**\n * 将行级时间戳强行设为字级时间戳\n */\nfunction resetLineTimestamps(lines: LyricLine[]) {\n\tfor (const line of lines) {\n\t\t// 主要是给 TTML 解析器打补丁,其解析逐行歌词时获得的词时间戳均为0\n\t\t// 如果只有一个词,且该词的起止时间均为0,且行时间戳不全为0,则将行时间戳同步给词时间戳\n\t\tif (\n\t\t\tline.words.length === 1 &&\n\t\t\tline.words[0].startTime === 0 &&\n\t\t\tline.words[0].endTime === 0 &&\n\t\t\t(line.startTime !== 0 || line.endTime !== 0)\n\t\t) {\n\t\t\tline.words[0].startTime = line.startTime;\n\t\t\tline.words[0].endTime = line.endTime;\n\t\t} else if (line.words.length > 0) {\n\t\t\tconst firstWord = line.words[0];\n\t\t\tconst lastWord = line.words[line.words.length - 1];\n\n\t\t\tline.startTime = firstWord.startTime;\n\t\t\tline.endTime = lastWord.endTime;\n\t\t}\n\t}\n}\n\n/**\n * 确保背景人声前存在主歌词,并把多行背景人声转换为单行背景人声 + 主歌词行的形式\n */\nfunction convertExcessiveBackgroundLines(lines: LyricLine[]) {\n\tlet consecutiveBgCount = 0;\n\n\tfor (let i = 0; i < lines.length; i++) {\n\t\tconst line = lines[i];\n\t\tif (line.isBG) {\n\t\t\tconsecutiveBgCount++;\n\t\t\tif (i === 0 || consecutiveBgCount > 1) {\n\t\t\t\tline.isBG = false;\n\t\t\t}\n\t\t} else {\n\t\t\tconsecutiveBgCount = 0;\n\t\t}\n\t}\n}\n\n/**\n * 同步主歌词与背景人声的时间\n *\n * 取两者中最早的开始时间和最晚的结束时间,应用给双方\n */\nfunction syncMainAndBackgroundLines(lines: LyricLine[]) {\n\tfor (let i = lines.length - 1; i >= 0; i--) {\n\t\tconst line = lines[i];\n\t\tif (line.isBG) continue;\n\n\t\tconst nextLine = lines[i + 1];\n\t\tif (nextLine?.isBG) {\n\t\t\tconst allWords = [...line.words, ...nextLine.words].filter(\n\t\t\t\t(w) => w.word.trim().length > 0,\n\t\t\t);\n\n\t\t\tconst finalStart = Math.min(\n\t\t\t\tline.startTime,\n\t\t\t\tnextLine.startTime,\n\t\t\t\t...allWords.map((w) => w.startTime),\n\t\t\t);\n\t\t\tconst finalEnd = Math.max(\n\t\t\t\tline.endTime,\n\t\t\t\tnextLine.endTime,\n\t\t\t\t...allWords.map((w) => w.endTime),\n\t\t\t);\n\n\t\t\tline.startTime = finalStart;\n\t\t\tline.endTime = finalEnd;\n\t\t\tnextLine.startTime = finalStart;\n\t\t\tnextLine.endTime = finalEnd;\n\t\t}\n\t}\n}\n\n/**\n * 按主歌词的开始时间稳定排序,并保持主歌词与其背景人声的相对顺序\n */\nfunction sortLyricLines(lines: LyricLine[]) {\n\tconst groups: {\n\t\tlines: LyricLine[];\n\t\tstartTime: number;\n\t\toriginalIndex: number;\n\t}[] = [];\n\n\tfor (let i = 0; i < lines.length; i++) {\n\t\tconst mainLine = lines[i];\n\t\tconst groupLines = [mainLine];\n\n\t\tif (!mainLine.isBG && lines[i + 1]?.isBG) {\n\t\t\tgroupLines.push(lines[++i]);\n\t\t}\n\n\t\tgroups.push({\n\t\t\tlines: groupLines,\n\t\t\tstartTime: mainLine.startTime,\n\t\t\toriginalIndex: groups.length,\n\t\t});\n\t}\n\n\tgroups.sort((a, b) => {\n\t\tconst timeDifference = a.startTime - b.startTime;\n\t\treturn timeDifference || a.originalIndex - b.originalIndex;\n\t});\n\n\tlet lineIndex = 0;\n\tfor (const group of groups) {\n\t\tfor (const line of group.lines) {\n\t\t\tlines[lineIndex++] = line;\n\t\t}\n\t}\n}\n\n/**\n * 清洗非刻意的重叠\n *\n * | 重叠情况 | 判定 |\n * | :------------------------------------------ | ---- |\n * | 重叠 ≥ 500ms | 有意 |\n * | 100ms < 重叠 < 500ms 且 > 下一行时长的 10% | 有意 |\n * | 重叠 ≤ 100ms 或 ≤ 下一行时长的 10% | 无意 |\n *\n */\nfunction cleanUnintentionalOverlaps(\n\tlines: LyricLine[],\n\tsyncBackgroundLines: boolean,\n) {\n\tfor (let i = 0; i < lines.length - 1; i++) {\n\t\tconst line = lines[i];\n\t\tif (line.isBG) continue;\n\n\t\t// 即使下一行是有意重叠,也继续检查后续仍重叠的歌词,避免不必要的多行高亮,例如:\n\t\t// A 0 - 3000\n\t\t// B 1000 - 2500\n\t\t// C 2950 - 3950\n\t\t// A 与 B 是有意重叠,但 A 与 C 只有 50ms 重叠,所以 A 最终被截断到 2950ms\n\t\tfor (let j = i + 1; j < lines.length; j++) {\n\t\t\tconst nextLine = lines[j];\n\t\t\tif (nextLine.isBG) continue;\n\n\t\t\tconst overlap = line.endTime - nextLine.startTime;\n\n\t\t\tif (overlap <= 0) {\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tconst nextDuration = nextLine.endTime - nextLine.startTime;\n\t\t\tconst percentageThreshold = nextDuration * 0.1;\n\n\t\t\tconst isIntentionalOverlap =\n\t\t\t\toverlap >= 500 || (overlap > 100 && overlap > percentageThreshold);\n\n\t\t\tif (!isIntentionalOverlap) {\n\t\t\t\tline.endTime = nextLine.startTime;\n\n\t\t\t\tconst attachedBgLine = lines[i + 1];\n\t\t\t\tif (syncBackgroundLines && attachedBgLine?.isBG) {\n\t\t\t\t\tattachedBgLine.endTime = nextLine.startTime;\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n}\n\n/**\n * 尝试让歌词提前最多 600ms 开始,如果有重叠则尝试提前 400ms,不够 400ms 的提前重叠时长的 70%\n */\nfunction tryAdvanceStartTime(lines: LyricLine[], syncBackgroundLines: boolean) {\n\t/**\n\t * 适用于第一行歌词或与上一行歌词存在充足间隔的提前量\n\t */\n\tconst defaultAdvanceAmount = 600;\n\t/**\n\t * 适用于与上一行存在重叠的提前量\n\t */\n\tconst fallbackAdvanceAmount = 400;\n\t/**\n\t * 与上一行重叠但重叠时长不够 400ms 时,按重叠时长提前的比率\n\t */\n\tconst fallbackAdvanceRatio = 0.7;\n\n\tlet prevLineStartTime = 0;\n\tlet prevLineEndTime = 0;\n\tlet prevMainGroupStartTime = 0;\n\tlet prevMainGroupEndTime = 0;\n\tlet hasPrevLine = false;\n\n\tfor (let i = 0; i < lines.length; i++) {\n\t\tconst line = lines[i];\n\t\tif (line.isBG) continue;\n\n\t\tconst originalStartTime = line.startTime;\n\t\tconst originalEndTime = line.endTime;\n\n\t\tlet targetAdvanceAmount = 0;\n\t\tlet safeBoundary = 0;\n\n\t\tif (hasPrevLine) {\n\t\t\tconst originallyHadGap = originalStartTime >= prevLineEndTime;\n\n\t\t\tif (originallyHadGap) {\n\t\t\t\t// 与上一行有空隙或严丝合缝,最多提前 600ms,不超过上一行的结束时间\n\t\t\t\ttargetAdvanceAmount = defaultAdvanceAmount;\n\t\t\t\tsafeBoundary = prevMainGroupEndTime;\n\t\t\t} else {\n\t\t\t\t// 与上一行有重叠,尝试提前 400ms,重叠时长不足则提前重叠时长的 70%\n\t\t\t\tconst overlapDuration = prevLineEndTime - originalStartTime;\n\n\t\t\t\tif (overlapDuration < fallbackAdvanceAmount) {\n\t\t\t\t\ttargetAdvanceAmount = overlapDuration * fallbackAdvanceRatio;\n\t\t\t\t} else {\n\t\t\t\t\ttargetAdvanceAmount = fallbackAdvanceAmount;\n\t\t\t\t}\n\t\t\t\t// 使用上一条主歌词的时间,不能依赖可能独立计时的背景行\n\t\t\t\tsafeBoundary = prevLineStartTime;\n\t\t\t}\n\t\t} else {\n\t\t\t// 第一行歌词\n\t\t\ttargetAdvanceAmount = defaultAdvanceAmount;\n\t\t\tsafeBoundary = 0;\n\t\t}\n\n\t\tconst targetTime = line.startTime - targetAdvanceAmount;\n\t\tconst newStartTime = Math.max(safeBoundary, targetTime);\n\n\t\tif (newStartTime < line.startTime) {\n\t\t\tline.startTime = newStartTime;\n\t\t}\n\n\t\t// 启用时间同步时,给背景人声同步开始时间\n\t\tconst nextLine = lines[i + 1];\n\t\tif (syncBackgroundLines && nextLine?.isBG) {\n\t\t\tnextLine.startTime = line.startTime;\n\t\t}\n\n\t\t// 为连续重叠的歌词行都加到一个组里,以便接下来不重叠的歌词行看到的是整个组的时间边界而不仅限于上一行的边界\n\t\tif (hasPrevLine) {\n\t\t\tconst overlapsPrevGroup =\n\t\t\t\toriginalStartTime < prevMainGroupEndTime &&\n\t\t\t\toriginalEndTime > prevMainGroupStartTime;\n\n\t\t\tif (overlapsPrevGroup) {\n\t\t\t\tprevMainGroupStartTime = Math.min(\n\t\t\t\t\tprevMainGroupStartTime,\n\t\t\t\t\toriginalStartTime,\n\t\t\t\t);\n\t\t\t\tprevMainGroupEndTime = Math.max(prevMainGroupEndTime, originalEndTime);\n\t\t\t} else {\n\t\t\t\tprevMainGroupStartTime = originalStartTime;\n\t\t\t\tprevMainGroupEndTime = originalEndTime;\n\t\t\t}\n\t\t} else {\n\t\t\tprevMainGroupStartTime = originalStartTime;\n\t\t\tprevMainGroupEndTime = originalEndTime;\n\t\t}\n\n\t\tprevLineStartTime = line.startTime;\n\t\tprevLineEndTime = originalEndTime;\n\t\thasPrevLine = true;\n\t}\n}\n\n/**\n * 浅比对两个 OptimizeLyricOptions 的属性值是否完全一致\n */\nexport function areOptimizeOptionsEqual(\n\ta: OptimizeLyricOptions = {},\n\tb: OptimizeLyricOptions = {},\n): boolean {\n\tconst keysA = Object.keys(a) as (keyof OptimizeLyricOptions)[];\n\tconst keysB = Object.keys(b) as (keyof OptimizeLyricOptions)[];\n\tif (keysA.length !== keysB.length) return false;\n\tfor (const key of keysA) {\n\t\tif (a[key] !== b[key]) return false;\n\t}\n\treturn true;\n}\n\n/**\n * 优化歌词行的展示效果\n *\n * 注意会直接原地修改入参,确保你已经提前深克隆了歌词行数组\n * @param lines 歌词行数组\n * @param options 优化的可选配置,除已弃用选项外默认全部开启\n */\nexport function optimizeLyricLines(\n\tlines: LyricLine[],\n\toptions?: OptimizeLyricOptions,\n): void {\n\tconst config = { ...DEFAULT_OPTIMIZE_OPTIONS, ...options };\n\tconst syncBackgroundLines = config.syncMainAndBackgroundLines ?? true;\n\n\tif (config.normalizeSpaces) {\n\t\tnormalizeSpaces(lines);\n\t}\n\tif (config.resetLineTimestamps) {\n\t\tresetLineTimestamps(lines);\n\t}\n\tconvertExcessiveBackgroundLines(lines);\n\tif (syncBackgroundLines) {\n\t\tsyncMainAndBackgroundLines(lines);\n\t}\n\tsortLyricLines(lines);\n\tif (config.cleanUnintentionalOverlaps) {\n\t\tcleanUnintentionalOverlaps(lines, syncBackgroundLines);\n\t}\n\tif (config.tryAdvanceStartTime) {\n\t\ttryAdvanceStartTime(lines, syncBackgroundLines);\n\t}\n}\n","import type { FocalTarget } from \"./layout.ts\";\nimport type { TimelineSnapshot } from \"./timeline.ts\";\n\n/**\n * 焦点推导所依赖的播放器交互状态\n */\nexport interface FocusResolveFlags {\n\t/**\n\t * 是否处于用户滚动过,尚未回归自动对齐的状态\n\t */\n\tisAutoAlignSuspended: boolean;\n\n\t/**\n\t * 底栏当前是否有内容\n\t */\n\thasBottomContent: boolean;\n\n\t/**\n\t * 当前命中的间奏点是否具备可展示的时长\n\t *\n\t * 为 false 时,焦点将顺延至下一行待唱歌词\n\t */\n\tcanDisplayInterlude: boolean;\n}\n\n/**\n * 对齐焦点状态机\n *\n * 持有跨帧的冻结对齐目标,并在每一帧根据时间线快照与交互状态推导出本帧排版应当对齐的焦点\n *\n * @remarks\n * 规则为:\n * - 用户滚动挂起期间冻结上一帧的焦点,不再跟随播放进度\n * - 若冻结在间奏点上而间奏已经结束,则自动顺延至间奏后的第一行歌词\n * - 未挂起时跟随播放状态:间奏中对齐间奏点,曲末对齐底栏或末行,其余对齐 `scrollToIndex`\n * - 任何情况下产出的歌词行索引都被钳制在 `[0, lineCount - 1]` 内\n */\nexport class FocusController {\n\tprivate target: FocalTarget = { type: \"line\", index: 0 };\n\n\t/**\n\t * 推导本帧的对齐焦点,并将其记录为新的冻结目标\n\t * @param snapshot 当前帧的时间线快照\n\t * @param lineCount 当前歌词行总数\n\t * @param flags 播放器的交互状态\n\t */\n\tpublic resolve(\n\t\tsnapshot: TimelineSnapshot,\n\t\tlineCount: number,\n\t\tflags: FocusResolveFlags,\n\t): FocalTarget {\n\t\tconst nextTarget = flags.isAutoAlignSuspended\n\t\t\t? this.resolveSuspendedTarget(snapshot, lineCount, flags)\n\t\t\t: this.resolveActiveTarget(snapshot, lineCount, flags);\n\n\t\tthis.target = nextTarget;\n\t\treturn nextTarget;\n\t}\n\n\t/**\n\t * 用户滚动挂起期间的焦点解析(维持上一帧目标或在间奏结束/不可用时顺延)\n\t */\n\tprivate resolveSuspendedTarget(\n\t\tsnapshot: TimelineSnapshot,\n\t\tlineCount: number,\n\t\tflags: FocusResolveFlags,\n\t): FocalTarget {\n\t\tconst target = this.target;\n\n\t\tswitch (target.type) {\n\t\t\tcase \"line\":\n\t\t\t\treturn {\n\t\t\t\t\ttype: \"line\",\n\t\t\t\t\tindex: this.clampLineIndex(target.index, lineCount),\n\t\t\t\t};\n\n\t\t\tcase \"interlude\": {\n\t\t\t\tconst isInterludeActive =\n\t\t\t\t\tsnapshot.isFocusOnInterlude &&\n\t\t\t\t\t!!snapshot.activeInterlude &&\n\t\t\t\t\tflags.canDisplayInterlude;\n\n\t\t\t\t// 离开间奏区间或间奏不可显示时,将冻结目标移动至间奏后的下一行歌词\n\t\t\t\tif (!isInterludeActive) {\n\t\t\t\t\treturn {\n\t\t\t\t\t\ttype: \"line\",\n\t\t\t\t\t\tindex: this.clampLineIndex(target.anchorIndex + 1, lineCount),\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t\treturn target;\n\t\t\t}\n\n\t\t\tcase \"bottom\":\n\t\t\t\treturn target;\n\t\t}\n\t}\n\n\t/**\n\t * 正常播放状态下的自动焦点解析\n\t */\n\tprivate resolveActiveTarget(\n\t\tsnapshot: TimelineSnapshot,\n\t\tlineCount: number,\n\t\tflags: FocusResolveFlags,\n\t): FocalTarget {\n\t\t// 处于间奏区间且需聚焦间奏点\n\t\tif (snapshot.isFocusOnInterlude && snapshot.activeInterlude) {\n\t\t\t// 若间奏不可显示,焦点顺延至下一行待唱歌词\n\t\t\tif (!flags.canDisplayInterlude) {\n\t\t\t\treturn {\n\t\t\t\t\ttype: \"line\",\n\t\t\t\t\tindex: this.clampLineIndex(\n\t\t\t\t\t\tsnapshot.activeInterlude.anchorLineIndex + 1,\n\t\t\t\t\t\tlineCount,\n\t\t\t\t\t),\n\t\t\t\t};\n\t\t\t}\n\t\t\treturn {\n\t\t\t\ttype: \"interlude\",\n\t\t\t\tanchorIndex: snapshot.activeInterlude.anchorLineIndex,\n\t\t\t};\n\t\t}\n\n\t\t// 播放完了,如果有底栏则对齐底栏,没有则对齐最后一行歌词\n\t\tif (snapshot.isEndOfSong) {\n\t\t\tif (flags.hasBottomContent) {\n\t\t\t\treturn { type: \"bottom\" };\n\t\t\t}\n\t\t\treturn {\n\t\t\t\ttype: \"line\",\n\t\t\t\tindex: this.clampLineIndex(lineCount - 1, lineCount),\n\t\t\t};\n\t\t}\n\n\t\t// 常规播放跟随\n\t\treturn {\n\t\t\ttype: \"line\",\n\t\t\tindex: this.clampLineIndex(snapshot.scrollToIndex, lineCount),\n\t\t};\n\t}\n\n\t/**\n\t * 将歌词行索引钳制到当前歌词范围内\n\t */\n\tprivate clampLineIndex(index: number, lineCount: number): number {\n\t\tif (lineCount <= 0) return 0;\n\t\treturn Math.min(Math.max(0, index), lineCount - 1);\n\t}\n\n\t/**\n\t * 重置焦点至首行\n\t *\n\t * 一般在载入新歌词、重建歌词视图时调用\n\t */\n\tpublic reset(): void {\n\t\tthis.target = { type: \"line\", index: 0 };\n\t}\n}\n","import { LayoutAlignAnchor } from \"./consts.ts\";\n\n//#region 类型定义\n/**\n * 布局对齐的静态配置项\n *\n * 一般很少改变\n */\nexport interface LayoutConfig {\n\t/**\n\t * 自动对齐的锚点\n\t */\n\talignAnchor: LayoutAlignAnchor;\n\n\t/**\n\t * 0.0 - 1.0 的视口相对位置\n\t */\n\talignPosition: number;\n\n\t/**\n\t * 视口上下额外保留的预渲染距离,单位为像素\n\t */\n\toverscanPx: number;\n}\n\n/**\n * 每一帧都可能变化的排版上下文状态\n */\nexport interface LayoutFrameContext {\n\t/**\n\t * 播放器容器当前总高度\n\t */\n\tcontainerHeight: number;\n\n\t/**\n\t * 被滚动引擎钳制后的安全滚动量\n\t */\n\tscrollOffset: number;\n\n\t/**\n\t * 当前视口焦点目标\n\t */\n\ttarget: FocalTarget;\n\n\t/**\n\t * 底栏高度\n\t */\n\tbottomLineHeight: number;\n\n\t/**\n\t * 间奏点状态,若当前排版帧无间奏则为 undefined\n\t */\n\tinterlude?: {\n\t\t/**\n\t\t * 间奏点高度\n\t\t */\n\t\ttotalHeight: number;\n\t\t/**\n\t\t * 间奏点应挂在第几行之后\n\t\t * -1 表示首行上方,0 ~ N-1 表示对应行下方\n\t\t **/\n\t\tanchorIndex: number;\n\t};\n}\n\n/**\n * 单行歌词的渲染几何指令\n */\nexport interface RenderInstruction {\n\t/**\n\t * 当前行歌词的 Y 轴绝对目标坐标\n\t */\n\ty: number;\n\n\t/**\n\t * 当前行歌词的高\n\t *\n\t * 可能为测量值或估算值\n\t */\n\theight: number;\n\n\t/**\n\t * 当前是否在可视区域(含 Overscan 容差)内,用于剔除渲染\n\t */\n\tisInViewport: boolean;\n}\n\n/**\n * 排版计算返回的复合结果\n */\nexport interface LayoutResult {\n\t/**\n\t * 本次排版计算的有效歌词行数\n\t */\n\tlineCount: number;\n\n\t/**\n\t * 对应所有歌词行的渲染指令池\n\t * @remarks 指令池由 LayoutCalculator 复用,遍历时务必以 {@link lineCount} 为界\n\t */\n\treadonly lineInstructions: ReadonlyArray<RenderInstruction>;\n\n\t/**\n\t * 是否需要显示间奏点\n\t */\n\thasInterlude: boolean;\n\n\t/**\n\t * 如果需要显示间奏点,它的 Y 轴绝对坐标\n\t */\n\tinterludeY: number;\n\n\t/**\n\t * 底栏的 Y 轴绝对坐标\n\t */\n\tbottomLineY: number;\n\n\t/**\n\t * 底栏是否在可视范围内,用于剔除渲染\n\t */\n\tisBottomLineInViewport: boolean;\n}\n\n/**\n * 当前对齐的目标类型\n */\nexport type FocalTargetType = \"line\" | \"interlude\" | \"bottom\";\n\n/**\n * 决定排版原点焦点的目标\n */\nexport type FocalTarget =\n\t| { type: \"line\"; index: number }\n\t| { type: \"interlude\"; anchorIndex: number }\n\t| { type: \"bottom\" };\n\ntype ResolvedLayoutMetrics = {\n\tisValid: boolean;\n\tfocalTopY: number;\n\tanchorOffset: number;\n\tinterludeTotalHeight: number;\n\tactiveInterludeAnchor: number | undefined;\n};\n\nexport type LayoutFrameSession = ResolvedLayoutMetrics & {\n\tcontainerHeight: number;\n\talignPosition: number;\n\toverscanPx: number;\n\tbottomLineHeight: number;\n};\n//#endregion\n\nexport class LayoutCalculator {\n\t//#region 内部状态\n\t/**\n\t * 前缀和缓存\n\t *\n\t * 长度为歌词行数 + 1\n\t *\n\t * prefixSums[i] 存储的是第 0 行到第 i-1 行的总高度,不包含间奏点\n\t */\n\tprivate prefixSums: Float64Array = new Float64Array(0);\n\n\tprivate heights: Float64Array = new Float64Array(0);\n\t/**\n\t * 使用 Uint8Array 作为掩码,1 表示该行经历了真实测量,0 表示该行在使用 fallback 高度\n\t */\n\tprivate isMeasured: Uint8Array = new Uint8Array(0);\n\n\t/**\n\t * 渲染指令对象池\n\t *\n\t * 长度永远只会增加不会减少,避免 GC\n\t */\n\tprivate instructionPool: RenderInstruction[] = [];\n\tprivate isPrefixSumDirty = true;\n\n\tprivate readonly resolvedMetrics: ResolvedLayoutMetrics = {\n\t\tisValid: false,\n\t\tfocalTopY: 0,\n\t\tanchorOffset: 0,\n\t\tinterludeTotalHeight: 0,\n\t\tactiveInterludeAnchor: undefined,\n\t};\n\n\t/**\n\t * 全局唯一复用的返回结果实例\n\t */\n\tprivate readonly layoutResult: LayoutResult = {\n\t\tlineCount: 0,\n\t\tlineInstructions: this.instructionPool,\n\t\tbottomLineY: 0,\n\t\tisBottomLineInViewport: false,\n\t\thasInterlude: false,\n\t\tinterludeY: 0,\n\t};\n\n\t/**\n\t * 缓存的歌词行数\n\t */\n\tprivate lyricCount: number = 0;\n\t/**\n\t * 缓存的所有歌词总高度\n\t */\n\tprivate totalLyricHeight: number = 0;\n\t//#endregion\n\n\t//#region 公共 API\n\t/**\n\t * 初始化排版空间结构与高度缓存\n\t *\n\t * 在加载新歌词时调用\n\t *\n\t * @param count 歌词总行数\n\t * @param defaultHeight 尚未渲染/测量的行的默认回退高度\n\t */\n\tpublic initHeights(count: number, defaultHeight: number): void {\n\t\tthis.lyricCount = count;\n\n\t\tthis.resetLayoutResult();\n\n\t\tif (this.prefixSums.length < count + 1) {\n\t\t\tthis.prefixSums = new Float64Array(count + 1);\n\t\t\tthis.heights = new Float64Array(count);\n\t\t\tthis.isMeasured = new Uint8Array(count);\n\t\t} else {\n\t\t\tthis.prefixSums.fill(0);\n\t\t}\n\n\t\tfor (let i = 0; i < count; i++) {\n\t\t\tthis.heights[i] = defaultHeight;\n\t\t\tthis.isMeasured[i] = 0;\n\t\t}\n\n\t\tthis.isPrefixSumDirty = true;\n\n\t\tconst currentPoolSize = this.instructionPool.length;\n\t\tif (count > currentPoolSize) {\n\t\t\tfor (let i = currentPoolSize; i < count; i++) {\n\t\t\t\tthis.instructionPool.push({\n\t\t\t\t\ty: 0,\n\t\t\t\t\theight: 0,\n\t\t\t\t\tisInViewport: false,\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * 获取指定索引歌词行的计算高度\n\t * @remarks 可能为测量值或估算值\n\t * @param index 歌词行索引\n\t */\n\tpublic getLineHeight(index: number): number {\n\t\tif (index < 0 || index >= this.lyricCount) return 0;\n\t\tthis.ensurePrefixSums();\n\t\treturn this.prefixSums[index + 1] - this.prefixSums[index];\n\t}\n\n\t/**\n\t * 设置单行歌词的真实测量高度\n\t * @param index 歌词行索引\n\t * @param height 真实测量的高度\n\t */\n\tpublic setLineHeight(index: number, height: number): void {\n\t\tif (index < 0 || index >= this.lyricCount) return;\n\n\t\t// 只有高度发生变化,或者该行原本是估算值时,才标记脏数据\n\t\tif (this.heights[index] !== height || this.isMeasured[index] === 0) {\n\t\t\tthis.heights[index] = height;\n\t\t\tthis.isMeasured[index] = 1; // 标记为已测量\n\t\t\tthis.isPrefixSumDirty = true;\n\t\t}\n\t}\n\n\t/**\n\t * 批量更新所有未测量行的回退高度\n\t *\n\t * 仅在容器 Resize 等会导致回退基准(如 containerHeight / 5)发生变化时调用。\n\t * 已被真实测量的行不受影响。\n\t *\n\t * @param defaultHeight 新的默认回退高度\n\t */\n\tpublic updateUnmeasuredHeights(defaultHeight: number): void {\n\t\tlet changed = false;\n\t\tfor (let i = 0; i < this.lyricCount; i++) {\n\t\t\tif (this.isMeasured[i] === 0 && this.heights[i] !== defaultHeight) {\n\t\t\t\tthis.heights[i] = defaultHeight;\n\t\t\t\tchanged = true;\n\t\t\t}\n\t\t}\n\t\tif (changed) {\n\t\t\tthis.isPrefixSumDirty = true;\n\t\t}\n\t}\n\n\t/**\n\t * 解析焦点度量并计算物理滚动边界\n\t *\n\t * 返回滚动安全闭区间 `{ min, max }` 以及此帧的生命周期会话句柄 {@link LayoutFrameSession}\n\t * 供后续使用 `ScrollInteractionEngine.updateBoundary` 钳制 `scrollOffset` 后传给 {@link commit}\n\t *\n\t * @param ctx 动态帧上下文,包含当前容器尺寸、焦点目标与底栏高度\n\t * @param config 布局静态配置,包含对齐锚点、相对位置与 Overscan 容差\n\t */\n\tpublic beginFrame(\n\t\tctx: LayoutFrameContext,\n\t\tconfig: LayoutConfig,\n\t): { bounds: { min: number; max: number }; session: LayoutFrameSession } {\n\t\tthis.ensurePrefixSums();\n\n\t\tconst metrics = this.resolveLayoutMetrics(ctx, config);\n\n\t\tconst session: LayoutFrameSession = {\n\t\t\t...metrics,\n\t\t\tcontainerHeight: ctx.containerHeight,\n\t\t\talignPosition: config.alignPosition,\n\t\t\toverscanPx: config.overscanPx,\n\t\t\tbottomLineHeight: ctx.bottomLineHeight,\n\t\t};\n\n\t\tif (!metrics.isValid) {\n\t\t\treturn { bounds: { min: 0, max: 0 }, session };\n\t\t}\n\n\t\tconst {\n\t\t\tfocalTopY,\n\t\t\tanchorOffset,\n\t\t\tinterludeTotalHeight,\n\t\t\tactiveInterludeAnchor,\n\t\t} = metrics;\n\n\t\tconst minOffset = Math.min(0, -focalTopY);\n\n\t\tconst basePosWithoutScroll =\n\t\t\t-focalTopY + ctx.containerHeight * config.alignPosition - anchorOffset;\n\n\t\tlet totalContentHeight = this.totalLyricHeight;\n\t\tif (activeInterludeAnchor !== undefined) {\n\t\t\ttotalContentHeight += interludeTotalHeight;\n\t\t}\n\n\t\tconst rawMaxOffset =\n\t\t\tbasePosWithoutScroll + totalContentHeight - ctx.containerHeight / 2;\n\t\tconst maxOffset = Math.max(0, rawMaxOffset);\n\n\t\treturn { bounds: { min: minOffset, max: maxOffset }, session };\n\t}\n\n\t/**\n\t * 基于已钳制的 `scrollOffset` 和第一阶段的 {@link LayoutFrameSession} 提交排版并生成指令\n\t *\n\t * @param session 由 {@link beginFrame} 生成的单帧排版会话\n\t * @param scrollOffset 经过边界钳制后的安全滚动偏移量\n\t *\n\t * @returns 复用的排版结果实例 {@link LayoutResult}\n\t */\n\tpublic commit(\n\t\tsession: LayoutFrameSession,\n\t\tscrollOffset: number,\n\t): LayoutResult {\n\t\tthis.ensurePrefixSums();\n\n\t\tif (!session.isValid) {\n\t\t\treturn this.resetLayoutResult();\n\t\t}\n\n\t\tthis.layoutResult.lineCount = this.lyricCount;\n\n\t\tconst {\n\t\t\tfocalTopY,\n\t\t\tanchorOffset,\n\t\t\tinterludeTotalHeight,\n\t\t\tactiveInterludeAnchor,\n\t\t\tcontainerHeight,\n\t\t\talignPosition,\n\t\t\toverscanPx,\n\t\t\tbottomLineHeight,\n\t\t} = session;\n\n\t\tconst viewportStartY =\n\t\t\tcontainerHeight * alignPosition - anchorOffset - scrollOffset - focalTopY;\n\n\t\tconst motionBuffer = containerHeight * 0.4;\n\t\tconst viewportTopBound = -overscanPx - motionBuffer;\n\t\tconst viewportBottomBound = containerHeight + overscanPx + motionBuffer;\n\n\t\tfor (let i = 0; i < this.lyricCount; i++) {\n\t\t\tconst instruction = this.instructionPool[i];\n\t\t\tlet lineY = viewportStartY + this.prefixSums[i];\n\t\t\tconst lineH = this.prefixSums[i + 1] - this.prefixSums[i];\n\n\t\t\tif (activeInterludeAnchor !== undefined && i > activeInterludeAnchor) {\n\t\t\t\tlineY += interludeTotalHeight;\n\t\t\t}\n\n\t\t\tinstruction.y = lineY;\n\t\t\tinstruction.height = lineH;\n\t\t\tinstruction.isInViewport =\n\t\t\t\tlineY <= viewportBottomBound && lineY + lineH >= viewportTopBound;\n\t\t}\n\n\t\tif (activeInterludeAnchor !== undefined) {\n\t\t\tthis.layoutResult.hasInterlude = true;\n\t\t\tthis.layoutResult.interludeY =\n\t\t\t\tviewportStartY + this.prefixSums[activeInterludeAnchor + 1];\n\t\t} else {\n\t\t\tthis.layoutResult.hasInterlude = false;\n\t\t\tthis.layoutResult.interludeY = 0;\n\t\t}\n\n\t\tlet bottomY = viewportStartY + this.totalLyricHeight;\n\t\tif (activeInterludeAnchor !== undefined) {\n\t\t\tbottomY += interludeTotalHeight;\n\t\t}\n\n\t\tthis.layoutResult.bottomLineY = bottomY;\n\t\tthis.layoutResult.isBottomLineInViewport =\n\t\t\tbottomY <= viewportBottomBound &&\n\t\t\tbottomY + bottomLineHeight >= viewportTopBound;\n\n\t\treturn this.layoutResult;\n\t}\n\t//#endregion\n\n\t//#region 工具方法\n\t/**\n\t * 解析当前排版帧所对应的间奏点挂载锚点行索引\n\t *\n\t * @param interlude 当前时间线处于激活状态的间奏点信息\n\t * @param focalTarget 当前帧对齐的物理焦点\n\t */\n\tpublic static resolveInterludeAnchorIndex(\n\t\tinterlude: { anchorLineIndex: number } | undefined,\n\t\tfocalTarget: FocalTarget,\n\t): number | undefined {\n\t\t// 若处于间奏时间段内,优先使用活跃间奏的锚点行\n\t\tif (interlude) {\n\t\t\treturn interlude.anchorLineIndex;\n\t\t}\n\n\t\t// 若用户正处于手势滑动中且焦点被冻结在间奏点,保持冻结焦点的锚点行\n\t\tif (focalTarget.type === \"interlude\") {\n\t\t\treturn focalTarget.anchorIndex;\n\t\t}\n\t\treturn undefined;\n\t}\n\n\t/**\n\t * 如果高度发生过改变,则重新计算前缀和\n\t */\n\tprivate ensurePrefixSums(): void {\n\t\tif (!this.isPrefixSumDirty) return;\n\n\t\tlet sum = 0;\n\t\tthis.prefixSums[0] = 0;\n\t\tfor (let i = 0; i < this.lyricCount; i++) {\n\t\t\tsum += this.heights[i];\n\t\t\tthis.prefixSums[i + 1] = sum;\n\t\t}\n\t\tthis.totalLyricHeight = sum;\n\t\tthis.isPrefixSumDirty = false;\n\t}\n\n\t/**\n\t * 公共的焦点度量与范围校验逻辑\n\t */\n\tprivate resolveLayoutMetrics(\n\t\tctx: LayoutFrameContext,\n\t\tconfig: LayoutConfig,\n\t): ResolvedLayoutMetrics {\n\t\tconst interludeTotalHeight = ctx.interlude?.totalHeight ?? 0;\n\t\tconst activeInterludeAnchor = ctx.interlude?.anchorIndex;\n\n\t\tthis.resolvedMetrics.interludeTotalHeight = interludeTotalHeight;\n\t\tthis.resolvedMetrics.activeInterludeAnchor = activeInterludeAnchor;\n\n\t\tif (\n\t\t\tthis.lyricCount === 0 ||\n\t\t\t(ctx.target.type === \"line\" &&\n\t\t\t\t(ctx.target.index < 0 || ctx.target.index >= this.lyricCount)) ||\n\t\t\t(ctx.target.type === \"interlude\" &&\n\t\t\t\t(ctx.target.anchorIndex < -1 ||\n\t\t\t\t\tctx.target.anchorIndex >= this.lyricCount - 1))\n\t\t) {\n\t\t\tthis.resolvedMetrics.isValid = false;\n\t\t\tthis.resolvedMetrics.focalTopY = 0;\n\t\t\tthis.resolvedMetrics.anchorOffset = 0;\n\t\t\treturn this.resolvedMetrics;\n\t\t}\n\n\t\tthis.updateFocalMetrics(\n\t\t\tctx.target,\n\t\t\tinterludeTotalHeight,\n\t\t\tactiveInterludeAnchor,\n\t\t\tctx.bottomLineHeight,\n\t\t\tconfig,\n\t\t);\n\n\t\tthis.resolvedMetrics.isValid = true;\n\t\treturn this.resolvedMetrics;\n\t}\n\n\t/**\n\t * 测量对齐目标的几何信息\n\t */\n\tprivate updateFocalMetrics(\n\t\ttarget: FocalTarget,\n\t\tinterludeTotalHeight: number,\n\t\tactiveInterludeAnchor: number | undefined,\n\t\tbottomLineHeight: number,\n\t\tconfig: LayoutConfig,\n\t): void {\n\t\tlet focalTopY = 0;\n\t\tlet targetHeight = 0;\n\n\t\tif (target.type === \"line\") {\n\t\t\tfocalTopY = this.prefixSums[target.index];\n\t\t\t// 如果这行歌词前面存在间奏点,那么这行歌词已经被间奏点往下推了,需要加上 interludeTotalHeight\n\t\t\tif (\n\t\t\t\tactiveInterludeAnchor !== undefined &&\n\t\t\t\ttarget.index > activeInterludeAnchor\n\t\t\t) {\n\t\t\t\tfocalTopY += interludeTotalHeight;\n\t\t\t}\n\t\t\ttargetHeight =\n\t\t\t\tthis.prefixSums[target.index + 1] - this.prefixSums[target.index];\n\t\t} else if (target.type === \"interlude\") {\n\t\t\tfocalTopY = this.prefixSums[target.anchorIndex + 1];\n\t\t\ttargetHeight = interludeTotalHeight;\n\t\t} else if (target.type === \"bottom\") {\n\t\t\tfocalTopY = this.totalLyricHeight;\n\t\t\tif (activeInterludeAnchor !== undefined) {\n\t\t\t\tfocalTopY += interludeTotalHeight;\n\t\t\t}\n\t\t\ttargetHeight = bottomLineHeight;\n\t\t}\n\n\t\tthis.resolvedMetrics.focalTopY = focalTopY;\n\t\tthis.resolvedMetrics.anchorOffset = this.calculateAnchorOffset(\n\t\t\tconfig.alignAnchor,\n\t\t\ttargetHeight,\n\t\t);\n\t}\n\n\t/**\n\t * 根据锚点与目标高度计算内部相对偏移\n\t */\n\tprivate calculateAnchorOffset(\n\t\talignAnchor: LayoutAlignAnchor,\n\t\ttargetHeight: number,\n\t): number {\n\t\tif (targetHeight <= 0) return 0;\n\n\t\tswitch (alignAnchor) {\n\t\t\tcase LayoutAlignAnchor.Top:\n\t\t\t\treturn 0;\n\t\t\tcase LayoutAlignAnchor.Center:\n\t\t\t\treturn targetHeight / 2;\n\t\t\tcase LayoutAlignAnchor.Bottom:\n\t\t\t\treturn targetHeight;\n\t\t}\n\n\t\tconst exhaustiveCheck: never = alignAnchor;\n\t\treturn exhaustiveCheck;\n\t}\n\n\t/**\n\t * 重置排版结果为安全干净的状态(全部不可见/无底栏)\n\t */\n\tprivate resetLayoutResult(): LayoutResult {\n\t\tthis.layoutResult.lineCount = 0;\n\t\tthis.layoutResult.hasInterlude = false;\n\t\tthis.layoutResult.interludeY = 0;\n\t\tthis.layoutResult.bottomLineY = 0;\n\t\tthis.layoutResult.isBottomLineInViewport = false;\n\n\t\tfor (let i = 0; i < this.instructionPool.length; i++) {\n\t\t\tthis.instructionPool[i].isInViewport = false;\n\t\t\tthis.instructionPool[i].y = 0;\n\t\t\tthis.instructionPool[i].height = 0;\n\t\t}\n\n\t\treturn this.layoutResult;\n\t}\n\t//#endregion\n}\n","import type { LyricLine } from \"../interfaces.ts\";\n\nfunction formatValue(value: unknown): string {\n\treturn typeof value === \"string\" ? JSON.stringify(value) : String(value);\n}\n\nfunction assertTimestamp(\n\tvalue: unknown,\n\tpath: string,\n): asserts value is number {\n\tif (typeof value !== \"number\" || !Number.isFinite(value) || value < 0) {\n\t\tthrow new TypeError(\n\t\t\t`Invalid lyric timestamp at ${path}: ${formatValue(value)}`,\n\t\t);\n\t}\n}\n\nfunction assertTimestampRange(\n\tvalue: { startTime: unknown; endTime: unknown },\n\tpath: string,\n): void {\n\tconst startTime = value.startTime;\n\tconst endTime = value.endTime;\n\tassertTimestamp(startTime, `${path}.startTime`);\n\tassertTimestamp(endTime, `${path}.endTime`);\n\n\tif (startTime > endTime) {\n\t\tthrow new RangeError(\n\t\t\t`Invalid lyric timestamp range at ${path}: startTime ${startTime} is greater than endTime ${endTime}`,\n\t\t);\n\t}\n}\n\n/**\n * 验证歌词数据中的时间戳满足基本数值约束,例如非负、有限等\n */\nexport function assertValidLyricTimestamps(lines: readonly LyricLine[]): void {\n\tfor (let lineIndex = 0; lineIndex < lines.length; lineIndex++) {\n\t\tconst line = lines[lineIndex];\n\t\tconst linePath = `lines[${lineIndex}]`;\n\t\tassertTimestampRange(line, linePath);\n\n\t\tfor (let wordIndex = 0; wordIndex < line.words.length; wordIndex++) {\n\t\t\tconst word = line.words[wordIndex];\n\t\t\tconst wordPath = `${linePath}.words[${wordIndex}]`;\n\t\t\tassertTimestampRange(word, wordPath);\n\n\t\t\tif (word.ruby) {\n\t\t\t\tfor (let rubyIndex = 0; rubyIndex < word.ruby.length; rubyIndex++) {\n\t\t\t\t\tassertTimestampRange(\n\t\t\t\t\t\tword.ruby[rubyIndex],\n\t\t\t\t\t\t`${wordPath}.ruby[${rubyIndex}]`,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n","import structuredClone from \"@ungap/structured-clone\";\nimport type { LyricLine, LyricWord, OptimizeLyricOptions } from \"#interfaces\";\nimport { optimizeLyricLines } from \"#utils/optimize-lyric.ts\";\nimport { assertValidLyricTimestamps } from \"#utils/validate-lyric.ts\";\nimport { MaskObsceneWordsMode } from \"./consts.ts\";\n\n/**\n * 所有歌词行数据的配置选项,包括歌词行优化和掩码选项\n */\nexport interface LyricDataConfig {\n\toptimizeOptions?: OptimizeLyricOptions;\n\tmaskMode?: MaskObsceneWordsMode;\n\tmaskChar?: string;\n}\n\n/**\n * 歌词数据管理器\n *\n * 负责:\n * 1. 存储原始歌词、进行深拷贝、应用歌词优化、应用歌词掩码\n * 2. 计算是否为动态歌词 (逐字歌词) 和是否有对唱歌词\n */\nexport class LyricDataManager {\n\t/**\n\t * 原始的歌词行数组\n\t */\n\tprivate rawLines: LyricLine[] = [];\n\t/**\n\t * 经过处理后的歌词行数组\n\t */\n\tprivate processedLines: LyricLine[] = [];\n\n\t/**\n\t * 当前处理好的 processedLines 是否已经失效\n\t */\n\tprivate isDirty = true;\n\n\tprivate optimizeOpts: OptimizeLyricOptions = {};\n\tprivate maskMode: MaskObsceneWordsMode = MaskObsceneWordsMode.Disabled;\n\tprivate maskChar = \"*\";\n\n\tprivate isNonDynamic = false;\n\tprivate hasDuetLine = false;\n\n\tpublic setOriginalLines(lines: LyricLine[]): void {\n\t\tassertValidLyricTimestamps(lines);\n\t\tthis.rawLines = structuredClone(lines);\n\t\tthis.isDirty = true;\n\t}\n\n\tpublic setConfig(config: LyricDataConfig): void {\n\t\tif (config.optimizeOptions) {\n\t\t\tthis.optimizeOpts = { ...this.optimizeOpts, ...config.optimizeOptions };\n\t\t}\n\n\t\tthis.maskMode = config.maskMode ?? this.maskMode;\n\t\tthis.maskChar = config.maskChar?.charAt(0) ?? this.maskChar;\n\n\t\tthis.isDirty = true;\n\t}\n\n\t/**\n\t * 获取用户设置的原始歌词行数组,未经过优化和掩码\n\t * @returns 原始歌词行数组\n\t */\n\tpublic getRawLines(): ReadonlyArray<LyricLine> {\n\t\treturn this.rawLines;\n\t}\n\t/**\n\t * 获取对原始歌词行数组处理过的的歌词行数组\n\t * @returns 经过处理的歌词行数组\n\t */\n\tpublic getProcessedLines(): ReadonlyArray<LyricLine> {\n\t\tthis.ensurePipeline();\n\t\treturn this.processedLines;\n\t}\n\t/**\n\t * 歌词是否为非动态歌词,又称为逐行歌词\n\t */\n\tpublic getIsNonDynamic(): boolean {\n\t\tthis.ensurePipeline();\n\t\treturn this.isNonDynamic;\n\t}\n\t/**\n\t * 歌词是否包含对唱歌词\n\t */\n\tpublic getHasDuetLine(): boolean {\n\t\tthis.ensurePipeline();\n\t\treturn this.hasDuetLine;\n\t}\n\n\tpublic getOptimizeOptions(): OptimizeLyricOptions {\n\t\treturn this.optimizeOpts;\n\t}\n\tpublic getMaskMode(): MaskObsceneWordsMode {\n\t\treturn this.maskMode;\n\t}\n\tpublic getMaskChar(): string {\n\t\treturn this.maskChar;\n\t}\n\n\tprivate ensurePipeline(): void {\n\t\tif (!this.isDirty) return;\n\t\tthis.processPipeline();\n\t\tthis.isDirty = false;\n\t}\n\n\tprivate processPipeline(): void {\n\t\tthis.processedLines = structuredClone(this.rawLines);\n\n\t\toptimizeLyricLines(this.processedLines, this.optimizeOpts);\n\n\t\tlet checkNonDynamic = true;\n\t\tlet checkDuet = false;\n\n\t\tfor (const line of this.processedLines) {\n\t\t\tif (line.words.length > 1) checkNonDynamic = false;\n\t\t\tif (line.isDuet) checkDuet = true;\n\n\t\t\tfor (const word of line.words) {\n\t\t\t\tthis.applyMask(word);\n\t\t\t}\n\t\t}\n\n\t\tthis.isNonDynamic = checkNonDynamic && this.processedLines.length > 0;\n\t\tthis.hasDuetLine = checkDuet;\n\t}\n\n\tprivate applyMask(word: LyricWord): void {\n\t\tif (!word.obscene || this.maskMode === MaskObsceneWordsMode.Disabled) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst text = word.word;\n\t\tconst maskChar = this.maskChar;\n\n\t\t// 出于以下考虑,我们未替换对应不雅词的 ruby 和逐字音译为掩码:\n\t\t// 1. 注音大部分情况下不会直接包含原不雅词,除非逐字音译和音节相同\n\t\t// 2. 逐行音译无法对其中的不雅词进行掩码,我们保持一致的行为,即所有注音都不掩码\n\t\t//\n\t\t// 同时,我们在渲染之前进行了掩码处理,出于以下考虑:\n\t\t// 1. 掩码后的字形会发生变化,如果在渲染时才进行掩码,可能会导致视觉宽度和实际渲染宽度错位\n\t\t// 2. 如果这个音节被掩码了,那么它就不应该应用掩码前字形的效果,例如 DOM 实现中的强调效果\n\t\tif (this.maskMode === MaskObsceneWordsMode.FullMask) {\n\t\t\tword.word = text.replace(/\\S/g, maskChar);\n\t\t} else if (this.maskMode === MaskObsceneWordsMode.PartialMask) {\n\t\t\tconst trimmed = text.trim();\n\t\t\tif (trimmed.length <= 2) {\n\t\t\t\tword.word = text.replace(/\\S/g, maskChar);\n\t\t\t} else {\n\t\t\t\tconst startPos = text.indexOf(trimmed);\n\t\t\t\tconst endPos = startPos + trimmed.length - 1;\n\t\t\t\tword.word =\n\t\t\t\t\ttext.slice(0, startPos + 1) +\n\t\t\t\t\ttext.slice(startPos + 1, endPos).replace(/\\S/g, maskChar) +\n\t\t\t\t\ttext.slice(endPos);\n\t\t\t}\n\t\t}\n\t}\n}\n","import { Duration } from \"#utils/time.ts\";\n\nexport type ScrollInputType = \"touch\" | \"wheel\";\n\nexport interface ScrollEngineHooks {\n\t/**\n\t * 当滚动偏移量发生变化时高频触发\n\t *\n\t * @param isContinuous 当前是否为连续输入 (触摸或惯性 RAF)\n\t *\n\t * 一般的使用场景为:\n\t * * 若是连续输入,上层应绕过弹簧动画效果直接照着偏移量重新布局;\n\t * * 若是低频离散步进 (如滚轮),则上层应保留弹簧效果以便在离散步进之间展示平滑的动画\n\t */\n\tonScrollUpdate: (isContinuous: boolean) => void;\n\n\t/**\n\t * 用户明确产生滑动意图 (手指触摸超过 10px) 或使用滚轮时触发\n\t *\n\t * 一般在此暂停模糊效果、暂停自动跟随等\n\t */\n\tonInteractionStart: (type: ScrollInputType) => void;\n}\n\n/** 滚动静止后允许在歌词焦点切换时恢复自动对齐的等待时间 */\nconst AUTO_ALIGN_RESUME_DELAY_MS = 500;\n\n/** 滚轮交互结束防抖时间(150毫秒) */\nconst WHEEL_IDLE_TIMEOUT_MS = 150;\n\n/** 惯性动画基准物理帧时间 */\nconst BASE_FRAME_DURATION = Duration.fromMillis(1000 / 60);\n\n/** 惯性单帧最大跨度阈值,超过 100ms 视为掉帧或切换页面丢弃当前步进 */\nconst MAX_INERTIA_FRAME_DELTA_MS = 100;\n\nexport class ScrollInteractionEngine {\n\tprivate offset: number = 0;\n\n\tprivate minOffset: number = 0;\n\tprivate maxOffset: number = 0;\n\n\tprivate touchState = {\n\t\tstartY: 0,\n\t\tstartX: 0,\n\t\tlastY: 0,\n\t\tstartOffset: 0,\n\t\tspeed: 0,\n\t\tlastTimestamp: 0,\n\t\t/**\n\t\t * 是否已经突破 10px 意图阈值\n\t\t */\n\t\tisIntentConfirmed: false,\n\t};\n\n\t/**\n\t * 记录 Touch 开始时被打断的既有状态\n\t */\n\tprivate interruptedState = {\n\t\thadInertia: false,\n\t\thadTimer: false,\n\t\twasInteracting: false,\n\t};\n\n\tprivate inertiaRafId: number = 0;\n\tprivate scrollEndTime: number | undefined;\n\tprivate isInteracting: boolean = false;\n\tprivate wheelEndTimeoutId: number = 0;\n\n\tprivate abortController = new AbortController();\n\n\tconstructor(\n\t\tprivate container: HTMLElement,\n\t\tprivate hooks: ScrollEngineHooks,\n\t) {\n\t\tconst signal = this.abortController.signal;\n\n\t\tthis.container.addEventListener(\"touchstart\", this.onTouchStart, {\n\t\t\tpassive: false,\n\t\t\tsignal,\n\t\t});\n\t\tthis.container.addEventListener(\"touchmove\", this.onTouchMove, {\n\t\t\tpassive: false,\n\t\t\tsignal,\n\t\t});\n\t\tthis.container.addEventListener(\"touchend\", this.onTouchEnd, {\n\t\t\tpassive: false,\n\t\t\tsignal,\n\t\t});\n\t\tthis.container.addEventListener(\"touchcancel\", this.onTouchCancel, {\n\t\t\tpassive: false,\n\t\t\tsignal,\n\t\t});\n\t\tthis.container.addEventListener(\"wheel\", this.onWheel, {\n\t\t\tpassive: false,\n\t\t\tsignal,\n\t\t});\n\t}\n\n\t//#region 生命周期控制\n\tprivate startInteraction(type: ScrollInputType): void {\n\t\tthis.scrollEndTime = undefined;\n\t\tif (!this.isInteracting) {\n\t\t\tthis.isInteracting = true;\n\t\t\tthis.hooks.onInteractionStart(type);\n\t\t}\n\t}\n\n\tprivate endInteraction(): void {\n\t\tthis.isInteracting = false;\n\n\t\tthis.clearTimers();\n\n\t\tthis.scrollEndTime = performance.now();\n\t}\n\t//#endregion\n\n\t//#region 原生事件绑定\n\tprivate onTouchStart = (evt: TouchEvent) => {\n\t\t// 如果已经有手指在屏幕上,仅将基准点重锚定到最新的第一根手指,不重置交互状态\n\t\tif (evt.touches.length > 1) {\n\t\t\tconst touch = evt.touches[0];\n\t\t\tconst state = this.touchState;\n\t\t\tstate.startY = touch.screenY;\n\t\t\tstate.startX = touch.screenX;\n\t\t\tstate.lastY = touch.screenY;\n\t\t\tstate.startOffset = this.offset;\n\t\t\tstate.lastTimestamp = performance.now();\n\t\t\tstate.speed = 0;\n\t\t\treturn;\n\t\t}\n\n\t\tthis.interruptedState.hadInertia = this.inertiaRafId !== 0;\n\t\tthis.interruptedState.hadTimer = this.wheelEndTimeoutId !== 0;\n\t\tthis.interruptedState.wasInteracting = this.isInteracting;\n\n\t\tthis.clearTimers();\n\n\t\tconst touch = evt.touches[0];\n\t\tconst state = this.touchState;\n\n\t\tstate.startY = touch.screenY;\n\t\tstate.startX = touch.screenX;\n\t\tstate.lastY = touch.screenY;\n\t\tstate.startOffset = this.offset;\n\t\tstate.lastTimestamp = performance.now();\n\t\tstate.speed = 0;\n\t\tstate.isIntentConfirmed = false;\n\t};\n\n\tprivate onTouchMove = (evt: TouchEvent) => {\n\t\tconst touch = evt.touches[0];\n\t\tconst state = this.touchState;\n\n\t\tconst deltaY = touch.screenY - state.startY;\n\t\tconst deltaX = touch.screenX - state.startX;\n\n\t\tif (!state.isIntentConfirmed) {\n\t\t\t// 手指移动超过 10px,认为是滑动\n\t\t\tif (Math.abs(deltaY) > 10 || Math.abs(deltaX) > 10) {\n\t\t\t\tstate.isIntentConfirmed = true;\n\t\t\t\tthis.startInteraction(\"touch\");\n\t\t\t} else {\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\n\t\tif (evt.cancelable) {\n\t\t\tevt.preventDefault();\n\t\t}\n\n\t\tconst currentY = touch.screenY;\n\t\tthis.offset = this.clampOffset(\n\t\t\tstate.startOffset - (currentY - state.startY),\n\t\t);\n\n\t\tconst now = performance.now();\n\t\tconst dt = Duration.fromMillis(now - state.lastTimestamp);\n\t\tconst dtMs = Duration.asMillis(dt);\n\t\tif (dtMs > 0) {\n\t\t\tstate.speed = (currentY - state.lastY) / dtMs;\n\t\t}\n\n\t\tstate.lastY = currentY;\n\t\tstate.lastTimestamp = now;\n\n\t\tthis.hooks.onScrollUpdate(true);\n\t};\n\n\tprivate onTouchCancel = (_evt: TouchEvent) => {\n\t\tconst state = this.touchState;\n\n\t\tif (!state.isIntentConfirmed) {\n\t\t\tconst { hadInertia, hadTimer, wasInteracting } = this.interruptedState;\n\n\t\t\tif (hadInertia || hadTimer || wasInteracting) {\n\t\t\t\tthis.endInteraction();\n\t\t\t}\n\n\t\t\treturn;\n\t\t}\n\n\t\tstate.speed = 0;\n\t\tstate.startY = 0;\n\n\t\tthis.endInteraction();\n\t};\n\n\tprivate onTouchEnd = (evt: TouchEvent) => {\n\t\tconst state = this.touchState;\n\n\t\t// 如果屏幕上还有其他手指(例如抬起了双指中的第一根),将基准点重锚定到剩余的手指,\n\t\t// 让用户可以用剩下的手指继续平滑拖拽,暂不触发惯性动画\n\t\tif (evt.touches.length > 0) {\n\t\t\tconst remainingTouch = evt.touches[0];\n\t\t\tstate.startY = remainingTouch.screenY;\n\t\t\tstate.startX = remainingTouch.screenX;\n\t\t\tstate.lastY = remainingTouch.screenY;\n\t\t\tstate.startOffset = this.offset;\n\t\t\tstate.lastTimestamp = performance.now();\n\t\t\tstate.speed = 0;\n\t\t\treturn;\n\t\t}\n\n\t\tif (!state.isIntentConfirmed) {\n\t\t\tconst { hadInertia, hadTimer, wasInteracting } = this.interruptedState;\n\n\t\t\tif (hadInertia || hadTimer || wasInteracting) {\n\t\t\t\tthis.endInteraction();\n\t\t\t}\n\n\t\t\treturn;\n\t\t}\n\n\t\tstate.isIntentConfirmed = false;\n\n\t\tif (evt.cancelable) {\n\t\t\tevt.preventDefault();\n\t\t}\n\t\tstate.startY = 0;\n\n\t\tif (this.inertiaRafId) {\n\t\t\tcancelAnimationFrame(this.inertiaRafId);\n\t\t\tthis.inertiaRafId = 0;\n\t\t}\n\n\t\tif (Math.abs(state.speed) < 0.1) {\n\t\t\tstate.speed = 0;\n\t\t}\n\n\t\tif (Math.abs(state.speed) > 0.05) {\n\t\t\tlet lastFrameTime = performance.now();\n\n\t\t\tconst onScrollFrame = (time: number) => {\n\t\t\t\tconst dt = Duration.fromMillis(time - lastFrameTime);\n\t\t\t\tlastFrameTime = time;\n\t\t\t\tconst dtMs = Duration.asMillis(dt);\n\n\t\t\t\tif (dtMs <= 0 || dtMs > MAX_INERTIA_FRAME_DELTA_MS) {\n\t\t\t\t\tthis.inertiaRafId = requestAnimationFrame(onScrollFrame);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tif (Math.abs(state.speed) > 0.05) {\n\t\t\t\t\tthis.offset -= state.speed * dtMs;\n\t\t\t\t\tthis.offset = this.clampOffset(this.offset);\n\n\t\t\t\t\tconst steps = Duration.divDuration(dt, BASE_FRAME_DURATION);\n\t\t\t\t\tstate.speed *= 0.95 ** steps;\n\n\t\t\t\t\tthis.hooks.onScrollUpdate(true);\n\t\t\t\t\tthis.inertiaRafId = requestAnimationFrame(onScrollFrame);\n\t\t\t\t} else {\n\t\t\t\t\tthis.inertiaRafId = 0;\n\t\t\t\t\tthis.endInteraction();\n\t\t\t\t}\n\t\t\t};\n\n\t\t\tthis.inertiaRafId = requestAnimationFrame(onScrollFrame);\n\t\t} else {\n\t\t\tthis.endInteraction();\n\t\t}\n\t};\n\n\tprivate onWheel = (evt: WheelEvent) => {\n\t\tthis.clearTimers();\n\t\tthis.startInteraction(\"wheel\");\n\n\t\tif (evt.cancelable) {\n\t\t\tevt.preventDefault();\n\t\t}\n\n\t\tif (evt.deltaMode === WheelEvent.DOM_DELTA_PIXEL) {\n\t\t\tthis.offset += evt.deltaY;\n\t\t} else {\n\t\t\tthis.offset += evt.deltaY * 50;\n\t\t}\n\n\t\tthis.offset = this.clampOffset(this.offset);\n\t\tthis.hooks.onScrollUpdate(false);\n\n\t\tthis.wheelEndTimeoutId = window.setTimeout(() => {\n\t\t\tthis.wheelEndTimeoutId = 0;\n\t\t\tthis.endInteraction();\n\t\t}, WHEEL_IDLE_TIMEOUT_MS);\n\t};\n\t//#endregion\n\n\t//#region 工具\n\t/**\n\t * 将给定的偏移量限制在当前的 [minOffset, maxOffset] 边界内\n\t */\n\tprivate clampOffset(val: number): number {\n\t\tconst min = Math.min(this.minOffset, this.maxOffset);\n\t\tconst max = Math.max(this.minOffset, this.maxOffset);\n\t\treturn Math.min(Math.max(val, min), max);\n\t}\n\t//#endregion\n\n\t//#region 外部干预逻辑\n\t/**\n\t * 滚动结束是否已超过 {@link AUTO_ALIGN_RESUME_DELAY_MS}\n\t */\n\tpublic get canResumeAutoAlign(): boolean {\n\t\treturn (\n\t\t\tthis.scrollEndTime !== undefined &&\n\t\t\tperformance.now() - this.scrollEndTime >= AUTO_ALIGN_RESUME_DELAY_MS\n\t\t);\n\t}\n\n\t/**\n\t * 更新允许的滚动边界,并返回钳制后的实际 offset\n\t *\n\t * @description\n\t * 在歌词发生排版变化,如页面 `resize`、加载了新歌词、展开背景歌词、歌词行高度改变时,\n\t * 计算出当前视口内允许滚动的上限与下限,通过此方法传给滚动引擎以确保滚动不会越界\n\t */\n\tpublic updateBoundary(min: number, max: number): number {\n\t\tthis.minOffset = Math.min(0, min);\n\t\tthis.maxOffset = Math.max(0, max);\n\n\t\tthis.offset = this.clampOffset(this.offset);\n\t\treturn this.offset;\n\t}\n\n\t/**\n\t * 覆盖当前的滚动偏移量并终止正在进行的惯性动画或等待状态\n\t *\n\t * @description\n\t * 当需要清空全部用户手势带来的临时滚动状态时,例如,用户点击了某行歌词触发了\n\t * Seek、歌曲切歌、或者焦点切换时恢复自动对齐,调用此方法重置滚动引擎\n\t */\n\tpublic resetScroll(targetOffset: number = 0): void {\n\t\tthis.clearTimers();\n\t\tthis.scrollEndTime = undefined;\n\n\t\tthis.isInteracting = false;\n\t\tthis.touchState.isIntentConfirmed = false;\n\t\tthis.touchState.speed = 0;\n\t\tthis.touchState.startY = 0;\n\t\tthis.touchState.lastY = 0;\n\t\tthis.touchState.lastTimestamp = 0;\n\n\t\tthis.offset = this.clampOffset(targetOffset);\n\t}\n\t//#endregion\n\n\t//#region 清理\n\tprivate clearTimers(): void {\n\t\tif (this.inertiaRafId) {\n\t\t\tcancelAnimationFrame(this.inertiaRafId);\n\t\t\tthis.inertiaRafId = 0;\n\t\t}\n\t\tif (this.wheelEndTimeoutId) {\n\t\t\twindow.clearTimeout(this.wheelEndTimeoutId);\n\t\t\tthis.wheelEndTimeoutId = 0;\n\t\t}\n\t}\n\n\tpublic dispose(): void {\n\t\tthis.abortController.abort();\n\t\tthis.clearTimers();\n\t\tthis.scrollEndTime = undefined;\n\t}\n\t//#endregion\n}\n","import { Duration, MediaTime } from \"#utils/time.ts\";\n\n/**\n * 读取单调递增的物理时钟的函数,单位为毫秒\n *\n * 默认使用 `performance.now`\n */\nexport type WallClock = () => number;\n\n/**\n * 媒体时钟偏离期望推进量时的固定底限容差\n */\nconst JITTER_TOLERANCE = Duration.fromMillis(150);\n\n/**\n * 媒体时钟相对于物理时钟允许的动态漂移比例\n */\nconst DRIFT_SLACK = 0.5;\n\n/**\n * 单次判定所信任的最大物理时钟跨度\n */\nconst MAX_TRUSTED_GAP = Duration.fromMillis(800);\n\n/**\n * 跳转状态自动推导器\n *\n * 让下游使用者只推送播放进度、无需自己判断某次进度变化是否为跳转\n *\n * 判定的思路是把本次媒体时钟的推进量与当前播放状态下它应有的推进量比较,\n * 超出容差的偏离即视为跳转。判定规则为:\n * - 进度倒退视为跳转\n * - 播放时应有的推进量是物理时钟的推进量,容差随之按比例放宽\n * - 暂停时应有的推进量是零,容差只留固定底限\n */\nexport class SeekDetector {\n\tprivate readonly now: WallClock;\n\n\tprivate lastMediaTime: MediaTime = MediaTime.ZERO;\n\tprivate lastWallTime = 0;\n\tprivate hasBaseline = false;\n\n\t/**\n\t * @param now 物理时钟读取函数,默认为 `performance.now`\n\t */\n\tpublic constructor(now: WallClock = () => performance.now()) {\n\t\tthis.now = now;\n\t}\n\n\t/**\n\t * 推导本次进度变化是否为跳转\n\t *\n\t * @param time 下游推送的当前播放进度\n\t * @param isPlaying 当前是否在播放,决定本次推送应有的推进量与容差\n\t * @returns 是否应当按跳转处理\n\t */\n\tpublic detect(time: MediaTime, isPlaying: boolean): boolean {\n\t\tconst wall = this.now();\n\n\t\t// 没有基线可比,无从推导,此时不视为跳转\n\t\t//\n\t\t// 需要强制对齐的场合(重新构建歌词、页面恢复等)由调用方显式传入跳转状态,\n\t\t// 无需在这里代为判断;在这里报告跳转会让恢复播放这类本质连续的场景被当作跳转\n\t\tif (!this.hasBaseline) {\n\t\t\tthis.rebase(time, wall);\n\t\t\tthis.hasBaseline = true;\n\t\t\treturn false;\n\t\t}\n\n\t\t// 进度倒退始终按跳转处理\n\t\tif (time < this.lastMediaTime) {\n\t\t\tthis.rebase(time, wall);\n\t\t\treturn true;\n\t\t}\n\n\t\tconst mediaDelta = MediaTime.since(time, this.lastMediaTime);\n\t\tconst elapsed = Duration.clampPositive(\n\t\t\tDuration.fromMillis(wall - this.lastWallTime),\n\t\t);\n\t\tconst wallDelta = Duration.min(elapsed, MAX_TRUSTED_GAP);\n\n\t\tthis.rebase(time, wall);\n\n\t\t// 暂停时进度本不该前进,因此应有的推进量是零,容差也只留固定底限,\n\t\t// 任何超过抖动幅度的前进都是跳转\n\t\t//\n\t\t// 播放时才以物理时钟应有的推进量为基准,并按其比例放宽容差,\n\t\t// 以容纳倍速播放与推送节奏的不均匀\n\t\tconst expected = isPlaying ? wallDelta : Duration.ZERO;\n\t\tconst tolerance = isPlaying\n\t\t\t? Duration.max(JITTER_TOLERANCE, Duration.mulF64(wallDelta, DRIFT_SLACK))\n\t\t\t: JITTER_TOLERANCE;\n\n\t\tconst drift = Duration.sub(mediaDelta, expected);\n\n\t\treturn drift > tolerance;\n\t}\n\n\tpublic reset(): void {\n\t\tthis.hasBaseline = false;\n\t\tthis.lastMediaTime = MediaTime.ZERO;\n\t\tthis.lastWallTime = 0;\n\t}\n\n\tprivate rebase(time: MediaTime, wall: number): void {\n\t\tthis.lastMediaTime = time;\n\t\tthis.lastWallTime = wall;\n\t}\n}\n","import type { SpringParams } from \"#utils/spring.ts\";\n\n// 缓慢模式参数,适用于 Seek 状态、间奏状态、首尾边界等场景\nconst SLOW_STIFFNESS = 90;\nconst SLOW_DAMPING = 15;\n\n// 中速模式参数,目前用于歌曲结束的场景,一般会在之后使用此参数切换到底栏\nconst MEDIUM_STIFFNESS = 140;\nconst MEDIUM_DAMPING = 22;\n\n// 正常播放时候的参数,会根据歌词行之间的间隔动态调整弹簧效果\nconst MIN_INTERVAL = 100;\nconst MAX_INTERVAL = 800;\nconst MIN_STIFFNESS = 170;\nconst MAX_STIFFNESS = 220;\nconst DAMPING_MULTIPLIER = 2.2;\nconst INTERVAL_EXPONENT = 0.2;\n\n/**\n * 获取歌词行纵向滚动的弹簧物理参数\n * @param isSeeking 当前是否是跳转状态\n * @param isInterludeActive 当前是否处于间奏动画状态\n * @param intervalMs 当前歌词行与上一行的时间差,若无法提供(如首尾行),传入 undefined\n * @param isEndOfSong 歌曲是否播放完毕\n * @returns 弹簧参数配置 {@link SpringParams}\n */\nexport function getPosYSpringPolicy(\n\tisSeeking: boolean,\n\tisInterludeActive: boolean,\n\tintervalMs?: number,\n\tisEndOfSong = false,\n): Partial<SpringParams> {\n\t// Seek 和间奏使用较为缓慢的弹簧参数\n\tif (isSeeking || isInterludeActive) {\n\t\treturn {\n\t\t\tstiffness: SLOW_STIFFNESS,\n\t\t\tdamping: SLOW_DAMPING,\n\t\t};\n\t}\n\n\t// 歌曲播放完毕时,使用中速参数\n\tif (isEndOfSong) {\n\t\treturn {\n\t\t\tstiffness: MEDIUM_STIFFNESS,\n\t\t\tdamping: MEDIUM_DAMPING,\n\t\t};\n\t}\n\n\t// 没有间隔,即处于第一句或最后一句,用慢速模式兜底\n\tif (intervalMs == null) {\n\t\treturn {\n\t\t\tstiffness: SLOW_STIFFNESS,\n\t\t\tdamping: SLOW_DAMPING,\n\t\t};\n\t}\n\n\t// 将间隔限制在一个合理的范围内\n\tconst clampedInterval = Math.min(\n\t\tMath.max(intervalMs, MIN_INTERVAL),\n\t\tMAX_INTERVAL,\n\t);\n\n\t// 反转时间差的位置以便计算映射比例\n\tlet ratio =\n\t\t1 - (clampedInterval - MIN_INTERVAL) / (MAX_INTERVAL - MIN_INTERVAL);\n\n\t// 开五次方根以便尽量保持较大的 ratio,偏向更快的速度\n\tratio = ratio ** INTERVAL_EXPONENT;\n\n\tconst targetStiffness =\n\t\tMIN_STIFFNESS + ratio * (MAX_STIFFNESS - MIN_STIFFNESS);\n\tconst targetDamping = Math.sqrt(targetStiffness) * DAMPING_MULTIPLIER;\n\n\treturn {\n\t\tstiffness: targetStiffness,\n\t\tdamping: targetDamping,\n\t};\n}\n","import { Duration, MediaTime } from \"#utils/time.ts\";\n\n/**\n * 判定为间奏所需的最小空隙时长\n */\nconst MIN_INTERLUDE_GAP = Duration.fromMillis(7000);\n\n//#region 类型定义\n/**\n * 用于进度计算的最小歌词数据\n */\nexport interface TimeBounds {\n\treadonly startTime: MediaTime;\n\treadonly endTime: MediaTime;\n}\n\n/**\n * 当前命中的间奏区间信息\n */\nexport interface PlayerInterlude {\n\t/**\n\t * 间奏开始时间,即此前全部歌词行中最晚的结束时间\n\t */\n\treadonly startTime: MediaTime;\n\n\t/**\n\t * 间奏结束时间,即间奏后第一行歌词的开始时间\n\t */\n\treadonly endTime: MediaTime;\n\n\t/**\n\t * 间奏点应插入的位置基准\n\t *\n\t * 即显示顺序上间奏前的最后一行歌词的索引,`-1` 表示第一句之前\n\t */\n\treadonly anchorLineIndex: number;\n}\n\n/**\n * 当前播放时间线状态的只读快照\n *\n * 用于给 UI 执行排版和计算各种歌词行的效果\n *\n * @remarks\n * 在获取快照后,必须在同一帧内消费完毕,切勿保留其引用,因为下一帧就会被原地覆写\n */\nexport interface TimelineSnapshot {\n\t/**\n\t * 当前时间推导所依据的绝对播放时间\n\t *\n\t * 一般用于提供给 UI 层在绘制/排版阶段作为基准时间\n\t *\n\t * 例如给 InterludeDotsBase 计算播放动画的当前时间戳\n\t */\n\treadonly currentTime: MediaTime;\n\n\t/**\n\t * 当前进度命中的、正在播放的歌词组\n\t */\n\treadonly playingGroups: ReadonlySet<number>;\n\n\t/**\n\t * 当前进度命中的、正在高亮的歌词组\n\t *\n\t * 高亮的歌词组可能会多于正在播放的,例如一行歌词唱完后不会自行熄灭,而是保持高亮直到下一行开始播放\n\t *\n\t * 因此多行重叠时先唱完的行会陪着后面的行一起亮,句间空隙内上一行也保持高亮以维持可读性\n\t */\n\treadonly highlightedGroups: ReadonlySet<number>;\n\n\t/**\n\t * 自动滚动应该对齐到哪一行歌词\n\t *\n\t * 取值始终落在 `[0, 歌词行数 - 1]` 内,没有歌词时为 `0`,因此可以直接用于索引\n\t *\n\t * @remarks\n\t * 仅在 {@link isFocusOnInterlude} 为 `false` 时有效\n\t *\n\t * 间奏期间此值仍然指向间奏前的那一组歌词,此时应当改为对齐 {@link activeInterlude} 的间奏点\n\t */\n\treadonly scrollToIndex: number;\n\n\t/**\n\t * 处于高亮状态的歌词行中,最靠后的一行\n\t *\n\t * 例如,如果当前有高亮行索引 `[1, 2, 3]`,则 `latestHighlightedIndex` 为 `3`\n\t *\n\t * 如果当前没有任何高亮行,被置为 undefined,如首行开始之前、间奏区间内、\n\t * 歌曲播放完毕、或已开始的行均为零时长的情况\n\t */\n\treadonly latestHighlightedIndex?: number;\n\n\t/**\n\t * 标识歌曲是否播放完毕,即当前时间已经越过全部歌词行中最晚的结束时间\n\t *\n\t * 此时所有高亮都已被清空,一般用于展示底栏\n\t */\n\treadonly isEndOfSong: boolean;\n\n\t/**\n\t * 当前命中的间奏区间数据\n\t */\n\treadonly activeInterlude?: PlayerInterlude;\n\n\t/**\n\t * 当前是否应当聚焦在间奏点上\n\t */\n\treadonly isFocusOnInterlude: boolean;\n}\n\n/**\n * 时间线增量变化\n *\n * 主要用于让 UI 层能够以 $O(1)$ 到 $O(K)$ 的开销知道当前这一帧相比上一帧改变了什么,\n * 而不需要去遍历或比对全量状态\n */\nexport interface TimelineDiff {\n\t/**\n\t * 当前帧是否有任何实质性的状态变更,如播放行更替、高亮行新增/移除、间奏状态切换、焦点切换,或发生了跳转\n\t *\n\t * UI 层接收到 diff 后,检查此标志即可直接跳过后续所有的布局计算\n\t */\n\treadonly hasChanged: boolean;\n\n\t/**\n\t * 标识本次同步的时间轴是否发生了跳转\n\t *\n\t * 在显式跳转 (`sync` 的 `forceSeek`) 或时间倒退时为 `true`\n\t *\n\t * 例如跳转时使用更缓慢的弹簧参数 (参见 `spring.ts`),\n\t * 以及在非触摸状态下重置滚动坐标系\n\t */\n\treadonly isTimeJumped: boolean;\n\n\t/**\n\t * 在当前时间进度下,最新被命中的、正在播放的歌词索引列表\n\t *\n\t * 用于通知 UI 哪些歌词行开始播放了\n\t */\n\treadonly addedPlaying: ReadonlyArray<number>;\n\n\t/**\n\t * 在当前时间进度下,刚刚脱离正在播放状态的歌词索引列表,\n\t * 即上一帧还在播放、但本帧已不再命中其 `[startTime, endTime)` 的歌词行\n\t *\n\t * 正常播放时是时间越过了 `endTime`,跳转时也可能是跳到了 `startTime` 之前\n\t *\n\t * 用于通知 UI 侧哪些歌词行已结束,后续可能会转入高亮行以保持高亮状态\n\t */\n\treadonly removedPlaying: ReadonlyArray<number>;\n\n\t/**\n\t * 在当前帧中,需要变成高亮行的歌词索引列表\n\t *\n\t * 一般用于 UI 遍历并启用歌词行\n\t */\n\treadonly addedHighlighted: ReadonlyArray<number>;\n\n\t/**\n\t * 在当前帧中,不再是高亮行的歌词行索引列表\n\t *\n\t * 一般用于 UI 遍历并停用歌词行\n\t */\n\treadonly removedHighlighted: ReadonlyArray<number>;\n\n\t/**\n\t * 标识间奏状态是否发生了切换\n\t *\n\t * 例如:刚刚进入间奏区间、刚刚离开间奏区间、或从一个间奏区间跳到了另一个间奏区间\n\t *\n\t * 用于通知 UI 是否需要重新计算间奏点的位置和动画\n\t */\n\treadonly isInterludeChanged: boolean;\n\n\t/**\n\t * 标识自动对齐的目标歌词行索引是否发生了变化\n\t *\n\t * 用于通知 UI 需要移动到新的歌词行\n\t */\n\treadonly isScrollToChanged: boolean;\n\n\t/**\n\t * 标识歌曲播放完毕状态是否发生了变化\n\t */\n\treadonly isEndOfSongChanged: boolean;\n}\n\n/**\n * 将只读接口转换为可变的实现结构\n */\ntype Mutable<T> = {\n\t-readonly [P in keyof T]: T[P];\n};\n//#endregion\n\nexport class TimelineController {\n\t//#region 内部状态\n\tprivate lyricBounds: readonly TimeBounds[] = [];\n\t/**\n\t * 全部歌词行中最晚的结束时间,用于判定歌曲是否播放完毕\n\t */\n\tprivate maxEndTime: MediaTime = MediaTime.ZERO;\n\n\t/**\n\t * 预先计算的间奏区域\n\t */\n\tprivate precalculatedInterludes: PlayerInterlude[] = [];\n\n\t/**\n\t * 保存上次顺序扫描停止的位置,用于避免每次都从头遍历所有歌词,提高性能\n\t */\n\tprivate playbackCursor = 0;\n\tprivate interludeCursor = 0;\n\n\tprivate playingGroupsSet: Set<number> = new Set();\n\tprivate highlightedGroupsSet: Set<number> = new Set();\n\n\tprivate nextPlayingSet: Set<number> = new Set();\n\tprivate nextHighlightedSet: Set<number> = new Set();\n\n\tprivate addedPlayingIds: number[] = [];\n\tprivate removedPlayingIds: number[] = [];\n\tprivate addedHighlightedIds: number[] = [];\n\tprivate removedHighlightedIds: number[] = [];\n\tprivate expiredHighlightedIds: number[] = [];\n\n\tprivate readonly snapshot: Mutable<TimelineSnapshot> = {\n\t\tcurrentTime: MediaTime.ZERO,\n\t\tplayingGroups: this.playingGroupsSet,\n\t\thighlightedGroups: this.highlightedGroupsSet,\n\t\tscrollToIndex: 0,\n\t\tlatestHighlightedIndex: undefined,\n\t\tisEndOfSong: false,\n\t\tactiveInterlude: undefined,\n\t\tisFocusOnInterlude: false,\n\t};\n\n\tprivate readonly diff: Mutable<TimelineDiff> = {\n\t\thasChanged: false,\n\t\tisTimeJumped: false,\n\t\taddedPlaying: this.addedPlayingIds,\n\t\tremovedPlaying: this.removedPlayingIds,\n\t\taddedHighlighted: this.addedHighlightedIds,\n\t\tremovedHighlighted: this.removedHighlightedIds,\n\t\tisInterludeChanged: false,\n\t\tisScrollToChanged: false,\n\t\tisEndOfSongChanged: false,\n\t};\n\t//#endregion\n\n\t//#region 外部 API\n\t/**\n\t * 提前设置好歌词的时间数据,内部会根据此数据来进行时间线推导,同时预计算间奏区间\n\t *\n\t * @param bounds 歌词行的时间边界,**必须按 `startTime` 升序排列**,不按 `startTime`\n\t * 排列可能会导致时间推导出现意外情况\n\t */\n\tpublic setTimeBounds(bounds: readonly TimeBounds[]): void {\n\t\tthis.lyricBounds = bounds;\n\t\tthis.precalculatedInterludes = this.calculateInterludes(bounds);\n\n\t\t// 歌词行按开始时间排序,末行的结束时间不一定是最大值\n\t\t// 例如末尾存在时间上被前一行包住的重叠行,因此单独预计算一次\n\t\tlet maxEnd = MediaTime.ZERO;\n\t\tfor (const bound of bounds) {\n\t\t\tmaxEnd = MediaTime.max(maxEnd, bound.endTime);\n\t\t}\n\t\tthis.maxEndTime = maxEnd;\n\n\t\tthis.reset();\n\t}\n\n\t/**\n\t * 获取当前播放时间线状态的只读快照\n\t *\n\t * 用于给 UI 执行排版和计算各种歌词行的效果\n\t *\n\t * @remarks 在获取快照后,必须在同一帧内消费完毕,切勿保留其引用,因为下一帧就会被原地覆写\n\t * @returns 时间线快照\n\t */\n\tpublic getSnapshot(): TimelineSnapshot {\n\t\treturn this.snapshot;\n\t}\n\n\t/**\n\t * 将播放进度推进到指定时间,并返回相对上一帧的增量变化\n\t *\n\t * @remarks\n\t * 歌词行的高亮生命周期为:\n\t * * 命中 `[startTime, endTime)` 时高亮\n\t * * 唱完后不会自行熄灭,而是继续保持高亮\n\t *\n\t * 直到出现下列任一情况:\n\t *\n\t * 1. 有新的歌词行开始播放,此时已唱完的行被一起熄灭\n\t * 2. 进入间奏区间,此时清空全部高亮并把焦点交给间奏点\n\t * 3. 歌曲播放完毕,此时清空全部高亮并设置 {@link TimelineSnapshot.isEndOfSong} 为 true\n\t * 4. 发生跳转,此时按跳转后的时间重新推导\n\t *\n\t * @param time 当前播放时间\n\t * @param forceSeek 这次时间变化是否由跳转触发\n\t * @returns 相对上一帧的增量变化\n\t */\n\tpublic sync(time: MediaTime, forceSeek = false): TimelineDiff {\n\t\tthis.addedPlayingIds.length = 0;\n\t\tthis.removedPlayingIds.length = 0;\n\t\tthis.addedHighlightedIds.length = 0;\n\t\tthis.removedHighlightedIds.length = 0;\n\n\t\tconst prevInterlude = this.snapshot.activeInterlude;\n\t\tconst prevFocusOnInterlude = this.snapshot.isFocusOnInterlude;\n\t\tconst prevScrollToIndex = this.snapshot.scrollToIndex;\n\t\tconst prevEndOfSong = this.snapshot.isEndOfSong;\n\n\t\t// 时间倒退时一律按跳转处理,因为 performPlayback 会保存上次扫描停止的位置,\n\t\t// 下次从该位置继续扫描以提高性能,若时间倒退,倒退到的行可能位于\n\t\t// 扫描位置之前,只能重新推导\n\t\tconst isTimeRetreating = time < this.snapshot.currentTime;\n\t\tconst isJump = forceSeek || isTimeRetreating;\n\n\t\t// 间奏命中情况需要先于歌词状态确定\n\t\t// Seek 时要按同样的规则决定是否保留已经唱完的行,需要提前知道结果\n\t\tconst activeInterlude = this.resolveActiveInterlude(time, isJump);\n\t\tthis.snapshot.activeInterlude = activeInterlude;\n\n\t\tconst isPastLastLine =\n\t\t\tthis.lyricBounds.length > 0 && time >= this.maxEndTime;\n\n\t\tif (isJump) {\n\t\t\tthis.performSeek(time, !!activeInterlude || isPastLastLine);\n\t\t} else {\n\t\t\tthis.performPlayback(time);\n\t\t}\n\n\t\t// 高亮行本身不会因为唱完而熄灭,这里处理两个需要清空的场景\n\t\t// 1. 进入间奏区间:间奏点接过焦点,不应该再有亮着的旧歌词\n\t\t// 2. 歌曲播放完毕:不会再有新歌词接续,需要主动熄灭并把焦点交给底栏\n\t\tif (activeInterlude && this.playingGroupsSet.size === 0) {\n\t\t\tthis.flushAllHighlighted();\n\t\t}\n\t\tif (isPastLastLine) {\n\t\t\tthis.flushAllHighlighted();\n\t\t}\n\n\t\tthis.updateInterludeFocus(activeInterlude);\n\n\t\tconst isInterludeChanged = prevInterlude !== activeInterlude;\n\t\tconst isFocusChanged =\n\t\t\tprevFocusOnInterlude !== this.snapshot.isFocusOnInterlude;\n\t\tconst isScrollToChanged = prevScrollToIndex !== this.snapshot.scrollToIndex;\n\t\tconst isEndOfSongChanged = isPastLastLine !== prevEndOfSong;\n\n\t\tconst hasChanged =\n\t\t\tisJump ||\n\t\t\tthis.addedPlayingIds.length > 0 ||\n\t\t\tthis.removedPlayingIds.length > 0 ||\n\t\t\tthis.addedHighlightedIds.length > 0 ||\n\t\t\tthis.removedHighlightedIds.length > 0 ||\n\t\t\tisInterludeChanged ||\n\t\t\tisFocusChanged ||\n\t\t\tisScrollToChanged ||\n\t\t\tisEndOfSongChanged;\n\n\t\tthis.snapshot.currentTime = time;\n\n\t\tif (this.highlightedGroupsSet.size > 0) {\n\t\t\tlet maxIndex = -1;\n\t\t\tfor (const id of this.highlightedGroupsSet) {\n\t\t\t\tif (id > maxIndex) maxIndex = id;\n\t\t\t}\n\t\t\tthis.snapshot.latestHighlightedIndex = maxIndex;\n\t\t} else {\n\t\t\tthis.snapshot.latestHighlightedIndex = undefined;\n\t\t}\n\n\t\tthis.snapshot.isEndOfSong = isPastLastLine;\n\n\t\tthis.diff.hasChanged = hasChanged;\n\t\tthis.diff.isTimeJumped = isJump;\n\t\tthis.diff.isInterludeChanged = isInterludeChanged;\n\t\tthis.diff.isScrollToChanged = isScrollToChanged;\n\t\tthis.diff.isEndOfSongChanged = isEndOfSongChanged;\n\n\t\treturn this.diff;\n\t}\n\t//#endregion\n\n\t//#region 时间线推导\n\t/**\n\t * 处理正常播放时的时间线推导\n\t */\n\tprivate performPlayback(time: MediaTime): void {\n\t\t// 我在这里定义了歌词的不同状态:\n\t\t// 播放行:只要当前时间落在 [startTime, endTime) 内,就是在播放行,播放行是高亮行的子集\n\t\t// 高亮行:UI 层真正看到的高亮状态\n\t\t//\n\t\t// 一行歌词播放完毕后会立刻退出播放状态,但会继续保持高亮,直到下一行开始播放才熄灭\n\t\t// 这样多行重叠时先唱完的行会陪着后面的行一起亮,句间空隙内上一行也不会提前变暗\n\t\t// 空隙长到构成间奏、以及歌曲已经播完这两种没有下一行接续的情况,由 sync 统一清空\n\n\t\t// 清理不再播放的行\n\t\tfor (const lastPlayingId of this.playingGroupsSet) {\n\t\t\tconst bound = this.lyricBounds[lastPlayingId];\n\t\t\tif (!bound || time < bound.startTime || bound.endTime <= time) {\n\t\t\t\tthis.playingGroupsSet.delete(lastPlayingId);\n\t\t\t\tthis.removedPlayingIds.push(lastPlayingId);\n\t\t\t}\n\t\t}\n\n\t\t// 顺序查找并激活新的播放中的行\n\t\t// 从 playbackCursor 开始往下找,跳过已经唱完的歌词,提高性能\n\t\tlet cursor = Math.max(0, this.playbackCursor);\n\t\tconst len = this.lyricBounds.length;\n\n\t\twhile (cursor < len) {\n\t\t\tconst bound = this.lyricBounds[cursor];\n\t\t\tif (bound.startTime > time) {\n\t\t\t\tbreak; // 已经排序过\n\t\t\t}\n\n\t\t\tif (\n\t\t\t\tbound.startTime <= time &&\n\t\t\t\tbound.endTime > time &&\n\t\t\t\t!this.playingGroupsSet.has(cursor)\n\t\t\t) {\n\t\t\t\tthis.playingGroupsSet.add(cursor);\n\t\t\t\tthis.addedPlayingIds.push(cursor);\n\t\t\t}\n\t\t\tcursor++;\n\t\t}\n\n\t\t// 更新 this.playbackCursor 指针\n\t\tthis.playbackCursor = cursor;\n\n\t\t// 找出那些已经唱完但仍处于高亮状态的歌词行\n\t\t// 它们会保持高亮,直到有新歌词开始播放才被一起熄灭\n\t\tthis.expiredHighlightedIds.length = 0;\n\t\tfor (const id of this.highlightedGroupsSet) {\n\t\t\tif (!this.playingGroupsSet.has(id)) {\n\t\t\t\tthis.expiredHighlightedIds.push(id);\n\t\t\t}\n\t\t}\n\n\t\tconst addedPlayingCount = this.addedPlayingIds.length;\n\t\tconst expiredCount = this.expiredHighlightedIds.length;\n\n\t\t// 只要有新歌词开始播放,将其存入 highlightedGroupsSet,并向 addedHighlightedIds 压入 Diff\n\t\t// UI 将会启用这些歌词\n\t\tfor (let i = 0; i < addedPlayingCount; i++) {\n\t\t\tconst id = this.addedPlayingIds[i];\n\t\t\tthis.highlightedGroupsSet.add(id);\n\t\t\tthis.addedHighlightedIds.push(id);\n\t\t}\n\n\t\t// 清理旧高亮的唯一条件是「有新歌词进入播放状态」\n\t\t//\n\t\t// 注意 expiredCount > 0 不作为清理条件,一行歌词唱完时若没有新行接续,\n\t\t// 它会继续保持高亮,这样多行高亮时先唱完的行和句间空隙的上一行不会失去可读性\n\t\tif (addedPlayingCount > 0) {\n\t\t\tfor (let i = 0; i < expiredCount; i++) {\n\t\t\t\tconst id = this.expiredHighlightedIds[i];\n\t\t\t\tthis.highlightedGroupsSet.delete(id);\n\t\t\t\tthis.removedHighlightedIds.push(id);\n\t\t\t}\n\n\t\t\tlet minHighlighted = Number.POSITIVE_INFINITY;\n\t\t\tfor (const id of this.highlightedGroupsSet) {\n\t\t\t\tif (id < minHighlighted) minHighlighted = id;\n\t\t\t}\n\n\t\t\t// 只在歌词更替时更新,以便在播放完毕后保持聚焦在这一组歌词\n\t\t\tthis.snapshot.scrollToIndex = minHighlighted;\n\t\t}\n\t}\n\n\t/**\n\t * 处理 Seek 时的时间线推导\n\t *\n\t * 直接按目标时间重建播放与高亮行集合,结果与正常播放到该时刻时一致\n\t *\n\t * @param time 跳转到的时间\n\t * @param dropLingeringWhenIdle 在没有任何行正在播放时,是否丢弃那些已经唱完、\n\t * 但在正常播放中仍会保持高亮的行,用于在间奏和播放完时清空高亮行\n\t */\n\tprivate performSeek(time: MediaTime, dropLingeringWhenIdle: boolean): void {\n\t\tconst nextPlaying = this.nextPlayingSet;\n\t\tconst nextHighlighted = this.nextHighlightedSet;\n\t\tnextPlaying.clear();\n\t\tnextHighlighted.clear();\n\n\t\t// 二分法找出第一个开始时间晚于目标时间的歌词行,排除所有尚未开始唱的歌词\n\t\tlet left = 0;\n\t\tlet right = this.lyricBounds.length - 1;\n\t\tlet firstGreater = this.lyricBounds.length;\n\n\t\twhile (left <= right) {\n\t\t\tconst mid = (left + right) >> 1;\n\t\t\tif (this.lyricBounds[mid].startTime > time) {\n\t\t\t\tfirstGreater = mid;\n\t\t\t\tright = mid - 1;\n\t\t\t} else {\n\t\t\t\tleft = mid + 1;\n\t\t\t}\n\t\t}\n\n\t\t// 往前找到最后一个真正开始播放过的歌词行作为锚点\n\t\tlet anchorIndex = -1;\n\t\tfor (let i = firstGreater - 1; i >= 0; i--) {\n\t\t\tconst bound = this.lyricBounds[i];\n\t\t\t// 有意跳过时长为 0 的歌词行\n\t\t\tif (bound.endTime > bound.startTime) {\n\t\t\t\tanchorIndex = i;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\tif (anchorIndex === -1) {\n\t\t\t// 目标时间在第一行歌词开始之前,或此前所有已开始的行都是零时长\n\t\t\t// 正常播放时尚未有任何歌词行进入播放状态,scrollToIndex 保持为 0\n\t\t\tthis.playbackCursor = firstGreater;\n\t\t\tthis.snapshot.scrollToIndex = 0;\n\t\t\tthis.commitSeekDiff();\n\t\t\treturn;\n\t\t}\n\n\t\t// 还原「歌词唱完不熄灭,直到下一句开始才更替」的状态\n\t\t// 锚点之后的歌词行要么开始时间晚于目标时间、要么时长为零,都不可能命中,无需遍历\n\t\tconst anchorStart = this.lyricBounds[anchorIndex].startTime;\n\t\tlet minPlaying = -1;\n\t\tlet minHighlighted = -1;\n\n\t\tfor (let i = anchorIndex; i >= 0; i--) {\n\t\t\tconst bound = this.lyricBounds[i];\n\n\t\t\t// 锚点时刻尚未唱完的行,在正常播放中会一直亮到下一行开始\n\t\t\t// 正在播放的行必然满足此条件,因为其结束时间晚于目标时间,而目标时间不早于锚点\n\t\t\tif (bound.endTime <= anchorStart) continue;\n\n\t\t\tif (bound.startTime <= time && bound.endTime > time) {\n\t\t\t\tnextPlaying.add(i);\n\t\t\t\tminPlaying = i;\n\t\t\t}\n\n\t\t\tnextHighlighted.add(i);\n\t\t\tminHighlighted = i;\n\t\t}\n\n\t\t// 间奏与曲末清空高亮行,如果没有行在播放的话\n\t\tif (dropLingeringWhenIdle && nextPlaying.size === 0) {\n\t\t\tnextHighlighted.clear();\n\t\t}\n\n\t\tthis.playbackCursor = minPlaying === -1 ? firstGreater : minPlaying;\n\t\tthis.snapshot.scrollToIndex = minHighlighted;\n\n\t\tthis.commitSeekDiff();\n\t}\n\n\t/**\n\t * 把 Seek 重建出的目标集合与上一帧的集合求对称差,输出发生变化的部分\n\t */\n\tprivate commitSeekDiff(): void {\n\t\tfor (const id of this.playingGroupsSet) {\n\t\t\tif (!this.nextPlayingSet.has(id)) {\n\t\t\t\tthis.playingGroupsSet.delete(id);\n\t\t\t\tthis.removedPlayingIds.push(id);\n\t\t\t}\n\t\t}\n\t\tfor (const id of this.nextPlayingSet) {\n\t\t\tif (!this.playingGroupsSet.has(id)) {\n\t\t\t\tthis.playingGroupsSet.add(id);\n\t\t\t\tthis.addedPlayingIds.push(id);\n\t\t\t}\n\t\t}\n\n\t\tfor (const id of this.highlightedGroupsSet) {\n\t\t\tif (!this.nextHighlightedSet.has(id)) {\n\t\t\t\tthis.highlightedGroupsSet.delete(id);\n\t\t\t\tthis.removedHighlightedIds.push(id);\n\t\t\t}\n\t\t}\n\t\tfor (const id of this.nextHighlightedSet) {\n\t\t\tif (!this.highlightedGroupsSet.has(id)) {\n\t\t\t\tthis.highlightedGroupsSet.add(id);\n\t\t\t\tthis.addedHighlightedIds.push(id);\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * 立即熄灭当前全部高亮歌词行\n\t *\n\t * 用于间奏与曲末这两个没有下一行接续、但必须清空高亮的场景\n\t */\n\tprivate flushAllHighlighted(): void {\n\t\tif (this.highlightedGroupsSet.size === 0) return;\n\n\t\tfor (const id of this.highlightedGroupsSet) {\n\t\t\tthis.removedHighlightedIds.push(id);\n\t\t}\n\t\tthis.highlightedGroupsSet.clear();\n\t}\n\t//#endregion\n\n\t//#region 间奏计算\n\t/**\n\t * 预计算全部间奏区间\n\t * @param bounds 按 `startTime` 升序排列的歌词时间边界\n\t * @returns 按时间升序排列、互不重叠的间奏区间,供二分查找与游标推进使用\n\t */\n\tprivate calculateInterludes(\n\t\tbounds: readonly TimeBounds[],\n\t): PlayerInterlude[] {\n\t\tconst interludes: PlayerInterlude[] = [];\n\n\t\t// 已扫描过的歌词行中最晚的结束时间\n\t\tlet maxEnd = MediaTime.ZERO;\n\n\t\t// 歌词行只保证按 `startTime` 升序,前一行的 `endTime` 并不等于此前\n\t\t// 所有行的最晚结束时间 (例如多行高亮的情况)\n\t\t//\n\t\t// 所以这里按前缀最大结束时间做一次区间并集扫描,保证产出的区间与\n\t\t// 任何歌词行都不重叠\n\t\tfor (let i = -1; i < bounds.length - 1; i++) {\n\t\t\tif (i >= 0) {\n\t\t\t\tmaxEnd = MediaTime.max(maxEnd, bounds[i].endTime);\n\t\t\t}\n\n\t\t\tconst gapEnd = MediaTime.max(maxEnd, bounds[i + 1].startTime);\n\n\t\t\tif (MediaTime.since(gapEnd, maxEnd) >= MIN_INTERLUDE_GAP) {\n\t\t\t\tinterludes.push({\n\t\t\t\t\tstartTime: maxEnd,\n\t\t\t\t\tendTime: gapEnd,\n\t\t\t\t\tanchorLineIndex: i,\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\n\t\treturn interludes;\n\t}\n\n\t/**\n\t * 查找当前时间命中的间奏区间,并顺带推进或重定位间奏游标\n\t * @param time 当前播放时间\n\t * @param isSeek 当前帧是否为跳转\n\t * @returns 命中的间奏区间,未命中时为 undefined\n\t */\n\tprivate resolveActiveInterlude(\n\t\ttime: MediaTime,\n\t\tisSeek: boolean,\n\t): PlayerInterlude | undefined {\n\t\tif (this.precalculatedInterludes.length === 0) return undefined;\n\n\t\tif (isSeek) {\n\t\t\tlet cursor = this.precalculatedInterludes.length;\n\t\t\tlet left = 0;\n\t\t\tlet right = this.precalculatedInterludes.length - 1;\n\n\t\t\twhile (left <= right) {\n\t\t\t\tconst mid = (left + right) >> 1;\n\t\t\t\tconst inter = this.precalculatedInterludes[mid];\n\n\t\t\t\tif (inter.endTime > time) {\n\t\t\t\t\tcursor = mid;\n\t\t\t\t\tright = mid - 1;\n\t\t\t\t} else {\n\t\t\t\t\tleft = mid + 1;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tthis.interludeCursor = cursor;\n\n\t\t\tif (cursor < this.precalculatedInterludes.length) {\n\t\t\t\tconst inter = this.precalculatedInterludes[cursor];\n\t\t\t\tif (time >= inter.startTime && time < inter.endTime) {\n\t\t\t\t\treturn inter;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn undefined;\n\t\t}\n\n\t\twhile (this.interludeCursor < this.precalculatedInterludes.length) {\n\t\t\tconst inter = this.precalculatedInterludes[this.interludeCursor];\n\t\t\tif (time >= inter.startTime && time < inter.endTime) {\n\t\t\t\treturn inter;\n\t\t\t}\n\t\t\tif (time >= inter.endTime) {\n\t\t\t\tthis.interludeCursor++;\n\t\t\t} else {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\treturn undefined;\n\t}\n\n\t/**\n\t * 根据间奏命中情况和当前高亮状态推导是否应当聚焦间奏点\n\t *\n\t * 处于间奏区域且没有任何歌词高亮时聚焦间奏点,否则交还给歌词行\n\t *\n\t * @param activeInterlude 当前命中的间奏区间\n\t */\n\tprivate updateInterludeFocus(activeInterlude?: PlayerInterlude): void {\n\t\tthis.snapshot.isFocusOnInterlude =\n\t\t\t!!activeInterlude && this.highlightedGroupsSet.size === 0;\n\t}\n\t//#endregion\n\n\t//#region 重置\n\t/**\n\t * 清空全部推导状态,回到时间原点\n\t */\n\tprivate reset(): void {\n\t\tthis.playbackCursor = 0;\n\t\tthis.interludeCursor = 0;\n\n\t\tthis.playingGroupsSet.clear();\n\t\tthis.highlightedGroupsSet.clear();\n\t\tthis.nextPlayingSet.clear();\n\t\tthis.nextHighlightedSet.clear();\n\n\t\tthis.snapshot.currentTime = MediaTime.ZERO;\n\t\tthis.snapshot.scrollToIndex = 0;\n\t\tthis.snapshot.latestHighlightedIndex = undefined;\n\t\tthis.snapshot.isEndOfSong = false;\n\t\tthis.snapshot.activeInterlude = undefined;\n\t\tthis.snapshot.isFocusOnInterlude = false;\n\t}\n\t//#endregion\n}\n","import type {\n\tDisposable,\n\tHasElement,\n\tLyricLine,\n\tOptimizeLyricOptions,\n} from \"#interfaces\";\nimport styles from \"#styles/lyric-player.module.css\";\nimport { clampPositive } from \"#utils/clamp.ts\";\nimport { areOptimizeOptionsEqual } from \"#utils/optimize-lyric.ts\";\nimport type { SpringParams } from \"#utils/spring.ts\";\nimport { Duration, MediaTime } from \"#utils/time.ts\";\nimport type { BottomLine } from \"./bottom-line.ts\";\nimport {\n\tLayoutAlignAnchor,\n\tLayoutReason,\n\tLayoutReasonStrategyMap,\n\tMAX_FRAME_DELTA,\n\ttype MaskObsceneWordsMode,\n} from \"./consts.ts\";\nimport { FocusController } from \"./focus.ts\";\nimport type { LyricLineGroupBase } from \"./group.ts\";\nimport type { InterludeDotsBase } from \"./interlude-dots.ts\";\nimport {\n\tLayoutCalculator,\n\ttype LayoutConfig,\n\ttype LayoutFrameContext,\n} from \"./layout.ts\";\nimport type { LyricLineBase } from \"./line.ts\";\nimport {\n\ttype LyricDataConfig,\n\tLyricDataManager,\n} from \"./lyric-data-manager.ts\";\nimport { type ScrollInputType, ScrollInteractionEngine } from \"./scroll.ts\";\nimport { SeekDetector } from \"./seek-detector.ts\";\nimport { getPosYSpringPolicy } from \"./spring\";\nimport { TimelineController, type TimelineSnapshot } from \"./timeline.ts\";\n\nexport type { BottomLine, BottomLineTransforms } from \"./bottom-line.ts\";\nexport type {\n\tInterludeDotsBase,\n\tInterludeDotsSnapshot,\n} from \"./interlude-dots.ts\";\nexport type { LyricLineBase } from \"./line.ts\";\nexport type { LyricDataConfig } from \"./lyric-data-manager.ts\";\n\nfunction getEntrySize(entry: ResizeObserverEntry): [number, number] {\n\tif (entry.borderBoxSize && entry.borderBoxSize.length > 0) {\n\t\tconst borderBox = entry.borderBoxSize[0];\n\t\treturn [borderBox.inlineSize, borderBox.blockSize];\n\t}\n\tconst el = entry.target as HTMLElement;\n\treturn [\n\t\tel.offsetWidth || entry.contentRect.width,\n\t\tel.offsetHeight || entry.contentRect.height,\n\t];\n}\n\n/**\n * 播放器布局状态。\n *\n * 记录当前视口动态测量得到的尺寸\n */\ninterface PlayerLayoutState {\n\t/** 间奏点元素当前测量得到的尺寸 */\n\tinterludeDotsSize: [number, number];\n}\n\n/**\n * 播放器滚动状态。\n *\n * 记录用户的滚动行为\n */\ninterface PlayerScrollState {\n\t/** 是否处于用户滚动过,尚未回归自动对齐的状态 */\n\tisAutoAlignSuspended: boolean;\n\tisTouchScrolled: boolean;\n}\n\n/**\n * 歌词播放器的基类,已经包含了有关歌词操作和排版的功能,\n * 子类需要为其实现对应的显示展示操作\n */\nexport abstract class LyricPlayerBase\n\textends EventTarget\n\timplements HasElement, Disposable\n{\n\tprotected element: HTMLElement = document.createElement(\"div\");\n\tabstract get baseFontSize(): number;\n\n\tprotected isPlaying = false;\n\tprotected timelineController: TimelineController = new TimelineController();\n\tprotected seekDetector: SeekDetector = new SeekDetector();\n\tprotected enableAutoSeekDetection = true;\n\n\tprivate hasBottomContent = false;\n\tprivate bottomLineObserver: MutationObserver;\n\n\t/** @internal */\n\tlyricGroupElementMap: WeakMap<Element, LyricLineGroupBase> = new WeakMap();\n\tprotected lyricLinesIndexes: WeakMap<LyricLineBase, number> = new WeakMap();\n\tprotected disableSpring = false;\n\n\tprotected dataManager: LyricDataManager = new LyricDataManager();\n\tprotected get processedLines(): ReadonlyArray<LyricLine> {\n\t\treturn this.dataManager.getProcessedLines();\n\t}\n\tprotected get isNonDynamic(): boolean {\n\t\treturn this.dataManager.getIsNonDynamic();\n\t}\n\tprotected get hasDuetLine(): boolean {\n\t\treturn this.dataManager.getHasDuetLine();\n\t}\n\n\tprotected layoutState: PlayerLayoutState = {\n\t\tinterludeDotsSize: [0, 0],\n\t};\n\tprotected layoutConfig: LayoutConfig = {\n\t\talignAnchor: LayoutAlignAnchor.Center,\n\t\talignPosition: 0.35,\n\t\toverscanPx: 300,\n\t};\n\t/** LayoutCalculator 所使用的排版上下文状态 */\n\tprivate frameContext: LayoutFrameContext = {\n\t\tcontainerHeight: 0,\n\t\tscrollOffset: 0,\n\t\ttarget: { index: 0, type: \"line\" },\n\t\tbottomLineHeight: 0,\n\t\tinterlude: undefined,\n\t};\n\t/**\n\t * 逐帧刷新的视觉推导派生值\n\t *\n\t * 存放会在逐行循环内被反复求值的量,避免逐行重算\n\t */\n\tprivate visualFrame = {\n\t\t/** 最靠后的高亮行,无高亮时回退到 `scrollToIndex` */\n\t\tlatestIndex: 0,\n\t\t/** 已播放行的分界,`hidePassedLines` 启用时此行之前的歌词被隐藏 */\n\t\tpassedBoundary: 0,\n\t\t/** 是否为窄视口,窄视口下模糊强度打折 */\n\t\tisNarrowViewport: false,\n\t};\n\tprotected interludeDots: InterludeDotsBase & HasElement;\n\tprotected bottomLine: BottomLine;\n\tprotected enableBlur = true;\n\tprotected enableScale = true;\n\tprotected hidePassedLines = false;\n\n\tprotected scrollEngine: ScrollInteractionEngine;\n\tprotected scrollState: PlayerScrollState = {\n\t\tisAutoAlignSuspended: false,\n\t\tisTouchScrolled: false,\n\t};\n\n\tprotected layoutCalculator: LayoutCalculator = new LayoutCalculator();\n\tprivate focusController: FocusController = new FocusController();\n\n\tpublic currentLyricGroups: LyricLineGroupBase[] = [];\n\tlyricGroupSize: WeakMap<LyricLineGroupBase, [number, number]> = new WeakMap();\n\treadonly size: [number, number] = [0, 0];\n\tprotected isPageVisible = true;\n\n\t/** 默认/回退单行歌词估算高度基准 (containerHeight / 5) */\n\tpublic get defaultLineHeight(): number {\n\t\treturn this.size[1] / 5;\n\t}\n\n\t/**\n\t * 获取指定索引歌词行的高度\n\t * @remarks 可能为测量值或估算值\n\t */\n\tpublic getLineHeight(index: number): number {\n\t\treturn this.layoutCalculator.getLineHeight(index);\n\t}\n\n\t/** 是否强制让背景人声行始终后置(即始终在主歌词下方显示,不前置背景人声) */\n\tprotected alwaysPostpositionBackground = false;\n\n\tprotected posXSpringParams: Partial<SpringParams> = {\n\t\tmass: 1,\n\t\tdamping: 10,\n\t\tstiffness: 100,\n\t};\n\tprotected posYSpringParams: Partial<SpringParams> = {\n\t\tmass: 0.9,\n\t\tdamping: 15,\n\t\tstiffness: 90,\n\t};\n\tprotected scaleSpringParams: Partial<SpringParams> = {\n\t\tmass: 2,\n\t\tdamping: 25,\n\t\tstiffness: 100,\n\t};\n\tprotected scaleForBGSpringParams: Partial<SpringParams> = {\n\t\tmass: 1,\n\t\tdamping: 20,\n\t\tstiffness: 50,\n\t};\n\tprivate lyricGroupIndexMap = new WeakMap<LyricLineGroupBase, number>();\n\tprivate onPageShow = () => {\n\t\tthis.isPageVisible = true;\n\t\tthis.setCurrentTime(this.getCurrentTime(), true);\n\t};\n\tprivate onPageHide = () => {\n\t\tthis.isPageVisible = false;\n\t};\n\tprivate onVisibilityChange = () => {\n\t\tif (document.visibilityState !== \"visible\") return;\n\t\t// 标签页挂起期间音频可能仍在持续播放,恢复首帧的推送间隔会远超\n\t\t// SeekDetector 信任的物理时钟跨度(MAX_TRUSTED_GAP),被误判为跳转\n\t\t// 所以丢弃基线让恢复后的首次推送重新建立基线,按连续播放推导\n\t\tthis.seekDetector.reset();\n\t};\n\t/** @internal */\n\tresizeObserver: ResizeObserver = new ResizeObserver(((entries) => {\n\t\tlet shouldRelayout = false;\n\t\tlet shouldRebuildPlayerStyle = false;\n\t\tlet shouldUpdateFallback = false;\n\n\t\tfor (const entry of entries) {\n\t\t\tif (entry.target === this.element) {\n\t\t\t\tconst rect = entry.contentRect;\n\t\t\t\tthis.size[0] = rect.width;\n\t\t\t\tthis.size[1] = rect.height;\n\t\t\t\tshouldRebuildPlayerStyle = true;\n\t\t\t\tshouldUpdateFallback = true;\n\t\t\t} else if (entry.target === this.interludeDots.getElement()) {\n\t\t\t\tconst size = getEntrySize(entry);\n\t\t\t\tthis.layoutState.interludeDotsSize[0] = size[0];\n\t\t\t\tthis.layoutState.interludeDotsSize[1] = size[1];\n\t\t\t\tshouldRelayout = true;\n\t\t\t} else if (entry.target === this.bottomLine.getElement()) {\n\t\t\t\tconst newSize = getEntrySize(entry);\n\t\t\t\tconst oldSize: [number, number] = this.bottomLine.lineSize;\n\n\t\t\t\tif (newSize[0] !== oldSize[0] || newSize[1] !== oldSize[1]) {\n\t\t\t\t\tthis.bottomLine.lineSize = newSize;\n\t\t\t\t\tshouldRelayout = true;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tconst groupObj = this.lyricGroupElementMap.get(entry.target);\n\t\t\t\tif (groupObj) {\n\t\t\t\t\tconst newSize = getEntrySize(entry);\n\n\t\t\t\t\tconst isGroupElement = entry.target === groupObj.getElement();\n\n\t\t\t\t\tif (isGroupElement) {\n\t\t\t\t\t\tconst oldSize: [number, number] = this.lyricGroupSize.get(\n\t\t\t\t\t\t\tgroupObj,\n\t\t\t\t\t\t) ?? [0, 0];\n\n\t\t\t\t\t\tif (newSize[0] !== oldSize[0] || newSize[1] !== oldSize[1]) {\n\t\t\t\t\t\t\tthis.lyricGroupSize.set(groupObj, newSize);\n\t\t\t\t\t\t\tgroupObj.onLineSizeChange(newSize);\n\n\t\t\t\t\t\t\tconst index = this.lyricGroupIndexMap.get(groupObj) ?? -1;\n\t\t\t\t\t\t\tif (index !== -1) {\n\t\t\t\t\t\t\t\tthis.layoutCalculator.setLineHeight(index, newSize[1]);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tshouldRelayout = true;\n\t\t\t\t\t\t}\n\t\t\t\t\t} else {\n\t\t\t\t\t\tgroupObj.onBgSizeChange?.(newSize);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif (shouldUpdateFallback) {\n\t\t\tthis.layoutCalculator.updateUnmeasuredHeights(this.defaultLineHeight);\n\t\t\tshouldRelayout = true;\n\t\t}\n\n\t\tif (shouldRelayout) {\n\t\t\tthis.calcLayout(LayoutReason.Resize);\n\t\t}\n\t\tif (shouldRebuildPlayerStyle) {\n\t\t\tthis.onResize();\n\t\t}\n\t}) as ResizeObserverCallback);\n\tprotected wordFadeWidth = 0.5;\n\n\tconstructor(element?: HTMLElement) {\n\t\tsuper();\n\t\tif (element) this.element = element;\n\t\tthis.element.classList.add(\"amll-lyric-player\");\n\n\t\tthis.interludeDots = this.createInterludeDots();\n\t\tthis.bottomLine = this.createBottomLine();\n\n\t\tthis.resizeObserver.observe(this.element);\n\t\tthis.resizeObserver.observe(this.interludeDots.getElement());\n\t\tthis.resizeObserver.observe(this.bottomLine.getElement());\n\n\t\tthis.element.appendChild(this.interludeDots.getElement());\n\t\tthis.element.appendChild(this.bottomLine.getElement());\n\t\tthis.interludeDots.setTransform(0, 200);\n\n\t\tthis.bottomLineObserver = new MutationObserver(() => {\n\t\t\tconst bottomEl = this.getBottomLineElement();\n\t\t\tconst newHasBottomContent = bottomEl.innerHTML.trim().length > 0;\n\t\t\tif (this.hasBottomContent !== newHasBottomContent) {\n\t\t\t\tif (newHasBottomContent) {\n\t\t\t\t\t// 内容可能在歌词视图重建后才由调用者写入,此时也要与歌词行保持从底部远处飞入的入场效果\n\t\t\t\t\tthis.bottomLine.resetPosition();\n\t\t\t\t}\n\t\t\t\tthis.hasBottomContent = newHasBottomContent;\n\t\t\t\tthis.calcLayout(LayoutReason.ConfigChange);\n\t\t\t}\n\t\t});\n\t\tthis.bottomLineObserver.observe(this.getBottomLineElement(), {\n\t\t\tchildList: true,\n\t\t\tcharacterData: true,\n\t\t\tsubtree: true,\n\t\t});\n\n\t\twindow.addEventListener(\"pageshow\", this.onPageShow);\n\t\twindow.addEventListener(\"pagehide\", this.onPageHide);\n\t\tdocument.addEventListener(\"visibilitychange\", this.onVisibilityChange);\n\n\t\tthis.scrollEngine = new ScrollInteractionEngine(this.element, {\n\t\t\tonScrollUpdate: (isContinuous: boolean) => {\n\t\t\t\tthis.calcLayout(\n\t\t\t\t\tisContinuous\n\t\t\t\t\t\t? LayoutReason.ContinuousScroll\n\t\t\t\t\t\t: LayoutReason.DiscreteScroll,\n\t\t\t\t);\n\t\t\t},\n\t\t\tonInteractionStart: (type: ScrollInputType) => {\n\t\t\t\tthis.scrollState.isAutoAlignSuspended = true;\n\t\t\t\tthis.scrollState.isTouchScrolled = type === \"touch\";\n\t\t\t\tthis.calcLayout(LayoutReason.InteractionStart);\n\t\t\t},\n\t\t});\n\t}\n\n\t/**\n\t * 设置文字动画的渐变宽度,单位以歌词行的主文字字体大小的倍数为单位,默认为 0.5,即一个全角字符的一半宽度\n\t *\n\t * 如果要模拟 Apple Music for Android 的效果,可以设置为 1\n\t *\n\t * 如果要模拟 Apple Music for iPad 的效果,可以设置为 0.5\n\t *\n\t * 如果想要近乎禁用渐变效果,可以设置成非常接近 0 的小数(例如 `0.0001` ),但是**不可以为 0**\n\t *\n\t * @param value 需要设置的渐变宽度,单位以歌词行的主文字字体大小的倍数为单位,默认为 0.5\n\t */\n\tsetWordFadeWidth(value = 0.5): void {\n\t\tthis.wordFadeWidth = Math.max(0.0001, value);\n\t}\n\n\t/**\n\t * 是否启用歌词行缩放效果,默认启用\n\t *\n\t * 如果启用,非选中的歌词行会轻微缩小以凸显当前播放歌词行效果\n\t *\n\t * 此效果对性能影响微乎其微,推荐启用\n\t * @param enable 是否启用歌词行缩放效果\n\t */\n\tsetEnableScale(enable = true): void {\n\t\tthis.enableScale = enable;\n\t\tthis.calcLayout(LayoutReason.ConfigChange);\n\t}\n\t/**\n\t * 获取当前是否启用了歌词行缩放效果\n\t * @returns 是否启用歌词行缩放效果\n\t */\n\tgetEnableScale(): boolean {\n\t\treturn this.enableScale;\n\t}\n\n\t/**\n\t * 获取当前文字动画的渐变宽度,单位以歌词行的主文字字体大小的倍数为单位\n\t * @returns 当前文字动画的渐变宽度,单位以歌词行的主文字字体大小的倍数为单位\n\t */\n\tgetWordFadeWidth(): number {\n\t\treturn this.wordFadeWidth;\n\t}\n\n\t/**\n\t * 设置持续性的跳转状态\n\t *\n\t * @deprecated 此方法已无实际作用,调用它不会产生任何效果,仅为兼容保留,将在未来移除\n\t *\n\t * 跳转状态现在由每次进度推送逐帧推导,不再存在需要外部显式解除的持续状态\n\t *\n\t * 跳转会通过以下三条途径被识别,三者同时生效:\n\t *\n\t * - {@link setCurrentTime} 的 `isSeek` 参数,由调用方明确告知某次进度变化是跳转\n\t * - 进度倒退,由内部无条件识别,不受任何开关控制\n\t * - 自动推导,由内部比对进度的实际推进量与它应有的推进量识别超量前进,默认启用,\n\t * 可通过 {@link setEnableAutoSeekDetection} 关闭\n\t */\n\tsetIsSeeking(_isSeeking: boolean): void {}\n\n\t/**\n\t * 设置是否自动推导跳转状态,默认启用\n\t *\n\t * 启用后,即使调用 {@link setCurrentTime} 时没有传入 `isSeek`,\n\t * 内部也会在进度前进时比较它的实际推进量与应有的推进量,超量前进即视为跳转\n\t *\n\t * 应有的推进量取决于当前的播放状态,因此请按 {@link pause} 与 {@link resume}\n\t * 的文档正确同步播放状态:\n\t * - 播放时以物理时钟的推进量为准,容差随之按比例放宽,以容纳倍速播放与不均匀的推送节奏\n\t * - 暂停时进度本不该前进,应有的推进量是零,因此任何超出抖动幅度的前进都会被视为跳转\n\t *\n\t * 这意味着进度信息的粒度粗于推送间隔时,粒度跳变的那一帧会因超量前进被视为跳转,\n\t * 此时应当改善进度来源的精度,或关闭此开关\n\t *\n\t * 较小的向前跳转可能无法被识别,但一般影响不大\n\t *\n\t * 此开关只控制上述超量前进的判定。进度倒退不受它控制,无论是否启用推导都会被视为跳转;\n\t * 进度保持不变则既不前进也不后退,不会被推导视为跳转\n\t *\n\t * 推导只会额外识别出跳转,不会否决已显式传入的跳转标志,因此如果你已经在正确传入\n\t * 跳转标志了,则一般无需关心此开关。若你的进度来源精度很差而导致超量前进被频繁误判,\n\t * 可以选择关闭\n\t *\n\t * @param enable 是否启用自动推导\n\t */\n\tsetEnableAutoSeekDetection(enable = true): void {\n\t\tif (this.enableAutoSeekDetection === enable) return;\n\t\tthis.enableAutoSeekDetection = enable;\n\t\tthis.seekDetector.reset();\n\t}\n\n\t/**\n\t * 获取当前是否启用了跳转状态的自动推导\n\t * @returns 是否启用自动推导\n\t */\n\tgetEnableAutoSeekDetection(): boolean {\n\t\treturn this.enableAutoSeekDetection;\n\t}\n\n\t/**\n\t * 设置是否隐藏已经播放过的歌词行,默认不隐藏\n\t * @param hide 是否隐藏已经播放过的歌词行,默认不隐藏\n\t */\n\tsetHidePassedLines(hide: boolean): void {\n\t\tthis.hidePassedLines = hide;\n\t\tthis.calcLayout(LayoutReason.ConfigChange);\n\t}\n\t/**\n\t * 设置是否启用歌词行的模糊效果\n\t * @param enable 是否启用\n\t */\n\tsetEnableBlur(enable: boolean): void {\n\t\tif (this.enableBlur === enable) return;\n\t\tthis.enableBlur = enable;\n\t\tthis.calcLayout(LayoutReason.ConfigChange);\n\t}\n\n\t/**\n\t * 批量更新歌词处理配置,包括优化和掩码设置\n\t *\n\t * @remarks\n\t * 此方法不会自动重建歌词行和刷新视图,\n\t * 适用于在渲染前预设配置、批量初始化,或需要手动控制 DOM 刷新时机的场景\n\t * @param config 需要更新的配置集合\n\t * @see {@link LyricDataConfig}\n\t */\n\tsetLyricProcessConfig(config: LyricDataConfig): void {\n\t\tthis.dataManager.setConfig(config);\n\t}\n\n\t/**\n\t * 批量更新歌词处理配置,包括优化和掩码设置\n\t *\n\t * 可以调用此方法以避免多次单独设置处理配置导致的多次刷新开销\n\t * @remarks 在设置完成后会自动重建歌词行和刷新视图\n\t * @param config 需要更新的配置集合\n\t * @see {@link LyricDataConfig}\n\t */\n\tupdateLyricProcessConfig(config: LyricDataConfig): void {\n\t\tconst currentOptimize = this.dataManager.getOptimizeOptions();\n\t\tconst currentMaskMode = this.dataManager.getMaskMode();\n\t\tconst currentMaskChar = this.dataManager.getMaskChar();\n\n\t\tconst newOptimize =\n\t\t\tconfig.optimizeOptions !== undefined\n\t\t\t\t? config.optimizeOptions\n\t\t\t\t: currentOptimize;\n\t\tconst newMaskMode =\n\t\t\tconfig.maskMode !== undefined ? config.maskMode : currentMaskMode;\n\t\tconst newMaskChar =\n\t\t\tconfig.maskChar !== undefined ? config.maskChar : currentMaskChar;\n\n\t\tif (\n\t\t\tnewMaskMode === currentMaskMode &&\n\t\t\tnewMaskChar === currentMaskChar &&\n\t\t\tareOptimizeOptionsEqual(newOptimize, currentOptimize)\n\t\t) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis.dataManager.setConfig({\n\t\t\toptimizeOptions: newOptimize,\n\t\t\tmaskMode: newMaskMode,\n\t\t\tmaskChar: newMaskChar,\n\t\t});\n\n\t\tif (this.dataManager.getRawLines().length > 0) {\n\t\t\tthis.rebuildLyricView(this.getCurrentTime());\n\t\t\tthis.calcLayout(LayoutReason.ConfigChange);\n\t\t}\n\t}\n\n\t/**\n\t * 设置歌词中不雅用语的掩码模式\n\t * @remarks 在设置完成后会自动重建歌词行和刷新视图\n\t * @param mode 掩码模式\n\t * @see {@link MaskObsceneWordsMode}\n\t */\n\tsetMaskObsceneWords(mode: MaskObsceneWordsMode): void {\n\t\tthis.updateLyricProcessConfig({ maskMode: mode });\n\t}\n\n\t/**\n\t * 设置不雅用语掩码使用的字符,默认为 `*`\n\t * @remarks 在设置完成后会自动重建歌词行和刷新视图\n\t * @param char 单个字符,用于替换不雅用语中的字符\n\t */\n\tsetMaskObsceneWordChar(char: string): void {\n\t\tconst c = char.charAt(0) || \"*\";\n\t\tthis.updateLyricProcessConfig({ maskChar: c });\n\t}\n\n\t/**\n\t * 设置歌词的优化配置项,这些配置项默认全部开启\n\t * @remarks 在设置完成后会自动重建歌词行和刷新视图\n\t * @param options 优化配置选项\n\t * @see {@link OptimizeLyricOptions}\n\t */\n\tsetOptimizeOptions(options: OptimizeLyricOptions): void {\n\t\tconst currentOpts = this.dataManager.getOptimizeOptions();\n\t\tthis.updateLyricProcessConfig({\n\t\t\toptimizeOptions: { ...currentOpts, ...options },\n\t\t});\n\t}\n\n\trebuildLyricLines(): void {\n\t\tfor (const group of this.currentLyricGroups) {\n\t\t\tgroup.rebuildAllLines();\n\t\t}\n\t}\n\n\t/**\n\t * 设置目标歌词行的对齐方式,默认为 `center`\n\t *\n\t * - 设置成 `top` 的话将会向目标歌词行的顶部对齐\n\t * - 设置成 `bottom` 的话将会向目标歌词行的底部对齐\n\t * - 设置成 `center` 的话将会向目标歌词行的垂直中心对齐\n\t * @param alignAnchor 歌词行对齐方式,详情见函数说明\n\t */\n\tsetAlignAnchor(alignAnchor: LayoutAlignAnchor): void {\n\t\tthis.layoutConfig.alignAnchor = alignAnchor;\n\t}\n\t/**\n\t * 设置默认的歌词行对齐位置,相对于整个歌词播放组件的大小位置,默认为 `0.5`\n\t * @param alignPosition 一个 `[0.0-1.0]` 之间的任意数字,代表组件高度由上到下的比例位置\n\t */\n\tsetAlignPosition(alignPosition: number): void {\n\t\tthis.layoutConfig.alignPosition = alignPosition;\n\t}\n\n\t/**\n\t * 设置 overscan(视图上下额外缓冲渲染区)距离,单位:像素。\n\t * @param px 像素值,默认 300\n\t */\n\tsetOverscanPx(px: number): void {\n\t\tthis.layoutConfig.overscanPx = clampPositive(px | 0);\n\t}\n\t/** 获取当前 overscan 像素距离 */\n\tgetOverscanPx(): number {\n\t\treturn this.layoutConfig.overscanPx;\n\t}\n\t/**\n\t * 设置是否使用物理弹簧算法实现歌词动画效果,默认启用\n\t *\n\t * 如果启用,则会通过弹簧算法实时处理歌词位置,但是需要性能足够强劲的电脑方可流畅运行\n\t *\n\t * 如果不启用,则会回退到基于 `transition` 的过渡效果,对低性能的机器比较友好,但是效果会比较单一\n\t */\n\tsetEnableSpring(enable = true): void {\n\t\tthis.disableSpring = !enable;\n\t\tif (enable) {\n\t\t\tthis.element.classList.remove(styles.disableSpring);\n\t\t} else {\n\t\t\tthis.element.classList.add(styles.disableSpring);\n\t\t}\n\t\tthis.calcLayout(LayoutReason.ConfigChange);\n\t}\n\t/**\n\t * 获取当前是否启用了物理弹簧\n\t * @returns 是否启用物理弹簧\n\t */\n\tgetEnableSpring(): boolean {\n\t\treturn !this.disableSpring;\n\t}\n\n\t/**\n\t * 设置当前播放歌词,要注意传入后这个数组内的信息不得修改,否则会发生错误\n\t * @param lines 歌词数组\n\t * @param initialTime 初始时间,默认为 0\n\t * @throws {TypeError} 歌词时间戳不是有限的非负数字\n\t * @throws {RangeError} 任一行、单词或注音的开始时间晚于结束时间\n\t */\n\tsetLyricLines(lines: LyricLine[], initialTime = 0): void {\n\t\tif (import.meta.env.DEV) {\n\t\t\tconsole.log(\"设置歌词行\", lines, initialTime);\n\t\t}\n\n\t\tthis.dataManager.setOriginalLines(lines);\n\t\tthis.rebuildLyricView(initialTime);\n\t}\n\n\t/**\n\t * 获取当前是否在播放\n\t * @returns 当前是否在播放\n\t */\n\tpublic getIsPlaying(): boolean {\n\t\treturn this.isPlaying;\n\t}\n\n\t/**\n\t * 设置当前播放进度,此时将会更新内部的歌词进度信息。\n\t *\n\t * 内部会根据调用间隔和播放进度自动决定应如何滚动和显示歌词,所以此方法的调用频率越快越准确越好。\n\t * 调用频率较低或进度细度过粗可能会导致歌词显示延迟或导致自动跳转推导错误。\n\t * 调用完成后,应每帧调用 {@link update} 方法来执行歌词动画效果。此函数本身不会触发动画效果。\n\t *\n\t * 当 `isSeek` 为 `true` 时,将强制按跳转处理,并在下次调用 {@link update} 时触发一系列的行为变更,\n\t * 具体请参考 <https://amll.dev/guides/component/seeking>,因此请只在真正跳转时设为 `true`\n\t *\n\t * @param time 当前播放进度,单位为毫秒,非有限值会被静默忽略\n\t * @param isSeek 是否强制按跳转处理,默认交由内部推导\n\t * @see {@link setEnableAutoSeekDetection} 自动推导跳转状态的文档\n\t * @see https://amll.dev/guides/component/sequence#播放进度\n\t */\n\tsetCurrentTime(time: number, isSeek = false): void {\n\t\tif (!Number.isFinite(time)) return;\n\n\t\tconst mediaTime = MediaTime.round(MediaTime.fromMillis(time));\n\n\t\t// 探测器必须消费每一次进度推送才能维持内部状态正确,即使本次已经被调用方标记为跳转\n\t\tconst isDetectedSeek = this.enableAutoSeekDetection\n\t\t\t? this.seekDetector.detect(mediaTime, this.isPlaying)\n\t\t\t: false;\n\n\t\tthis.syncTime(mediaTime, isSeek || isDetectedSeek);\n\t}\n\n\t/**\n\t * 推进时间线并把增量变化应用到视图上\n\t * @param mediaTime 当前播放进度\n\t * @param isSeek 这次进度变化是否为跳转\n\t */\n\tprivate syncTime(mediaTime: MediaTime, isSeek: boolean): void {\n\t\tconst wasFocusOnInterlude =\n\t\t\tthis.timelineController.getSnapshot().isFocusOnInterlude;\n\t\tconst diff = this.timelineController.sync(mediaTime, isSeek);\n\n\t\t// 间奏播放时,时间线没有任何差异,calcLayout 与 setInterlude 不会执行,\n\t\t// 演出时钟需要在这里对齐到推送的媒体时间,否则只能靠 update 的 delta 累加推进,\n\t\t// 页面挂起恢复后 delta 被钳制,时钟会落后于媒体时间\n\t\tthis.interludeDots.syncClock(mediaTime);\n\n\t\tif (!diff.hasChanged) {\n\t\t\treturn;\n\t\t}\n\n\t\t// 时间轴是否跳跃由时间线统一推导,除了传入的 isSeek 外还包含进度倒退的情况\n\t\tconst isTimeJumped = diff.isTimeJumped;\n\t\tconst snapshot = this.timelineController.getSnapshot();\n\n\t\tfor (let i = 0; i < diff.removedHighlighted.length; i++) {\n\t\t\tthis.currentLyricGroups[diff.removedHighlighted[i]]?.disable();\n\t\t}\n\n\t\tif (isTimeJumped) {\n\t\t\tfor (const index of snapshot.highlightedGroups) {\n\t\t\t\tthis.currentLyricGroups[index]?.enable();\n\t\t\t}\n\t\t} else {\n\t\t\tfor (let i = 0; i < diff.addedHighlighted.length; i++) {\n\t\t\t\tthis.currentLyricGroups[diff.addedHighlighted[i]]?.enable();\n\t\t\t}\n\t\t}\n\n\t\tif (isTimeJumped) {\n\t\t\tif (!this.scrollState.isTouchScrolled) {\n\t\t\t\tthis.resetScroll();\n\t\t\t}\n\t\t} else if (\n\t\t\t(diff.isScrollToChanged || wasFocusOnInterlude) &&\n\t\t\t!snapshot.isFocusOnInterlude &&\n\t\t\tsnapshot.playingGroups.has(snapshot.scrollToIndex) &&\n\t\t\tthis.scrollState.isAutoAlignSuspended &&\n\t\t\tthis.scrollEngine.canResumeAutoAlign &&\n\t\t\tthis.currentLyricGroups[snapshot.scrollToIndex]?.isInRenderRange(false)\n\t\t) {\n\t\t\tthis.resetScroll();\n\t\t}\n\n\t\tif (\n\t\t\tdiff.isInterludeChanged ||\n\t\t\tdiff.isScrollToChanged ||\n\t\t\tdiff.isEndOfSongChanged ||\n\t\t\tisTimeJumped\n\t\t) {\n\t\t\tthis.updateSpringParams(\n\t\t\t\t!!snapshot.activeInterlude,\n\t\t\t\tisTimeJumped,\n\t\t\t\tsnapshot.isEndOfSong,\n\t\t\t);\n\t\t}\n\n\t\tthis.calcLayout(\n\t\t\tisTimeJumped ? LayoutReason.Seek : LayoutReason.PlaybackTick,\n\t\t);\n\t}\n\n\t/**\n\t * 由子类实现的歌词组构建逻辑\n\t */\n\tprotected abstract buildLyricGroups(): void;\n\n\t/**\n\t * 由子类实现的间奏点组件创建逻辑\n\t *\n\t * 在基类构造函数中调用,子类需要返回对应渲染实现的后端\n\t *\n\t * @remarks 工厂执行时子类字段尚未初始化,实现内不得读取子类实例状态,\n\t * 所需资源应由返回的组件自行创建或延迟获取\n\t */\n\tprotected abstract createInterludeDots(): InterludeDotsBase & HasElement;\n\n\t/**\n\t * 由子类实现的底栏组件创建逻辑\n\t *\n\t * 在基类构造函数中调用,子类需要返回对应渲染实现的实例\n\t *\n\t * @remarks 工厂执行时子类字段尚未初始化,实现内不得读取子类实例状态,\n\t * 所需资源应由返回的组件自行创建或延迟获取\n\t */\n\tprotected abstract createBottomLine(): BottomLine;\n\n\t/**\n\t * 重新构建歌词行和时间状态\n\t *\n\t * 一般用于在调用 {@link setLyricProcessConfig} 更新配置后手动刷新视图,\n\t * 或在外部样式/DOM 结构发生改变后重置歌词视图\n\t *\n\t * @param initialTime 重建后对齐的初始时间(毫秒),默认使用当前播放进度\n\t */\n\tpublic rebuildLyricView(initialTime: number = this.getCurrentTime()): void {\n\t\tthis.resetScroll();\n\t\tthis.focusController.reset();\n\n\t\tconst bottomLineContent = this.getBottomLineElement();\n\t\tif (bottomLineContent.innerHTML.trim().length > 0) {\n\t\t\tthis.bottomLine.resetPosition();\n\t\t}\n\n\t\tfor (const group of this.currentLyricGroups) {\n\t\t\tgroup.dispose();\n\t\t}\n\t\tthis.currentLyricGroups = [];\n\n\t\tthis.interludeDots.clearInterlude(true);\n\n\t\tthis.buildLyricGroups();\n\n\t\t// 对歌词组进行排序,确保滑动窗口与二分查找算法面对的时间线是严格升序的\n\t\tthis.currentLyricGroups.sort((a, b) =>\n\t\t\tMediaTime.cmp(a.startTime, b.startTime),\n\t\t);\n\t\tfor (let i = 0; i < this.currentLyricGroups.length; i++) {\n\t\t\tthis.lyricGroupIndexMap.set(this.currentLyricGroups[i], i);\n\t\t}\n\n\t\tconst bounds = this.currentLyricGroups.map((group) => ({\n\t\t\tstartTime: group.startTime,\n\t\t\tendTime: group.endTime,\n\t\t}));\n\t\tthis.timelineController.setTimeBounds(bounds);\n\n\t\tthis.layoutCalculator.initHeights(\n\t\t\tthis.currentLyricGroups.length,\n\t\t\tthis.defaultLineHeight,\n\t\t);\n\n\t\tthis.seekDetector.reset();\n\t\tthis.setCurrentTime(initialTime, true);\n\t\tthis.calcLayout(LayoutReason.RebuildView);\n\n\t\tif (import.meta.env.DEV) {\n\t\t\tconsole.log(\"歌词视图重建完成\", this);\n\t\t}\n\t}\n\t/**\n\t * 更新歌词纵向滚动动画的弹簧参数。\n\t *\n\t * 其策略为:\n\t * - seeking 或间奏时使用更稳定的固定参数\n\t * - 普通播放时根据相邻歌词的时间间隔动态调整 stiffness / damping\n\t * - 播放完毕时使用中速弹簧参数\n\t *\n\t * @param isInterludeActive 当前是否命中间奏区间\n\t * @param isSeeking 本次同步的时间轴是否发生了跳转\n\t * @param isEndOfSong 歌曲是否播放完毕\n\t */\n\tprivate updateSpringParams(\n\t\tisInterludeActive: boolean,\n\t\tisSeeking: boolean,\n\t\tisEndOfSong: boolean,\n\t): void {\n\t\tif (!this.getEnableSpring() || this.currentLyricGroups.length === 0) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst { scrollToIndex } = this.timelineController.getSnapshot();\n\n\t\tconst currentGroup = this.currentLyricGroups[scrollToIndex];\n\t\tconst prevGroup = this.currentLyricGroups[scrollToIndex - 1];\n\n\t\tlet interval: number | undefined;\n\t\tif (currentGroup && prevGroup) {\n\t\t\tinterval = Duration.asMillis(\n\t\t\t\tMediaTime.since(currentGroup.startTime, prevGroup.startTime),\n\t\t\t);\n\t\t}\n\n\t\tconst policy = getPosYSpringPolicy(\n\t\t\tisSeeking,\n\t\t\tisInterludeActive,\n\t\t\tinterval,\n\t\t\tisEndOfSong,\n\t\t);\n\n\t\tthis.setLinePosYSpringParams(policy);\n\t}\n\n\t/**\n\t * 重新计算歌词行的几何排版坐标与视觉状态\n\t *\n\t * 此方法不会触发 DOM 强制重排\n\t *\n\t * 计算完成后,在每一帧调用 `update()` / `commitChanges()` 即可让歌词平滑移动至目标位置\n\t *\n\t * @internal 仅供内部和绑定包使用\n\t * @param reason 触发排版布局更新的原因场景\n\t */\n\tcalcLayout(reason: LayoutReason): void {\n\t\tconst strategy = LayoutReasonStrategyMap[reason];\n\n\t\tconst snapshot = this.timelineController.getSnapshot();\n\t\tconst interlude = snapshot.activeInterlude;\n\n\t\t// 确定间奏演出状态与可用性\n\t\tlet canDisplayInterlude = false;\n\t\tif (interlude) {\n\t\t\tcanDisplayInterlude = this.interludeDots.setInterlude(\n\t\t\t\t[interlude.startTime, interlude.endTime],\n\t\t\t\tsnapshot.currentTime,\n\t\t\t\tstrategy.resetInterlude,\n\t\t\t\tinterlude.anchorLineIndex,\n\t\t\t);\n\t\t} else {\n\t\t\tthis.interludeDots.clearInterlude();\n\t\t}\n\n\t\t// 确定这一帧焦点应该对齐谁\n\t\tconst focalTarget = this.focusController.resolve(\n\t\t\tsnapshot,\n\t\t\tthis.currentLyricGroups.length,\n\t\t\t{\n\t\t\t\tisAutoAlignSuspended: this.scrollState.isAutoAlignSuspended,\n\t\t\t\thasBottomContent: this.hasBottomContent,\n\t\t\t\tcanDisplayInterlude,\n\t\t\t},\n\t\t);\n\n\t\t// 组装给布局计算器和滚动引擎用的数据\n\t\tconst fontSize = this.baseFontSize || 24;\n\t\tconst dotMargin = fontSize * 0.4;\n\t\tconst totalInterludeHeight =\n\t\t\tthis.layoutState.interludeDotsSize[1] + dotMargin * 2;\n\n\t\tconst ctx = this.frameContext;\n\t\tctx.containerHeight = this.size[1];\n\t\tctx.target = focalTarget;\n\t\tctx.bottomLineHeight = this.bottomLine.lineSize[1] || 0;\n\n\t\t// 设置间奏相关的上下文参数\n\t\tconst activeInterludeForLayout = canDisplayInterlude\n\t\t\t? interlude\n\t\t\t: undefined;\n\t\tconst interludeAnchorIndex = LayoutCalculator.resolveInterludeAnchorIndex(\n\t\t\tactiveInterludeForLayout,\n\t\t\tfocalTarget,\n\t\t);\n\n\t\tif (interludeAnchorIndex !== undefined) {\n\t\t\tctx.interlude = ctx.interlude || { totalHeight: 0, anchorIndex: 0 };\n\t\t\tctx.interlude.totalHeight = totalInterludeHeight;\n\t\t\tctx.interlude.anchorIndex = interludeAnchorIndex;\n\t\t} else {\n\t\t\tctx.interlude = undefined;\n\t\t}\n\n\t\t// 获取滚动边界与帧 Session,钳制出安全 offset 后提交排版\n\t\tconst { bounds, session } = this.layoutCalculator.beginFrame(\n\t\t\tctx,\n\t\t\tthis.layoutConfig,\n\t\t);\n\t\tctx.scrollOffset = this.scrollEngine.updateBoundary(bounds.min, bounds.max);\n\n\t\t// 让 LayoutCalculator 算出各个排版信息\n\t\tconst result = this.layoutCalculator.commit(session, ctx.scrollOffset);\n\n\t\t// 检查是否需要显示间奏点\n\t\tif (result.hasInterlude && canDisplayInterlude && interlude) {\n\t\t\tconst nextLineIndex = interlude.anchorLineIndex + 1;\n\t\t\tconst nextGroup = this.currentLyricGroups[nextLineIndex];\n\t\t\tconst isNextDuet = nextGroup?.mainLine.getLine().isDuet ?? false;\n\n\t\t\t// 如果下一行是对唱,让间奏点右对齐\n\t\t\tconst targetX = isNextDuet\n\t\t\t\t? this.size[0] - this.layoutState.interludeDotsSize[0]\n\t\t\t\t: 0;\n\n\t\t\tthis.interludeDots.setTransform(\n\t\t\t\ttargetX,\n\t\t\t\tresult.interludeY + dotMargin,\n\t\t\t\tstrategy.snapPosY || !this.getEnableSpring(),\n\t\t\t);\n\t\t}\n\n\t\t// 刷新本帧的视觉推导派生值\n\t\tconst visual = this.visualFrame;\n\t\tvisual.latestIndex =\n\t\t\tsnapshot.latestHighlightedIndex ?? snapshot.scrollToIndex;\n\t\tvisual.passedBoundary = interlude\n\t\t\t? interlude.anchorLineIndex + 1\n\t\t\t: snapshot.scrollToIndex;\n\t\tvisual.isNarrowViewport = window.innerWidth <= 1024;\n\n\t\t// 遍历 LayoutCalculator 算出的排版信息并应用视觉效果\n\t\tconst activeCount = result.lineCount;\n\n\t\tlet delay = Duration.ZERO;\n\t\tlet baseDelay = strategy.disableStagger\n\t\t\t? Duration.ZERO\n\t\t\t: Duration.fromSecs(0.05);\n\n\t\tfor (let i = 0; i < activeCount; i++) {\n\t\t\tconst group = this.currentLyricGroups[i];\n\t\t\tconst instruction = result.lineInstructions[i];\n\t\t\tconst curPos = instruction.y;\n\t\t\tconst isInViewport = instruction.isInViewport;\n\t\t\tconst isActive = this.resolveIsActive(i, snapshot);\n\n\t\t\t// 设置样式\n\t\t\tgroup.setTransform(\n\t\t\t\tcurPos,\n\t\t\t\tstrategy.snapPosY,\n\t\t\t\tdelay,\n\t\t\t\tisActive,\n\t\t\t\tthis.resolveOpacity(i, isInViewport, snapshot),\n\t\t\t\tthis.resolveBlurLevel(i, isActive, isInViewport, snapshot),\n\t\t\t);\n\n\t\t\t// 应用阶梯式的动画延迟\n\t\t\tconst lineH = instruction.height;\n\t\t\tif (curPos + lineH >= 0) {\n\t\t\t\tdelay = Duration.add(delay, baseDelay);\n\t\t\t\tif (i >= snapshot.scrollToIndex) {\n\t\t\t\t\tbaseDelay = Duration.mulF64(baseDelay, 1 / 1.05);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// 底栏相关的处理\n\t\tconst isBottomFocused = focalTarget.type === \"bottom\";\n\t\tthis.bottomLine.setFocused(isBottomFocused);\n\n\t\tthis.bottomLine.setTransform(\n\t\t\tresult.bottomLineY,\n\t\t\t// 底栏按「末行之后的一行」索引计算模糊度\n\t\t\tthis.resolveBlurLevel(\n\t\t\t\tactiveCount,\n\t\t\t\tisBottomFocused,\n\t\t\t\tresult.isBottomLineInViewport,\n\t\t\t\tsnapshot,\n\t\t\t),\n\t\t\tstrategy.snapPosY,\n\t\t\tdelay,\n\t\t);\n\t}\n\n\t/**\n\t * 推导某一行是否处于激活状态\n\t * @param index 歌词行索引\n\t * @param snapshot 当前帧的时间线快照\n\t */\n\tprivate resolveIsActive(index: number, snapshot: TimelineSnapshot): boolean {\n\t\treturn (\n\t\t\tsnapshot.highlightedGroups.has(index) ||\n\t\t\t(index >= snapshot.scrollToIndex && index < this.visualFrame.latestIndex)\n\t\t);\n\t}\n\n\t/**\n\t * 推导一行的目标透明度\n\t * @param index 歌词行索引\n\t * @param isInViewport 该行是否在可视区域内\n\t * @param snapshot 当前帧的时间线快照\n\t */\n\tprivate resolveOpacity(\n\t\tindex: number,\n\t\tisInViewport: boolean,\n\t\tsnapshot: TimelineSnapshot,\n\t): number {\n\t\t// 在视口外则剔除渲染\n\t\tif (!isInViewport) return 0;\n\n\t\tif (\n\t\t\tthis.hidePassedLines &&\n\t\t\tthis.isPlaying &&\n\t\t\tindex < this.visualFrame.passedBoundary\n\t\t) {\n\t\t\t// 为了避免浏览器优化,这里使用了一个极小但不为零的值(几乎不可见)\n\t\t\treturn 1e-4;\n\t\t}\n\n\t\tif (snapshot.highlightedGroups.has(index)) return 0.85;\n\n\t\treturn this.isNonDynamic ? 0.2 : 1;\n\t}\n\n\t/**\n\t * 按距焦点的行距推导模糊档位\n\t * @param index 歌词行索引,底栏传入歌词总行数\n\t * @param isFocused 该目标是否为当前焦点,歌词行传 `isActive`,底栏传是否聚焦底栏\n\t * @param isInViewport 该目标是否在可视区域内\n\t * @param snapshot 当前帧的时间线快照\n\t */\n\tprivate resolveBlurLevel(\n\t\tindex: number,\n\t\tisFocused: boolean,\n\t\tisInViewport: boolean,\n\t\tsnapshot: TimelineSnapshot,\n\t): number {\n\t\tif (!this.enableBlur) return 0;\n\n\t\t// 在视口外直接给到最大模糊\n\t\tif (!isInViewport) return 5;\n\n\t\t// 用户触摸滑动期间和对焦目标不施加模糊\n\t\tif (this.scrollState.isTouchScrolled || isFocused) return 0;\n\n\t\tconst scrollToIndex = snapshot.scrollToIndex;\n\t\tconst distance =\n\t\t\tindex < scrollToIndex\n\t\t\t\t? Math.abs(scrollToIndex - index) + 1\n\t\t\t\t: Math.abs(index - this.visualFrame.latestIndex);\n\n\t\tconst level = 1 + distance;\n\t\treturn this.visualFrame.isNarrowViewport ? level * 0.8 : level;\n\t}\n\n\t/**\n\t * 设置所有歌词行、底栏和间奏点在横坐标上的弹簧属性,包括重量、弹力和阻力。\n\t *\n\t * @param params 需要设置的弹簧属性,提供的属性将会覆盖原来的属性,未提供的属性将会保持原样\n\t * @deprecated 考虑到横向弹簧效果并不常见,所以这个函数将会在未来的版本中移除\n\t */\n\tsetLinePosXSpringParams(_params: Partial<SpringParams> = {}): void {}\n\t/**\n\t * 设置所有歌词行、底栏和间奏点在​纵坐标上的弹簧属性,包括重量、弹力和阻力。\n\t *\n\t * @param params 需要设置的弹簧属性,提供的属性将会覆盖原来的属性,未提供的属性将会保持原样\n\t */\n\tsetLinePosYSpringParams(params: Partial<SpringParams> = {}): void {\n\t\tthis.posYSpringParams = {\n\t\t\t...this.posYSpringParams,\n\t\t\t...params,\n\t\t};\n\t\tthis.bottomLine.lineTransforms.posY.updateParams(this.posYSpringParams);\n\t\tthis.interludeDots.posY.updateParams(this.posYSpringParams);\n\t\tfor (const group of this.currentLyricGroups) {\n\t\t\tgroup.posY.updateParams(this.posYSpringParams);\n\t\t\tgroup.bgSlideY.updateParams(this.posYSpringParams);\n\t\t}\n\t}\n\t/**\n\t * 设置所有歌词行在​缩放大小上的弹簧属性,包括重量、弹力和阻力。\n\t *\n\t * @param params 需要设置的弹簧属性,提供的属性将会覆盖原来的属性,未提供的属性将会保持原样\n\t */\n\tsetLineScaleSpringParams(params: Partial<SpringParams> = {}): void {\n\t\tthis.scaleSpringParams = {\n\t\t\t...this.scaleSpringParams,\n\t\t\t...params,\n\t\t};\n\t\tthis.scaleForBGSpringParams = {\n\t\t\t...this.scaleForBGSpringParams,\n\t\t\t...params,\n\t\t};\n\t\tfor (const group of this.currentLyricGroups) {\n\t\t\tgroup.mainLine.lineTransforms.scale.updateParams(this.scaleSpringParams);\n\n\t\t\tgroup.bgLine?.lineTransforms.scale.updateParams(\n\t\t\t\tthis.scaleForBGSpringParams,\n\t\t\t);\n\t\t}\n\t}\n\t/**\n\t * 暂停部分效果演出,目前会暂停播放间奏点的动画,且将背景歌词显示出来\n\t */\n\tpause(): void {\n\t\tthis.interludeDots.pause();\n\t\tif (this.isPlaying) {\n\t\t\tthis.isPlaying = false;\n\t\t\tthis.calcLayout(LayoutReason.ConfigChange);\n\t\t}\n\t}\n\t/**\n\t * 恢复部分效果演出,目前会恢复播放间奏点的动画\n\t */\n\tresume(): void {\n\t\tthis.interludeDots.resume();\n\t\tif (!this.isPlaying) {\n\t\t\tthis.isPlaying = true;\n\t\t\tthis.calcLayout(LayoutReason.ConfigChange);\n\t\t}\n\t}\n\t/**\n\t * 更新动画,这个函数应该被逐帧调用或者在以下情况下调用一次:\n\t *\n\t * 1. 刚刚调用完设置歌词函数的时候\n\t * @param delta 距离上一次被调用到现在的时长,单位为毫秒(可为浮点数)\n\t */\n\n\tupdate(delta = 0): void {\n\t\tconst d = Duration.min(Duration.fromMillis(delta), MAX_FRAME_DELTA);\n\t\tthis.bottomLine.update(d);\n\t\tthis.interludeDots.update(d);\n\t}\n\n\tprotected onResize(): void {}\n\n\t/**\n\t * 获取一个特殊的底栏元素,默认是空白的,可以往内部添加任意元素\n\t *\n\t * 这个元素始终在歌词的底部,可以用于显示歌曲创作者等信息\n\t *\n\t * 但是请勿删除该元素,只能在内部存放元素\n\t *\n\t * @returns 一个元素,可以往内部添加任意元素\n\t */\n\tgetBottomLineElement(): HTMLElement {\n\t\treturn (\n\t\t\tthis.bottomLine.getContentElement?.() ?? this.bottomLine.getElement()\n\t\t);\n\t}\n\t/**\n\t * 重置用户滚动状态并恢复自动对齐\n\t *\n\t * 一个典型的使用场景是在用户滚动完毕、但歌词未自动归位时立刻归位\n\t */\n\tresetScroll(): void {\n\t\tthis.scrollEngine.resetScroll(0);\n\t\tthis.scrollState.isAutoAlignSuspended = false;\n\t\tthis.scrollState.isTouchScrolled = false;\n\t}\n\t/**\n\t * 获取当前播放的、未经过优化和掩码处理的歌词数组\n\t *\n\t * 一般和最后调用 `setLyricLines` 给予的参数一样\n\t * @returns 当前歌词数组\n\t */\n\tgetLyricLines(): ReadonlyArray<LyricLine> {\n\t\treturn this.dataManager.getRawLines();\n\t}\n\t/**\n\t * 获取当前歌词的播放位置\n\t *\n\t * 一般和最后调用 `setCurrentTime` 给予的参数一样\n\t * @returns 当前播放位置\n\t */\n\tgetCurrentTime(): number {\n\t\treturn MediaTime.asMillis(\n\t\t\tthis.timelineController.getSnapshot().currentTime,\n\t\t);\n\t}\n\n\t/**\n\t * 设置是否让背景人声行始终后置显示\n\t *\n\t * 默认情况下,如果背景歌词开始时间早于主歌词,会在主歌词上方展示;\n\t * 如果设置为 `true`,则无论时间顺序如何,背景歌词都会始终在主歌词下方展示\n\t * @param enable 是否启用始终后置\n\t */\n\tsetAlwaysPostpositionBackground(enable: boolean): void {\n\t\tif (this.alwaysPostpositionBackground === enable) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis.alwaysPostpositionBackground = enable;\n\n\t\tthis.rebuildLyricLines();\n\t\tthis.calcLayout(LayoutReason.ConfigChange);\n\t}\n\n\t/** 获取当前是否设置了让背景人声行始终后置显示 */\n\tgetAlwaysPostpositionBackground(): boolean {\n\t\treturn this.alwaysPostpositionBackground;\n\t}\n\n\tgetElement(): HTMLElement {\n\t\treturn this.element;\n\t}\n\tdispose(): void {\n\t\tthis.scrollEngine.dispose();\n\t\tthis.element.remove();\n\t\tthis.bottomLineObserver.disconnect();\n\t\tthis.interludeDots.dispose();\n\t\tthis.bottomLine.dispose();\n\t\twindow.removeEventListener(\"pageshow\", this.onPageShow);\n\t\twindow.removeEventListener(\"pagehide\", this.onPageHide);\n\t\tdocument.removeEventListener(\"visibilitychange\", this.onVisibilityChange);\n\t}\n}\n","export function derivative(f: (x: number) => number) {\n\tconst h = 0.001;\n\treturn (x: number): number => (f(x + h) - f(x - h)) / (2 * h);\n}\n\nexport function getVelocity(f: (t: number) => number): (t: number) => number {\n\treturn derivative(f);\n}\n","import { getVelocity } from \"./derivative.ts\";\nimport { Duration } from \"./time.ts\";\n\n/** MIT License github.com/pushkine/ */\nexport interface SpringParams {\n\tmass: number; // = 1.0\n\tdamping: number; // = 10.0\n\tstiffness: number; // = 100.0\n\tsoft: boolean; // = false\n}\n\ntype Seconds = number;\n\nexport class Spring {\n\tprivate currentPosition = 0;\n\tprivate targetPosition = 0;\n\tprivate currentTime: Seconds = 0;\n\tprivate params: Partial<SpringParams> = {};\n\tprivate currentSolver: (t: Seconds) => number;\n\tprivate getV: (t: Seconds) => number;\n\tprivate getV2: (t: Seconds) => number;\n\tprivate queueParams:\n\t\t| (Partial<SpringParams> & {\n\t\t\t\ttime: Seconds;\n\t\t })\n\t\t| undefined;\n\tprivate queuePosition:\n\t\t| {\n\t\t\t\ttime: Seconds;\n\t\t\t\tposition: number;\n\t\t }\n\t\t| undefined;\n\tconstructor(currentPosition = 0) {\n\t\tthis.targetPosition = currentPosition;\n\t\tthis.currentPosition = this.targetPosition;\n\t\tthis.currentSolver = () => this.targetPosition;\n\t\tthis.getV = () => 0;\n\t\tthis.getV2 = () => 0;\n\t}\n\tprivate resetSolver() {\n\t\tconst curV = this.getV(this.currentTime);\n\t\tthis.currentTime = 0;\n\t\tthis.currentSolver = solveSpring(\n\t\t\tthis.currentPosition,\n\t\t\tcurV,\n\t\t\tthis.targetPosition,\n\t\t\t0,\n\t\t\tthis.params,\n\t\t);\n\t\tthis.getV = getVelocity(this.currentSolver);\n\t\tthis.getV2 = getVelocity(this.getV);\n\t}\n\tarrived(): boolean {\n\t\treturn (\n\t\t\tMath.abs(this.targetPosition - this.currentPosition) < 0.01 &&\n\t\t\tMath.abs(this.getV(this.currentTime)) < 0.01 &&\n\t\t\tMath.abs(this.getV2(this.currentTime)) < 0.01 &&\n\t\t\tthis.queueParams === undefined &&\n\t\t\tthis.queuePosition === undefined\n\t\t);\n\t}\n\tsetPosition(targetPosition: number): void {\n\t\tthis.targetPosition = targetPosition;\n\t\tthis.currentPosition = targetPosition;\n\t\tthis.currentSolver = () => this.targetPosition;\n\t\tthis.getV = () => 0;\n\t\tthis.getV2 = () => 0;\n\t}\n\tupdate(delta: Duration = Duration.ZERO): void {\n\t\tconst dt = Duration.asSecsF64(delta);\n\t\tthis.currentTime += dt;\n\t\tthis.currentPosition = this.currentSolver(this.currentTime);\n\t\tif (this.queueParams) {\n\t\t\tthis.queueParams.time -= dt;\n\t\t\tif (this.queueParams.time <= 0) {\n\t\t\t\tthis.updateParams({\n\t\t\t\t\t...this.queueParams,\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t\tif (this.queuePosition) {\n\t\t\tthis.queuePosition.time -= dt;\n\t\t\tif (this.queuePosition.time <= 0) {\n\t\t\t\tthis.setTargetPosition(this.queuePosition.position);\n\t\t\t}\n\t\t}\n\t\tif (this.arrived()) {\n\t\t\tthis.setPosition(this.targetPosition);\n\t\t}\n\t}\n\tupdateParams(\n\t\tparams: Partial<SpringParams>,\n\t\tdelay: Duration = Duration.ZERO,\n\t): void {\n\t\tconst delaySecs = Duration.asSecsF64(delay);\n\t\tif (delaySecs > 0) {\n\t\t\tthis.queueParams = {\n\t\t\t\t...(this.queuePosition ?? {}),\n\t\t\t\t...params,\n\t\t\t\ttime: delaySecs,\n\t\t\t};\n\t\t} else {\n\t\t\tthis.queuePosition = undefined;\n\t\t\tthis.params = {\n\t\t\t\t...this.params,\n\t\t\t\t...params,\n\t\t\t};\n\t\t\tthis.resetSolver();\n\t\t}\n\t}\n\tsetTargetPosition(\n\t\ttargetPosition: number,\n\t\tdelay: Duration = Duration.ZERO,\n\t): void {\n\t\tconst delaySecs = Duration.asSecsF64(delay);\n\t\tif (\n\t\t\tdelaySecs <= 0 &&\n\t\t\tMath.abs(this.targetPosition - targetPosition) < 0.001\n\t\t) {\n\t\t\tthis.queuePosition = undefined;\n\t\t\treturn;\n\t\t}\n\n\t\tif (delaySecs > 0) {\n\t\t\tthis.queuePosition = {\n\t\t\t\t...(this.queuePosition ?? {}),\n\t\t\t\tposition: targetPosition,\n\t\t\t\ttime: delaySecs,\n\t\t\t};\n\t\t} else {\n\t\t\tthis.queuePosition = undefined;\n\t\t\tthis.targetPosition = targetPosition;\n\t\t\tthis.resetSolver();\n\t\t}\n\t}\n\tgetCurrentPosition(): number {\n\t\treturn this.currentPosition;\n\t}\n}\n\nfunction solveSpring(\n\tfrom: number,\n\tvelocity: number,\n\tto: number,\n\tdelay: Seconds = 0,\n\tparams?: Partial<SpringParams>,\n): (t: Seconds) => number {\n\tconst soft = params?.soft ?? false;\n\tconst stiffness = params?.stiffness ?? 100;\n\tconst damping = params?.damping ?? 10;\n\tconst mass = params?.mass ?? 1;\n\tconst delta = to - from;\n\tif (soft || 1.0 <= damping / (2.0 * Math.sqrt(stiffness * mass))) {\n\t\tconst angular_frequency = -Math.sqrt(stiffness / mass);\n\t\tconst leftover = -angular_frequency * delta - velocity;\n\t\treturn (t: Seconds) => {\n\t\t\tt -= delay;\n\t\t\tif (t < 0) return from;\n\t\t\treturn to - (delta + t * leftover) * Math.E ** (t * angular_frequency);\n\t\t};\n\t}\n\tconst damping_frequency = Math.sqrt(4.0 * mass * stiffness - damping ** 2.0);\n\tconst leftover =\n\t\t(damping * delta - 2.0 * mass * velocity) / damping_frequency;\n\tconst dfm = (0.5 * damping_frequency) / mass;\n\tconst dm = -(0.5 * damping) / mass;\n\treturn (t: Seconds) => {\n\t\tt -= delay;\n\t\tif (t < 0) return from;\n\t\treturn (\n\t\t\tto -\n\t\t\t(Math.cos(t * dfm) * delta + Math.sin(t * dfm) * leftover) *\n\t\t\t\tMath.E ** (t * dm)\n\t\t);\n\t};\n}\n","import type {\n\tBottomLine,\n\tBottomLineTransforms,\n} from \"#lyric/base/bottom-line.ts\";\nimport type { LyricPlayerBase } from \"#lyric/base/index.ts\";\nimport styles from \"#styles/lyric-player.module.css\";\nimport { Spring } from \"#utils/spring.ts\";\nimport { Duration } from \"#utils/time.ts\";\n\n/**\n * 底栏组件的 DOM 实现\n *\n * 一个始终位于歌词底部的空白容器元素,外部可经由播放器的\n * getBottomLineElement 获取元素并添加歌曲创作者等内容\n */\nexport class BottomLineEl implements BottomLine {\n\tprivate element: HTMLElement = document.createElement(\"div\");\n\tprivate contentElement: HTMLElement = document.createElement(\"div\");\n\tprivate top = 0;\n\tprivate isFocused = false;\n\tprivate blur = 0;\n\n\tprivate lastTransformStyle = \"\";\n\tprivate lastFilterStyle = \"\";\n\n\treadonly lineTransforms: BottomLineTransforms = {\n\t\tposY: new Spring(0),\n\t};\n\n\t/**\n\t * 底栏当前测量得到的尺寸\n\t *\n\t * 由播放器的 ResizeObserver 回调写入\n\t */\n\tpublic lineSize: [number, number] = [0, 0];\n\n\tconstructor(private lyricPlayer: LyricPlayerBase) {\n\t\tthis.element.setAttribute(\n\t\t\t\"class\",\n\t\t\t`${styles.lyricLineWrapper} ${styles.bottomLineWrapper}`,\n\t\t);\n\t\tthis.contentElement.setAttribute(\n\t\t\t\"class\",\n\t\t\t`${styles.lyricLine} ${styles.bottomLine}`,\n\t\t);\n\t\tthis.contentElement.dataset.bottomLine = \"true\";\n\t\tthis.element.appendChild(this.contentElement);\n\t\tthis.rebuildStyle();\n\t}\n\n\tpublic getElement(): HTMLElement {\n\t\treturn this.element;\n\t}\n\n\tpublic getContentElement(): HTMLElement {\n\t\treturn this.contentElement;\n\t}\n\n\tpublic resetPosition(): void {\n\t\tthis.lineTransforms.posY.setPosition(window.innerHeight * 2);\n\t\tthis.rebuildStyle();\n\t}\n\n\t/**\n\t * 设置底栏是否处于聚焦状态\n\t *\n\t * 一般在歌曲播放完毕且底栏有内容时聚焦到底栏并设为 true\n\t */\n\tpublic setFocused(focused: boolean): void {\n\t\tif (this.isFocused !== focused) {\n\t\t\tthis.isFocused = focused;\n\t\t\tthis.contentElement.classList.toggle(styles.gradientMask, focused);\n\t\t\tif (focused) {\n\t\t\t\tthis.element.dataset.focused = \"true\";\n\t\t\t} else {\n\t\t\t\tdelete this.element.dataset.focused;\n\t\t\t}\n\t\t}\n\t}\n\n\tpublic setTransform(\n\t\ttop: number = this.top,\n\t\tblur = 0,\n\t\timmediate = false,\n\t\tdelay: Duration = Duration.ZERO,\n\t): void {\n\t\tthis.top = top;\n\n\t\tif (immediate || !this.lyricPlayer.getEnableSpring()) {\n\t\t\tthis.blur = Math.min(32, blur);\n\t\t\tif (immediate) this.element.classList.add(styles.tmpDisableTransition);\n\t\t\tthis.lineTransforms.posY.setPosition(top);\n\t\t\tthis.rebuildStyle();\n\t\t\tif (immediate)\n\t\t\t\trequestAnimationFrame(() => {\n\t\t\t\t\tthis.element.classList.remove(styles.tmpDisableTransition);\n\t\t\t\t});\n\t\t} else {\n\t\t\tthis.blur = Math.min(5, blur);\n\t\t\tthis.lineTransforms.posY.setTargetPosition(top, delay);\n\t\t}\n\t}\n\n\t/**\n\t * 逐帧推进弹簧动画并应用样式\n\t * @param delta 距离上一次调用的时长\n\t */\n\tpublic update(delta: Duration = Duration.ZERO): void {\n\t\tif (!this.lyricPlayer.getEnableSpring()) return;\n\t\tthis.lineTransforms.posY.update(delta);\n\t\tthis.rebuildStyle();\n\t}\n\n\t/**\n\t * 将弹簧当前位置与模糊值写入内联样式\n\t */\n\tprivate rebuildStyle(): void {\n\t\tconst style = this.element.style;\n\n\t\tconst posY = this.lineTransforms.posY.getCurrentPosition().toFixed(2);\n\t\tconst transformStr = `translate(0px, ${posY}px)`;\n\n\t\tif (this.lastTransformStyle !== transformStr) {\n\t\t\tthis.lastTransformStyle = transformStr;\n\t\t\tstyle.transform = transformStr;\n\t\t}\n\n\t\tconst blurVal = Math.min(5, this.blur);\n\t\tconst filterStr = blurVal > 0.01 ? `blur(${blurVal.toFixed(2)}px)` : \"none\";\n\t\tif (this.lastFilterStyle !== filterStr) {\n\t\t\tthis.lastFilterStyle = filterStr;\n\t\t\tstyle.filter = filterStr;\n\t\t}\n\t}\n\n\tpublic dispose(): void {\n\t\tthis.element.remove();\n\t}\n}\n","import bezier from \"bezier-easing\";\nimport type { Disposable } from \"#interfaces\";\nimport { clamp01 } from \"#utils/clamp.ts\";\nimport { Spring } from \"#utils/spring.ts\";\nimport { Duration, MediaTime } from \"#utils/time.ts\";\n\n//#region 类型定义\n/**\n * 间奏点在特定时刻的渲染快照\n */\nexport interface InterludeDotsSnapshot {\n\t/**\n\t * 动画是否仍处于活跃状态\n\t */\n\treadonly isActive: boolean;\n\n\t/**\n\t * 三颗圆点各自的不透明度\n\t */\n\treadonly dotOpacities: readonly [number, number, number];\n\n\t/**\n\t * 容器缩放值\n\t */\n\treadonly scale: number;\n\n\t/**\n\t * 容器整体不透明度\n\t */\n\treadonly opacity: number;\n}\n\ntype Mutable<T> = {\n\t-readonly [P in keyof T]: T[P];\n};\n\n/**\n * 间奏点演出的生命周期阶段\n * - `idle`: 无演出,不推进时钟也不渲染\n * - `performing`: 演出进行中,媒体时钟随帧间隔推进\n * - `fading`: 淡出收尾,媒体时钟冻结,仅容器不透明度继续衰减\n */\ntype InterludePhase = \"idle\" | \"performing\" | \"fading\";\n\n/**\n * 演出进行中的编排方式\n *\n * 仅在阶段为 `performing` 期间有意义\n * - `breathe`: 完整呼吸循环与三段式点亮\n * - `fallback-hold`: 主体时长不足 `FALLBACK_HOLD_THRESHOLD_MS`(3s)时降级为进退场与常态高亮\n */\ntype PerformingMode = \"breathe\" | \"fallback-hold\";\n\nconst DOT3_TRAILING_MS = 750;\nconst EXIT_PHASE1_MS = 750;\nconst EXIT_PHASE2_MS = 250;\nconst EXIT_TOTAL_MS = EXIT_PHASE1_MS + EXIT_PHASE2_MS;\nconst EXIT_FADE_MS = 250;\nconst DISMISS_FADE_MS = 150;\n\n/**\n * 非前奏或 Seek 时的入场延迟\n *\n * 用于给歌词行上移或跳转排版腾出视觉缓冲时间\n */\nconst ENTER_HOLD_MS = 500;\n\nconst ENTER_FADE_MS = 180;\nconst DOT_ENTER_FADE_MS = 750;\nconst DOT_ENTER_STAGGER_MS = 80;\n/**\n * 三颗圆点错峰完全淡入所需的时长 (80 * 2 + 750 = 910ms)\n */\nconst DOT_ENTER_TOTAL_MS = (3 - 1) * DOT_ENTER_STAGGER_MS + DOT_ENTER_FADE_MS;\n\nconst BREATHE_BASE_PERIOD_MS = 4000;\nconst FALLBACK_HOLD_THRESHOLD_MS = 3000;\nconst BREATHE_MAX_SCALE = 1.25;\nconst BREATHE_MIN_SCALE = 0.4;\n\nconst DOT_INACTIVE_OPACITY = 0.2;\nconst DOT_ACTIVE_OPACITY = 0.9;\nconst DOT_COUNT = 3;\n\nconst lightingEasing = bezier(0.56, 0.01, 0.45, 1);\nconst enterFadeEasing = bezier(0.59, 0.02, 0.07, 1);\nconst exitPhase1Easing = bezier(0.14, 0.06, 0.25, 1);\nconst exitPhase2Easing = bezier(0.29, 0.03, 1, 0.38);\nconst exitFadeEasing = bezier(0.43, 0.08, 0.83, 0.31);\n\n/**\n * 间奏消失时派发的合成快照,用于让子类收起渲染物\n */\nconst HIDDEN_SNAPSHOT: Readonly<InterludeDotsSnapshot> = {\n\tisActive: false,\n\tdotOpacities: [0, 0, 0],\n\tscale: 1,\n\topacity: 0,\n};\n//#endregion\n\nexport abstract class InterludeDotsBase implements Disposable {\n\t//#region 演出状态\n\tprivate left = 0;\n\tprivate top = 0;\n\tpublic readonly posY: Spring = new Spring(0);\n\t/**\n\t * 下一次设置变换位置时是否直接吸附到目标位置\n\t *\n\t * 演出重建或位置跳变时新旧坐标可能相距很远,走弹簧会看到间奏点从旧位置滑入的残影\n\t */\n\tprivate shouldSnapPosY = true;\n\n\tprivate currentTime: MediaTime = MediaTime.ZERO;\n\tprivate playing = true;\n\tprivate phase: InterludePhase = \"idle\";\n\tprivate mode: PerformingMode = \"breathe\";\n\tprivate fadeElapsedMs = 0;\n\tprivate fadeInitialOpacity = 0;\n\tprivate startTime: MediaTime = MediaTime.ZERO;\n\tprivate endTime: MediaTime = MediaTime.ZERO;\n\tprivate anchorTime: MediaTime = MediaTime.ZERO;\n\n\tprivate delayEndMs = 0;\n\tprivate bodyEndMs = 0;\n\tprivate totalEndMs = 0;\n\n\tprivate breathePeriodMs = BREATHE_BASE_PERIOD_MS;\n\tprivate segmentMs = 0;\n\tprivate dot3DurationMs = 0;\n\tprivate dot3Target = 0;\n\n\tprivate readonly mutDotOpacities: [number, number, number] = [0, 0, 0];\n\n\tprivate readonly snapshot: Mutable<InterludeDotsSnapshot> = {\n\t\tisActive: true,\n\t\tdotOpacities: this.mutDotOpacities,\n\t\tscale: 1,\n\t\topacity: 0,\n\t};\n\t//#endregion\n\n\t//#region 外部 API\n\t/**\n\t * 设置间奏区间并锚定演出时间\n\t *\n\t * @param interlude 间奏起止时间\n\t * @param currentTime 当前播放时间,用于把演出重锚到该时刻;未传入时使用间奏起点\n\t * @param forceReset 是否强制重建演出,如跳转播放进度或重建歌词视图时\n\t * @param anchorLineIndex 间奏锚定的歌词行索引\n\t * @returns 本次间奏是否有足够时长显示间奏点\n\t */\n\tpublic setInterlude(\n\t\tinterlude: [MediaTime, MediaTime],\n\t\tcurrentTime?: MediaTime,\n\t\tforceReset = false,\n\t\tanchorLineIndex = 0,\n\t): boolean {\n\t\tconst [startTime, endTime] = interlude;\n\t\tconst isSameInterlude =\n\t\t\tthis.startTime === startTime && this.endTime === endTime;\n\n\t\t// 非 Seek、仍处于同一间奏区间且未处于淡出过程中时,直接返回当前展示状态\n\t\tif (!forceReset && isSameInterlude && this.phase !== \"fading\") {\n\t\t\treturn this.phase === \"performing\";\n\t\t}\n\n\t\tthis.cancelFadeOut();\n\t\tthis.startTime = startTime;\n\t\tthis.endTime = endTime;\n\t\tthis.currentTime = currentTime ?? startTime;\n\n\t\t// 确定时间锚点与入场延迟\n\t\tif (forceReset) {\n\t\t\tthis.anchorTime = this.currentTime;\n\t\t\tthis.delayEndMs = ENTER_HOLD_MS;\n\t\t} else {\n\t\t\tthis.anchorTime = startTime;\n\t\t\tthis.delayEndMs = anchorLineIndex === -1 ? 0 : ENTER_HOLD_MS;\n\t\t}\n\n\t\t// 计算剩余可用时长\n\t\tconst remainingMs = Math.max(\n\t\t\t0,\n\t\t\tDuration.asMillis(MediaTime.since(endTime, this.anchorTime)),\n\t\t);\n\t\tconst bodyMs = remainingMs - this.delayEndMs - EXIT_TOTAL_MS;\n\n\t\tif (bodyMs < DOT_ENTER_TOTAL_MS) {\n\t\t\t// 连进退场都不足以支撑,直接隐藏\n\t\t\tthis.hidePerformance();\n\t\t\treturn false;\n\t\t}\n\n\t\tthis.bodyEndMs = this.delayEndMs + bodyMs;\n\t\tthis.totalEndMs = this.bodyEndMs + EXIT_TOTAL_MS;\n\n\t\tlet mode: PerformingMode;\n\t\tif (bodyMs < FALLBACK_HOLD_THRESHOLD_MS) {\n\t\t\t// 降级为进退场与常态高亮\n\t\t\tmode = \"fallback-hold\";\n\t\t\tthis.dot3Target = 1.0;\n\t\t} else {\n\t\t\t// 正常播放,基于 bodyMs 重新编排\n\t\t\tmode = \"breathe\";\n\t\t\tconst breatheCycles = Math.max(\n\t\t\t\t1,\n\t\t\t\tMath.floor(bodyMs / BREATHE_BASE_PERIOD_MS),\n\t\t\t);\n\t\t\tthis.breathePeriodMs = bodyMs / breatheCycles;\n\t\t\tthis.segmentMs = Math.round((bodyMs + DOT3_TRAILING_MS) / DOT_COUNT);\n\t\t\tthis.dot3DurationMs = bodyMs - this.segmentMs * 2;\n\t\t\tthis.dot3Target = this.dot3DurationMs / this.segmentMs;\n\t\t}\n\n\t\tthis.enterPerforming(mode);\n\n\t\treturn true;\n\t}\n\n\t/**\n\t * 清空间奏区间并终止当前演出\n\t *\n\t * 与 {@link dismiss} 的区别在于本方法会一并抹去区间状态,\n\t * 使此后重新进入同一间奏区间时能够重新演出\n\t *\n\t * @param immediate 是否立即隐藏而非淡出\n\t */\n\tpublic clearInterlude(immediate = false): void {\n\t\tthis.startTime = MediaTime.ZERO;\n\t\tthis.endTime = MediaTime.ZERO;\n\t\tthis.dismiss(immediate);\n\t}\n\n\t/**\n\t * 结束间奏点演出,默认使用 150ms 淡出\n\t * @param immediate 是否立即隐藏\n\t */\n\tpublic dismiss(immediate = false): void {\n\t\tif (this.phase === \"idle\") {\n\t\t\treturn;\n\t\t}\n\n\t\tif (immediate || !this.playing) {\n\t\t\tthis.cancelFadeOut();\n\t\t\tthis.hidePerformance();\n\t\t\treturn;\n\t\t}\n\n\t\tif (this.phase === \"fading\") {\n\t\t\treturn;\n\t\t}\n\n\t\tif (this.snapshot.opacity <= 0) {\n\t\t\tthis.hidePerformance();\n\t\t\treturn;\n\t\t}\n\n\t\tthis.enterFading();\n\t}\n\n\t/**\n\t * 设置间奏点的变换位置并立即刷新一次\n\t * @param left 横向位置\n\t * @param top 纵向位置\n\t * @param immediate 是否绕过弹簧直接跳转到目标位置,用于触摸拖动等需要跟手的场景\n\t */\n\tpublic setTransform(\n\t\tleft: number = this.left,\n\t\ttop: number = this.top,\n\t\timmediate = false,\n\t): void {\n\t\tthis.left = left;\n\t\tthis.top = top;\n\n\t\t// 演出进行中或正在淡出时允许弹簧平滑移动\n\t\tconst shouldAnimate =\n\t\t\t!immediate && this.phase !== \"idle\" && !this.shouldSnapPosY;\n\n\t\tif (shouldAnimate) {\n\t\t\tthis.posY.setTargetPosition(top);\n\t\t} else {\n\t\t\tthis.shouldSnapPosY = false;\n\t\t\tthis.posY.setPosition(top);\n\t\t}\n\n\t\tthis.update();\n\t}\n\n\tpublic pause(): void {\n\t\tthis.playing = false;\n\t\tif (this.phase === \"fading\") {\n\t\t\tthis.hidePerformance();\n\t\t}\n\t}\n\n\tpublic resume(): void {\n\t\tthis.playing = true;\n\t}\n\n\t/**\n\t * 把演出时钟对齐到指定的媒体时间,由宿主每次推送播放进度时调用\n\t */\n\tpublic syncClock(time: MediaTime): void {\n\t\tthis.currentTime = time;\n\t}\n\n\t/**\n\t * 逐帧推进演出并把当前帧交给子类渲染\n\t * @param delta 距离上一次调用的物理时长\n\t */\n\tpublic update(delta: Duration = Duration.ZERO): void {\n\t\tif (this.phase === \"idle\") return;\n\n\t\tif (this.phase === \"fading\") {\n\t\t\tthis.updateFadeOut(delta);\n\t\t\treturn;\n\t\t}\n\n\t\tif (this.playing) {\n\t\t\tthis.currentTime = MediaTime.add(this.currentTime, delta);\n\t\t}\n\n\t\tconst elapsed = Duration.max(\n\t\t\tDuration.ZERO,\n\t\t\tMediaTime.since(this.currentTime, this.anchorTime),\n\t\t);\n\n\t\tconst snapshot = this.resolveSnapshot(elapsed);\n\t\tthis.posY.update(delta);\n\t\tthis.render(snapshot, this.left, this.posY.getCurrentPosition());\n\n\t\tif (!snapshot.isActive) {\n\t\t\tthis.enterIdle();\n\t\t}\n\t}\n\n\t/**\n\t * 释放演出状态\n\t */\n\tpublic dispose(): void {\n\t\tthis.dismiss(true);\n\t}\n\t//#endregion\n\n\t//#region 子类契约\n\t/**\n\t * 由子类实现的渲染逻辑\n\t *\n\t * 快照对象会被基类逐帧复用,必须在当前帧内消费完毕,不得保留其引用\n\t *\n\t * `isActive` 为 `false` 时表示演出已经结束或取消,应当隐藏渲染物\n\t *\n\t * @param snapshot 当前帧的视觉状态\n\t * @param left 由 {@link setTransform} 设置的横向位置\n\t * @param top 由 {@link setTransform} 设置的纵向位置经 {@link posY} 平滑后的坐标\n\t */\n\tprotected abstract render(\n\t\tsnapshot: Readonly<InterludeDotsSnapshot>,\n\t\tleft: number,\n\t\ttop: number,\n\t): void;\n\t//#endregion\n\n\t//#region 状态转移\n\t/**\n\t * 进入演出阶段并确定编排方式\n\t *\n\t * 演出重建后的第一帧位置由外部重新给出,不参与弹簧过渡,\n\t * 因此一并重置 {@link shouldSnapPosY}\n\t */\n\tprivate enterPerforming(mode: PerformingMode): void {\n\t\tthis.mode = mode;\n\t\tthis.phase = \"performing\";\n\t\t// 演出重建后的第一帧位置由外部重新给出,不参与弹簧过渡,因此一并重置 shouldSnapPosY\n\t\tthis.shouldSnapPosY = true;\n\t}\n\n\t/**\n\t * 进入淡出阶段,冻结当前帧的不透明度作为衰减起点\n\t */\n\tprivate enterFading(): void {\n\t\tthis.fadeElapsedMs = 0;\n\t\tthis.fadeInitialOpacity = this.snapshot.opacity;\n\t\tthis.phase = \"fading\";\n\t}\n\n\t/**\n\t * 结束演出,回到既不推进时钟也不渲染的静止状态\n\t */\n\tprivate enterIdle(): void {\n\t\tthis.phase = \"idle\";\n\t}\n\n\t/**\n\t * 取消正在进行的淡出\n\t *\n\t * 只清掉淡出阶段,演出阶段保持原样,随后的收尾仍需据此判断\n\t * 是否有可见内容要派发隐藏快照\n\t */\n\tprivate cancelFadeOut(): void {\n\t\tif (this.phase === \"fading\") {\n\t\t\tthis.enterIdle();\n\t\t}\n\t}\n\n\t/**\n\t * 演出被取消时立即隐藏渲染物并清空演出状态\n\t */\n\tprivate hidePerformance(): void {\n\t\tconst wasActive = this.phase !== \"idle\";\n\t\tthis.enterIdle();\n\n\t\tif (wasActive) {\n\t\t\tthis.render(HIDDEN_SNAPSHOT, this.left, this.posY.getCurrentPosition());\n\t\t}\n\t}\n\t//#endregion\n\n\t//#region 时间线推导\n\n\t/**\n\t * 写入三颗圆点当前帧的不透明度\n\t *\n\t * 最终不透明度由点亮分数映射的透明度与各圆点的错峰入场系数相乘得到\n\t *\n\t * @param internalMs 距演出开始的经过时间\n\t * @param fractions 三颗圆点各自的点亮分数(0~1)\n\t */\n\tprivate writeDotOpacities(\n\t\tinternalMs: number,\n\t\tfractions: readonly [number, number, number],\n\t): void {\n\t\tthis.mutDotOpacities[0] =\n\t\t\tdotOpacity(fractions[0]) * dotEnterAlpha(0, internalMs);\n\t\tthis.mutDotOpacities[1] =\n\t\t\tdotOpacity(fractions[1]) * dotEnterAlpha(1, internalMs);\n\t\tthis.mutDotOpacities[2] =\n\t\t\tdotOpacity(fractions[2]) * dotEnterAlpha(2, internalMs);\n\t}\n\n\t/**\n\t * 物理淡出步进器\n\t */\n\tprivate updateFadeOut(delta: Duration): void {\n\t\tthis.fadeElapsedMs += Duration.asMillis(delta);\n\t\tconst progress = clamp01(this.fadeElapsedMs / DISMISS_FADE_MS);\n\n\t\tif (progress >= 1) {\n\t\t\tthis.hidePerformance();\n\t\t\treturn;\n\t\t}\n\n\t\t// 保持进入淡出瞬间已冻结的 scale 与 dotOpacities,仅对 opacity 执行缓出衰减\n\t\tthis.snapshot.opacity =\n\t\t\tthis.fadeInitialOpacity * (1 - exitFadeEasing(progress));\n\t\tthis.snapshot.isActive = true;\n\n\t\tthis.posY.update(delta);\n\t\tthis.render(this.snapshot, this.left, this.posY.getCurrentPosition());\n\t}\n\n\t/**\n\t * 按经过时间求出该时刻的视觉状态\n\t *\n\t * @remarks 返回的快照对象是内部复用的同一引用,必须在当前帧内消费完毕\n\t * @param elapsed 距离本次演出时间锚点的经过时间\n\t */\n\tprivate resolveSnapshot(elapsed: Duration): Readonly<InterludeDotsSnapshot> {\n\t\tconst elapsedMs = Duration.asMillis(elapsed);\n\n\t\tif (elapsedMs >= this.totalEndMs) {\n\t\t\tthis.snapshot.isActive = false;\n\t\t\tthis.snapshot.scale = 1;\n\t\t\tthis.snapshot.opacity = 0;\n\t\t\tthis.mutDotOpacities[0] = 0;\n\t\t\tthis.mutDotOpacities[1] = 0;\n\t\t\tthis.mutDotOpacities[2] = 0;\n\t\t\treturn this.snapshot;\n\t\t}\n\n\t\tthis.snapshot.isActive = true;\n\n\t\t// 入场延迟等待阶段:处于占位但完全透明\n\t\tif (elapsedMs < this.delayEndMs) {\n\t\t\tthis.snapshot.opacity = 0;\n\t\t\tthis.snapshot.scale = 1;\n\t\t\tthis.mutDotOpacities[0] = 0;\n\t\t\tthis.mutDotOpacities[1] = 0;\n\t\t\tthis.mutDotOpacities[2] = 0;\n\t\t\treturn this.snapshot;\n\t\t}\n\n\t\tconst internalMs = elapsedMs - this.delayEndMs;\n\t\tconst fractionAt = (startDelay: number, duration: number, target: number) =>\n\t\t\tcomputeDotFraction(startDelay, duration, internalMs, target);\n\n\t\t/*\n\t\t * 退场阶段 [bodyEndMs, totalEndMs)\n\t\t *\n\t\t * 退场分为两个阶段:\n\t\t * 1. 快速放大以蓄力\n\t\t * 2. 快速缩小并渐隐\n\t\t *\n\t\t * 第三颗圆点也在此补亮剩余的亮度\n\t\t */\n\t\tif (elapsedMs >= this.bodyEndMs) {\n\t\t\tconst exitElapsedMs = elapsedMs - this.bodyEndMs;\n\n\t\t\t// 在最后 EXIT_FADE_MS 执行退场渐隐,蓄力阶段保持不透明\n\t\t\tconst fadeT = clamp01(\n\t\t\t\t(exitElapsedMs - (EXIT_TOTAL_MS - EXIT_FADE_MS)) / EXIT_FADE_MS,\n\t\t\t);\n\t\t\tthis.snapshot.opacity =\n\t\t\t\tenterOpacity(internalMs) * (1 - exitFadeEasing(fadeT));\n\n\t\t\t// 放大蓄力(1.0 -> BREATHE_MAX_SCALE)\n\t\t\tif (exitElapsedMs < EXIT_PHASE1_MS) {\n\t\t\t\tthis.snapshot.scale =\n\t\t\t\t\t1 +\n\t\t\t\t\texitPhase1Easing(exitElapsedMs / EXIT_PHASE1_MS) *\n\t\t\t\t\t\t(BREATHE_MAX_SCALE - 1);\n\t\t\t} else {\n\t\t\t\t// 快速缩小(BREATHE_MAX_SCALE -> BREATHE_MIN_SCALE)\n\t\t\t\tconst phase2T = clamp01(\n\t\t\t\t\t(exitElapsedMs - EXIT_PHASE1_MS) / EXIT_PHASE2_MS,\n\t\t\t\t);\n\t\t\t\tthis.snapshot.scale =\n\t\t\t\t\tBREATHE_MAX_SCALE -\n\t\t\t\t\texitPhase2Easing(phase2T) * (BREATHE_MAX_SCALE - BREATHE_MIN_SCALE);\n\t\t\t}\n\n\t\t\t// breath 下前两颗圆点在 body 结束时已点满,第三颗以 750ms 补齐剩余亮度;\n\t\t\t// fallback-hold 下 dot3Target 为 1.0,计算自然退化为恒定全亮\n\t\t\tconst trailing = clamp01(exitElapsedMs / DOT3_TRAILING_MS);\n\n\t\t\tthis.writeDotOpacities(internalMs, [\n\t\t\t\t1,\n\t\t\t\t1,\n\t\t\t\tthis.dot3Target + (1 - this.dot3Target) * trailing,\n\t\t\t]);\n\n\t\t\treturn this.snapshot;\n\t\t}\n\n\t\t/*\n\t\t * 主演出阶段 [delayEndMs, bodyEndMs)\n\t\t *\n\t\t * 入场分为两个部分,同时与容器周期呼吸缩放并行推进:\n\t\t * 1. 整个容器以 180ms 渐入\n\t\t * 2. 三个圆点错峰 750ms 依次点亮\n\t\t */\n\t\tthis.snapshot.opacity = enterOpacity(internalMs);\n\n\t\tif (this.mode === \"fallback-hold\") {\n\t\t\t// 缩放恒为 1.0,三颗圆点各自保留 80ms 错峰淡入至全亮,随后维持全亮\n\t\t\tthis.snapshot.scale = 1;\n\t\t\tthis.writeDotOpacities(internalMs, [1, 1, 1]);\n\t\t\treturn this.snapshot;\n\t\t}\n\n\t\tconst cycleT = (internalMs % this.breathePeriodMs) / this.breathePeriodMs;\n\t\tconst progress = breathingProgress(cycleT);\n\t\tthis.snapshot.scale =\n\t\t\tprogress <= 0.5\n\t\t\t\t? 1 + (progress / 0.5) * (BREATHE_MAX_SCALE - 1)\n\t\t\t\t: BREATHE_MAX_SCALE -\n\t\t\t\t\t((progress - 0.5) / 0.5) * (BREATHE_MAX_SCALE - 1);\n\n\t\t// 三颗圆点依次开始点亮,前两颗全亮,第三颗只点亮部分,剩余由退场动画进行补充\n\t\tthis.writeDotOpacities(internalMs, [\n\t\t\tfractionAt(0, this.segmentMs, 1),\n\t\t\tfractionAt(this.segmentMs, this.segmentMs, 1),\n\t\t\tfractionAt(this.segmentMs * 2, this.dot3DurationMs, this.dot3Target),\n\t\t]);\n\n\t\treturn this.snapshot;\n\t}\n\t//#endregion\n}\n\n//#region 辅助函数\n/**\n * 容器呼吸式缩放的曲线\n */\nfunction breathingProgress(t: number): number {\n\tif (t <= 0) return 0;\n\tif (t >= 1) return 1;\n\tconst angle = 4.0 * Math.PI * t;\n\tconst s = Math.sin(angle);\n\tconst c = Math.cos(angle);\n\treturn t - 0.084 * s + 0.008 * (1 - c) + 0.0046 * s * (c - s);\n}\n\n/**\n * 将点亮分数(0~1)映射为圆点透明度,在未点亮与全亮之间线性插值\n */\nfunction dotOpacity(fraction: number): number {\n\treturn (\n\t\tDOT_INACTIVE_OPACITY +\n\t\t(DOT_ACTIVE_OPACITY - DOT_INACTIVE_OPACITY) * clamp01(fraction)\n\t);\n}\n\n/**\n * 容器行的入场淡入系数\n *\n * 演出开始后的前 `ENTER_FADE_MS` 内从 0 升到 1,之后恒为 1\n */\nfunction enterOpacity(internalMs: number): number {\n\treturn enterFadeEasing(clamp01(internalMs / ENTER_FADE_MS));\n}\n\n/**\n * 某颗圆点的入场淡入系数\n *\n * 每颗圆点使用 `DOT_ENTER_STAGGER_MS` 错峰淡入,各自在 `DOT_ENTER_FADE_MS`\n * 内从 0 升到 1\n *\n * @param index 圆点序号(0 起),决定错峰延迟\n * @param internalMs 距演出开始的经过时间\n */\nfunction dotEnterAlpha(index: number, internalMs: number): number {\n\tconst t = clamp01(\n\t\t(internalMs - index * DOT_ENTER_STAGGER_MS) / DOT_ENTER_FADE_MS,\n\t);\n\treturn t * t;\n}\n\n/**\n * 计算单颗圆点在给定时刻的点亮分数\n *\n * @param startDelay 该圆点的开始延迟(依次为 0、segment、2 * segment)\n * @param duration 该圆点的点亮时长(圆点 3 应短于前两颗)\n * @param internalMs 距演出开始的经过时间\n * @param target 点亮完成目标\n */\nfunction computeDotFraction(\n\tstartDelay: number,\n\tduration: number,\n\tinternalMs: number,\n\ttarget: number,\n): number {\n\tif (internalMs <= startDelay) return 0;\n\tconst localT = (internalMs - startDelay) / duration;\n\treturn lightingEasing(clamp01(localT)) * target;\n}\n//#endregion\n","import type { HasElement } from \"#interfaces\";\nimport {\n\tInterludeDotsBase,\n\ttype InterludeDotsSnapshot,\n} from \"#lyric/base/interlude-dots.ts\";\nimport styles from \"#styles/lyric-player.module.css\";\n\nexport class InterludeDotsEl extends InterludeDotsBase implements HasElement {\n\tprivate element = document.createElement(\"div\");\n\tprivate dot0 = document.createElement(\"span\");\n\tprivate dot1 = document.createElement(\"span\");\n\tprivate dot2 = document.createElement(\"span\");\n\n\tprivate lastStyle = \"\";\n\n\tconstructor() {\n\t\tsuper();\n\n\t\tthis.element.className = styles.interludeDots;\n\t\tthis.element.appendChild(this.dot0);\n\t\tthis.element.appendChild(this.dot1);\n\t\tthis.element.appendChild(this.dot2);\n\n\t\tthis.element.style.opacity = \"0\";\n\t}\n\n\tpublic getElement(): HTMLElement {\n\t\treturn this.element;\n\t}\n\n\tprotected override render(\n\t\tsnapshot: Readonly<InterludeDotsSnapshot>,\n\t\tleft: number,\n\t\ttop: number,\n\t): void {\n\t\tconst curStyle =\n\t\t\t`transform:translate(${left.toFixed(2)}px, ${top.toFixed(2)}px)` +\n\t\t\t` scale(${snapshot.scale.toFixed(4)});opacity:${snapshot.opacity.toFixed(3)}`;\n\n\t\tthis.dot0.style.opacity = snapshot.dotOpacities[0].toFixed(3);\n\t\tthis.dot1.style.opacity = snapshot.dotOpacities[1].toFixed(3);\n\t\tthis.dot2.style.opacity = snapshot.dotOpacities[2].toFixed(3);\n\n\t\tif (this.lastStyle !== curStyle) {\n\t\t\tthis.element.setAttribute(\"style\", curStyle);\n\t\t\tthis.lastStyle = curStyle;\n\t\t}\n\t}\n\n\tpublic override dispose(): void {\n\t\tsuper.dispose();\n\t\tthis.element.remove();\n\t}\n}\n","import type { Disposable } from \"#interfaces\";\nimport { Spring } from \"#utils/spring.ts\";\nimport { Duration, MediaTime } from \"#utils/time.ts\";\nimport { LyricLineRenderMode } from \"./consts.ts\";\nimport type { LyricLineBase } from \"./line.ts\";\n\nexport interface LyricPlayerFlags {\n\tgetEnableSpring(): boolean;\n\tgetEnableScale(): boolean;\n\tgetIsPlaying(): boolean;\n\tgetAlwaysPostpositionBackground(): boolean;\n}\n\nexport abstract class LyricLineGroupBase<\n\tT extends LyricLineBase = LyricLineBase,\n> implements Disposable\n{\n\tprotected abstract readonly lyricPlayer: LyricPlayerFlags;\n\n\tpublic posY: Spring = new Spring(0);\n\tpublic bgSlideY: Spring = new Spring(-80);\n\tpublic top = 0;\n\tpublic delay: Duration = Duration.ZERO;\n\n\tpublic isActive = false;\n\tpublic opacity = 1;\n\tpublic blur = 0;\n\n\tpublic isBgFirst = false;\n\n\tprotected isUiDirty = true;\n\n\tconstructor(\n\t\tpublic mainLine: T,\n\t\tpublic bgLine?: T | undefined,\n\t) {}\n\n\tget startTime(): MediaTime {\n\t\t// 优化歌词时 `syncMainAndBackgroundLines` 已经把时间同步好了,直接读取主歌词的即可\n\t\t// 要是用户关掉了这个优化,我们认为在这种情况下主歌词和背景人声显示不同步是符合用户预期的\n\t\treturn MediaTime.fromMillis(this.mainLine.getLine().startTime);\n\t}\n\n\tget endTime(): MediaTime {\n\t\treturn MediaTime.fromMillis(this.mainLine.getLine().endTime);\n\t}\n\n\tonLineSizeChange(size: [number, number]): void {\n\t\tthis.mainLine.onLineSizeChange(size);\n\t\tthis.bgLine?.onLineSizeChange(size);\n\t}\n\n\tonBgSizeChange?(size: [number, number]): void;\n\n\tabstract getElement(): Element;\n\n\tsetTransform(\n\t\ttop: number,\n\t\timmediate: boolean,\n\t\tdelay: Duration,\n\t\tisActive: boolean,\n\t\topacity: number,\n\t\tblur: number,\n\t): void {\n\t\tthis.top = top;\n\t\tthis.delay = delay;\n\t\tthis.isActive = isActive;\n\t\tthis.opacity = opacity;\n\t\tthis.blur = blur;\n\n\t\tthis.setLineTransformations(delay);\n\n\t\tconst enableSpring = this.lyricPlayer.getEnableSpring();\n\t\tconst alwaysPostposition =\n\t\t\tthis.lyricPlayer.getAlwaysPostpositionBackground();\n\t\tconst shouldBgFirst = alwaysPostposition ? false : this.isBgFirst;\n\t\tconst hiddenSlideY = shouldBgFirst ? 80 : -80;\n\n\t\tconst isPlaying = this.lyricPlayer.getIsPlaying();\n\t\tconst targetBgSlideY = isActive || !isPlaying ? 0 : hiddenSlideY;\n\n\t\tif (immediate || !enableSpring) {\n\t\t\tthis.posY.setPosition(top);\n\t\t\tthis.bgSlideY.setPosition(targetBgSlideY);\n\t\t} else {\n\t\t\tthis.posY.setTargetPosition(top, delay);\n\t\t\tthis.bgSlideY.setTargetPosition(targetBgSlideY, delay);\n\t\t}\n\n\t\tthis.isUiDirty = true;\n\t}\n\n\tprivate setLineTransformations(delay: Duration) {\n\t\tconst enableScale = this.lyricPlayer.getEnableScale();\n\t\tconst isPlaying = this.lyricPlayer.getIsPlaying();\n\n\t\tconst renderMode = this.isActive\n\t\t\t? LyricLineRenderMode.GRADIENT\n\t\t\t: LyricLineRenderMode.SOLID;\n\n\t\tconst SCALE_ASPECT = enableScale ? 97 : 100;\n\t\tlet mainScale = 100;\n\t\tif (!this.isActive && isPlaying) {\n\t\t\tmainScale = SCALE_ASPECT;\n\t\t}\n\n\t\tthis.mainLine.setTransform(mainScale, 1, 0, delay, renderMode);\n\n\t\tlet bgScale = 100;\n\t\tif (!this.isActive && isPlaying) {\n\t\t\tbgScale = 75;\n\t\t}\n\t\tthis.bgLine?.setTransform(bgScale, 1, 0, delay, renderMode);\n\t}\n\n\tprotected abstract renderStyles(): void;\n\n\t/**\n\t * 根据当前动画位置判断歌词行是否处于渲染范围内\n\t *\n\t * @param includeOverscan 是否包含 overscan 渲染缓冲范围,默认包含;\n\t * 传入 false 时,仅判断歌词行是否在真实视口范围内\n\t */\n\tabstract isInRenderRange(includeOverscan?: boolean): boolean;\n\n\tupdate(delta: Duration = Duration.ZERO): void {\n\t\tif (this.lyricPlayer.getEnableSpring()) {\n\t\t\tconst posMoving = !this.posY.arrived();\n\t\t\tconst bgMoving = !this.bgSlideY.arrived();\n\t\t\tthis.posY.update(delta);\n\t\t\tthis.bgSlideY.update(delta);\n\n\t\t\tif (posMoving || bgMoving) {\n\t\t\t\tthis.isUiDirty = true;\n\t\t\t}\n\t\t}\n\n\t\tthis.mainLine.update(delta);\n\t\tthis.bgLine?.update(delta);\n\t}\n\n\tcommitChanges(): void {\n\t\tif (!this.isInRenderRange()) return;\n\t\tif (this.isUiDirty) {\n\t\t\tthis.renderStyles();\n\t\t\tthis.isUiDirty = false;\n\t\t}\n\t\tthis.mainLine.commitChanges();\n\t\tthis.bgLine?.commitChanges();\n\t}\n\n\trebuildAllLines(): void {\n\t\tthis.mainLine.rebuildElement();\n\t\tthis.bgLine?.rebuildElement();\n\t}\n\n\tenable(time?: number, shouldPlay?: boolean): void {\n\t\tthis.mainLine.enable(time, shouldPlay);\n\t\tthis.bgLine?.enable(time, shouldPlay);\n\t}\n\n\tdisable(): void {\n\t\tthis.mainLine.disable();\n\t\tthis.bgLine?.disable();\n\t}\n\n\tdispose(): void {\n\t\tthis.mainLine.dispose();\n\t\tthis.bgLine?.dispose();\n\t}\n}\n","import { LyricLineGroupBase } from \"#lyric/base/group.ts\";\nimport styles from \"#styles/lyric-player.module.css\";\nimport { clamp01 } from \"#utils/clamp.ts\";\nimport { Duration } from \"#utils/time.ts\";\nimport type { DomLyricPlayer } from \"./index.ts\";\nimport type { LyricLineEl } from \"./lyric-line.ts\";\n\nexport class LyricLineGroup extends LyricLineGroupBase<LyricLineEl> {\n\tpublic element: HTMLElement;\n\tpublic bgWrapper?: HTMLElement;\n\tprivate lastIsActive?: boolean;\n\n\tprivate lastBgHeight = 0;\n\tprivate lastBgIsHidden?: boolean;\n\tprivate lastYNum = -9999;\n\tprivate lastOpacityNum = -1;\n\tprivate lastBlurNum = -1;\n\tprivate lastBgSlideYNum = -9999;\n\n\tconstructor(\n\t\tpublic lyricPlayer: DomLyricPlayer,\n\t\tmainLine: LyricLineEl,\n\t) {\n\t\tsuper(mainLine);\n\t\tthis.element = document.createElement(\"div\");\n\t\tthis.element.className = styles.lyricLineWrapper;\n\n\t\tif (mainLine.getLine().isDuet) {\n\t\t\tthis.element.classList.add(styles.isDuetWrapper);\n\t\t}\n\n\t\tthis.element.appendChild(mainLine.getElement());\n\t\tthis.posY.setPosition(window.innerHeight * 2);\n\n\t\tlyricPlayer.resizeObserver.observe(this.element);\n\t}\n\n\tgetElement(): HTMLElement {\n\t\treturn this.element;\n\t}\n\n\tisInRenderRange(includeOverscan = true): boolean {\n\t\tconst top = this.posY.getCurrentPosition();\n\n\t\tconst index = this.lyricPlayer.currentLyricGroups.indexOf(this);\n\t\tconst height =\n\t\t\tindex !== -1\n\t\t\t\t? this.lyricPlayer.getLineHeight(index)\n\t\t\t\t: this.lyricPlayer.defaultLineHeight;\n\n\t\tconst viewportHeight = this.lyricPlayer.size[1];\n\t\tif (viewportHeight <= 0 || height <= 0) return false;\n\n\t\tconst overscan = includeOverscan ? this.lyricPlayer.getOverscanPx() : 0;\n\n\t\treturn top < viewportHeight + overscan && top + height > -overscan;\n\t}\n\n\tshow(): void {\n\t\tif (!this.element.parentElement) {\n\t\t\tconst playerEl = this.lyricPlayer.getElement();\n\t\t\tconst groups = this.lyricPlayer.currentLyricGroups;\n\t\t\tconst myIndex = groups.indexOf(this);\n\n\t\t\tlet referenceNode: HTMLElement | null = null;\n\t\t\tif (myIndex !== -1) {\n\t\t\t\tfor (let i = myIndex + 1; i < groups.length; i++) {\n\t\t\t\t\tif (groups[i].element.parentElement === playerEl) {\n\t\t\t\t\t\treferenceNode = groups[i].element;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tplayerEl.insertBefore(this.element, referenceNode);\n\n\t\t\tthis.lyricPlayer.resizeObserver.observe(this.element);\n\t\t\tif (this.bgWrapper) {\n\t\t\t\tthis.lyricPlayer.resizeObserver.observe(this.bgWrapper);\n\t\t\t}\n\t\t}\n\n\t\tthis.mainLine.show();\n\t\tthis.bgLine?.show();\n\t}\n\n\thide(): void {\n\t\tif (this.element.parentElement) {\n\t\t\tthis.lyricPlayer.resizeObserver.unobserve(this.element);\n\t\t\tif (this.bgWrapper) {\n\t\t\t\tthis.lyricPlayer.resizeObserver.unobserve(this.bgWrapper);\n\t\t\t}\n\t\t\tthis.element.remove();\n\t\t}\n\t}\n\n\toverride update(delta: Duration = Duration.ZERO): void {\n\t\tsuper.update(delta);\n\t}\n\n\toverride commitChanges(): void {\n\t\tif (this.isInRenderRange()) {\n\t\t\tthis.show();\n\t\t\tsuper.commitChanges();\n\t\t} else {\n\t\t\tthis.hide();\n\t\t}\n\t}\n\n\toverride onBgSizeChange(size: [number, number]): void {\n\t\tif (this.bgWrapper && this.lastBgHeight !== size[1]) {\n\t\t\tthis.lastBgHeight = size[1];\n\t\t\tthis.lastBgSlideYNum = -9999;\n\t\t\tthis.isUiDirty = true;\n\t\t}\n\t}\n\n\taddBgLine(bgLine: LyricLineEl): void {\n\t\tif (this.bgLine) {\n\t\t\tthis.bgLine.dispose();\n\t\t}\n\t\tif (this.bgWrapper) {\n\t\t\tthis.bgWrapper.remove();\n\t\t}\n\n\t\tthis.bgLine = bgLine;\n\n\t\t// 需要对比第一个词的开始时间而不是行起始时间,因为行的起始时间已经被\n\t\t// `syncMainAndBackgroundLines` 同步过了\n\t\tconst bgStartTime =\n\t\t\tbgLine.getLine().words[0]?.startTime ?? bgLine.getLine().startTime;\n\t\tconst mainStartTime =\n\t\t\tthis.mainLine.getLine().words[0]?.startTime ??\n\t\t\tthis.mainLine.getLine().startTime;\n\n\t\tthis.isBgFirst = bgStartTime < mainStartTime;\n\n\t\tif (this.mainLine.getLine().isDuet) {\n\t\t\tbgLine.getElement().classList.add(styles.lyricDuetLine);\n\t\t\tthis.element.classList.add(styles.isDuetWrapper);\n\t\t}\n\n\t\tthis.bgWrapper = document.createElement(\"div\");\n\t\tthis.bgWrapper.className = styles.bgWrapper;\n\n\t\tthis.bgWrapper.appendChild(bgLine.getElement());\n\n\t\tconst alwaysPostposition =\n\t\t\tthis.lyricPlayer.getAlwaysPostpositionBackground();\n\t\tconst shouldBgFirst = !alwaysPostposition && this.isBgFirst;\n\n\t\tif (shouldBgFirst) {\n\t\t\tthis.bgWrapper.classList.add(styles.bgWrapperTop);\n\t\t\tthis.element.insertBefore(this.bgWrapper, this.mainLine.getElement());\n\t\t\tthis.bgSlideY.setPosition(80);\n\t\t} else {\n\t\t\tthis.element.appendChild(this.bgWrapper);\n\t\t}\n\n\t\tthis.lyricPlayer.lyricGroupElementMap.set(this.bgWrapper, this);\n\t\tif (this.element.parentElement) {\n\t\t\tthis.lyricPlayer.resizeObserver.observe(this.bgWrapper);\n\t\t}\n\n\t\tthis.lastBgHeight = this.bgWrapper.clientHeight || 0;\n\t}\n\n\tprotected renderStyles(): void {\n\t\tconst style = this.element.style;\n\n\t\tconst currentY = this.posY.getCurrentPosition();\n\t\tif (Math.abs(currentY - this.lastYNum) >= 0.001) {\n\t\t\tthis.lastYNum = currentY;\n\t\t\tstyle.transform = `translateY(${currentY.toFixed(1)}px)`;\n\t\t}\n\n\t\tif (Math.abs(this.opacity - this.lastOpacityNum) >= 0.05) {\n\t\t\tthis.lastOpacityNum = this.opacity;\n\t\t\tstyle.opacity = String(this.opacity);\n\t\t}\n\n\t\tconst blurVal = Math.min(5, this.blur);\n\t\tif (Math.abs(blurVal - this.lastBlurNum) >= 0.05) {\n\t\t\tthis.lastBlurNum = blurVal;\n\t\t\tstyle.filter = blurVal > 0.01 ? `blur(${blurVal.toFixed(2)}px)` : \"none\";\n\t\t}\n\n\t\tif (this.bgWrapper) {\n\t\t\tif (this.lastIsActive !== this.isActive) {\n\t\t\t\tthis.lastIsActive = this.isActive;\n\t\t\t\tthis.bgWrapper.classList.toggle(styles.bgWrapperActive, this.isActive);\n\t\t\t}\n\n\t\t\tconst bgStyle = this.bgWrapper.style;\n\n\t\t\tconst slideY = this.bgSlideY.getCurrentPosition();\n\t\t\tif (Math.abs(slideY - this.lastBgSlideYNum) >= 0.001) {\n\t\t\t\tthis.lastBgSlideYNum = slideY;\n\t\t\t\tconst activeProgress = clamp01(1 - Math.abs(slideY) / 80);\n\t\t\t\tconst scaleStr = (0.8 + activeProgress * 0.2).toFixed(3);\n\t\t\t\tconst alwaysPostposition =\n\t\t\t\t\tthis.lyricPlayer.getAlwaysPostpositionBackground();\n\t\t\t\tconst shouldBgFirst = !alwaysPostposition && this.isBgFirst;\n\n\t\t\t\tconst translateYPx = (slideY / 100) * this.lastBgHeight;\n\t\t\t\tif (shouldBgFirst) {\n\t\t\t\t\tconst currentMarginTop = -this.lastBgHeight * (1 - activeProgress);\n\t\t\t\t\tbgStyle.marginTop = `${currentMarginTop.toFixed(1)}px`;\n\t\t\t\t} else {\n\t\t\t\t\tbgStyle.marginTop = \"\";\n\t\t\t\t}\n\n\t\t\t\tbgStyle.transform = `translateY(${translateYPx.toFixed(1)}px) scale(${scaleStr})`;\n\n\t\t\t\tconst targetHiddenY = shouldBgFirst ? 80 : -80;\n\t\t\t\tconst isHidden =\n\t\t\t\t\tMath.abs(slideY - targetHiddenY) < 0.1 && !this.isActive;\n\n\t\t\t\tif (this.lastBgIsHidden !== isHidden) {\n\t\t\t\t\tthis.lastBgIsHidden = isHidden;\n\t\t\t\t\tthis.bgWrapper.classList.toggle(styles.bgWrapperHidden, isHidden);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\toverride dispose(): void {\n\t\tsuper.dispose();\n\t\tthis.lyricPlayer.resizeObserver.unobserve(this.element);\n\t\tif (this.bgWrapper) {\n\t\t\tthis.lyricPlayer.lyricGroupElementMap.delete(this.bgWrapper);\n\t\t\tthis.lyricPlayer.resizeObserver.unobserve(this.bgWrapper);\n\t\t}\n\t\tthis.element.remove();\n\t}\n}\n","export const isCJK = (char: string): boolean => {\n\treturn /^[\\p{Unified_Ideograph}\\u0800-\\u9FFC]+$/u.test(char);\n};\n","import type { Disposable, LyricLine, LyricWord } from \"#interfaces\";\nimport { isCJK } from \"#utils/is-cjk.ts\";\nimport { Spring } from \"#utils/spring.ts\";\nimport { Duration } from \"#utils/time.ts\";\nimport { LyricLineRenderMode } from \"./consts.ts\";\n\ninterface LineTransforms {\n\tscale: Spring;\n}\n\n/**\n * 所有标准歌词行的基类\n * @internal\n */\nexport abstract class LyricLineBase extends EventTarget implements Disposable {\n\tprotected top = 0;\n\tprotected scale = 1;\n\tprotected blur = 0;\n\tprotected opacity = 1;\n\tprotected delay: Duration = Duration.ZERO;\n\n\tprotected isUiDirty = true;\n\n\treadonly lineTransforms: LineTransforms = {\n\t\tscale: new Spring(100),\n\t};\n\n\t/**\n\t * 用于 CJK 词语边界检测的分词器\n\t */\n\tstatic readonly wordSegmenter: Intl.Segmenter | null =\n\t\ttypeof Intl !== \"undefined\" && Intl.Segmenter\n\t\t\t? new Intl.Segmenter(undefined, { granularity: \"word\" })\n\t\t\t: null;\n\n\t/**\n\t * Unicode 标准的全局 Grapheme Cluster 分词器\n\t * 用于正确处理 emoji、复合字符等\n\t */\n\tstatic readonly graphemeSegmenter: Intl.Segmenter | null =\n\t\ttypeof Intl !== \"undefined\" && Intl.Segmenter\n\t\t\t? new Intl.Segmenter(undefined, { granularity: \"grapheme\" })\n\t\t\t: null;\n\n\tabstract getLine(): LyricLine;\n\tabstract enable(time?: number, shouldPlay?: boolean): void;\n\tabstract disable(): void;\n\tabstract resume(): void;\n\tabstract pause(): void;\n\tabstract onLineSizeChange(size: [number, number]): void;\n\tabstract commitChanges(): void;\n\n\tsetTransform(\n\t\tscale: number = this.scale,\n\t\topacity: number = this.opacity,\n\t\tblur: number = this.blur,\n\t\tdelay: Duration = Duration.ZERO,\n\t\t_mode: LyricLineRenderMode = LyricLineRenderMode.SOLID,\n\t): void {\n\t\tthis.scale = scale;\n\t\tthis.opacity = opacity;\n\t\tthis.blur = blur;\n\t\tthis.delay = delay;\n\t\tthis.isUiDirty = true;\n\t}\n\n\trebuildElement(): void {}\n\n\t/**\n\t * 判定歌词是否可以应用强调辉光效果\n\t *\n\t * 果子在对辉光效果的解释是一种强调(emphasized)效果\n\t *\n\t * 条件是一个单词时长大于等于 1s 且长度小于等于 7\n\t *\n\t * @param word 单词\n\t * @returns 是否可以应用强调辉光效果\n\t */\n\tstatic shouldEmphasize(word: LyricWord): boolean {\n\t\tif (isCJK(word.word)) return word.endTime - word.startTime >= 1000;\n\n\t\treturn (\n\t\t\tword.endTime - word.startTime >= 1000 &&\n\t\t\tword.word.trim().length <= 7 &&\n\t\t\tword.word.trim().length > 1\n\t\t);\n\t}\n\tabstract update(delta?: Duration): void;\n\tdispose(): void {}\n}\n","import { isCJK } from \"./is-cjk.ts\";\n\nexport interface ChildNodeInfo {\n\twidth: number;\n\ttext: string;\n\tisSpace: boolean;\n}\n\n/**\n * 单个词超过容器宽度时的大惩罚倍数\n */\nconst OVERFLOW_PENALTY_MULTIPLIER = 1000;\n/**\n * 截断 CJK 词组边界的惩罚比例\n *\n * 相对于容器宽度\n */\nconst CJK_BREAK_PENALTY_RATIO = 0.15;\n/**\n * 截断普通文本(非空格、非 CJK 词界)的惩罚比例\n */\nconst NORMAL_BREAK_PENALTY_RATIO = 0.5;\n/**\n * 在空格处断开的奖励比例\n */\nconst SPACE_BREAK_REWARD_RATIO = 0.4;\n/**\n * 在标点符号处断开的奖励比例\n *\n * 比空格更高以便优先一点在标点处换行\n */\nconst PUNCTUATION_BREAK_REWARD_RATIO = 0.6;\nconst PUNCTUATION_REGEX = /[,.;:!?,。;:!?、)】》」』’”)[\\]}>~…]$/;\n\n/**\n * 计算平均行长度的断点位置\n * @param children 子节点信息\n * @param containerWidth 容器可用内容宽度\n * @param fullText 完整的行文本\n * @param segmenter 预创建的 Intl.Segmenter 分词器\n * @returns 需要在其前面插入 `<br>` 的子节点索引数组,升序\n */\nexport function calcBalancedBreaks(\n\tchildren: ChildNodeInfo[],\n\tcontainerWidth: number,\n\tfullText: string,\n\tsegmenter: Intl.Segmenter,\n): number[] {\n\tconst n = children.length;\n\tif (n === 0 || containerWidth <= 0) {\n\t\treturn [];\n\t}\n\n\t// 计算哪里是 CJK 词组的边界\n\tconst cjkBoundaries = new Set<number>();\n\tlet offset = 0;\n\tfor (const { segment, isWordLike } of segmenter.segment(fullText)) {\n\t\tif (offset > 0 && isWordLike) {\n\t\t\tif ([...segment].some((ch) => isCJK(ch))) {\n\t\t\t\tcjkBoundaries.add(offset);\n\t\t\t}\n\t\t}\n\t\toffset += segment.length;\n\t}\n\n\t// 计算前缀宽和字符偏移量用于快速查询\n\tconst charOffsets = new Int32Array(n + 1);\n\tconst prefixWidth = new Float64Array(n + 1);\n\tfor (let i = 0; i < n; i++) {\n\t\tcharOffsets[i + 1] = charOffsets[i] + children[i].text.length;\n\t\tprefixWidth[i + 1] = prefixWidth[i] + children[i].width;\n\t}\n\n\tif (prefixWidth[n] <= containerWidth) {\n\t\treturn [];\n\t}\n\n\t/**\n\t * dp[i] 表示将 index i 到 n-1 的节点进行排版的最小代价\n\t */\n\tconst dp = new Float64Array(n + 1).fill(Number.POSITIVE_INFINITY);\n\tconst nextBreak = new Int32Array(n + 1).fill(-1);\n\tdp[n] = 0;\n\n\tconst PENALTY_CJK = (containerWidth * CJK_BREAK_PENALTY_RATIO) ** 2;\n\tconst PENALTY_NORMAL = (containerWidth * NORMAL_BREAK_PENALTY_RATIO) ** 2;\n\n\tfor (let i = n - 1; i >= 0; i--) {\n\t\tfor (let j = i + 1; j <= n; j++) {\n\t\t\tconst w = prefixWidth[j] - prefixWidth[i];\n\n\t\t\tlet lineCost = 0;\n\n\t\t\tif (w > containerWidth) {\n\t\t\t\tif (j === i + 1) {\n\t\t\t\t\t// 单个无法分割的词自身就比容器宽,被迫独立成行,给大惩罚\n\t\t\t\t\tlineCost = (w - containerWidth) ** 2 * OVERFLOW_PENALTY_MULTIPLIER;\n\t\t\t\t} else {\n\t\t\t\t\t// 行内包含多个超过物理宽度的词就跳过\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\t// 迫使所有行的长度方差最小化\n\t\t\t\tlineCost = (containerWidth - w) ** 2;\n\t\t\t}\n\n\t\t\tlet breakPenalty = 0;\n\t\t\tif (j < n) {\n\t\t\t\tconst prevChild = children[j - 1];\n\n\t\t\t\t// 优先级:标点 > 空格 > CJK 词界 > 普通文本\n\t\t\t\tif (PUNCTUATION_REGEX.test(prevChild.text)) {\n\t\t\t\t\tbreakPenalty = -(\n\t\t\t\t\t\t(containerWidth * PUNCTUATION_BREAK_REWARD_RATIO) **\n\t\t\t\t\t\t2\n\t\t\t\t\t);\n\t\t\t\t} else if (prevChild.isSpace) {\n\t\t\t\t\tbreakPenalty = -((containerWidth * SPACE_BREAK_REWARD_RATIO) ** 2);\n\t\t\t\t} else if (cjkBoundaries.has(charOffsets[j])) {\n\t\t\t\t\tbreakPenalty = PENALTY_CJK;\n\t\t\t\t} else {\n\t\t\t\t\tbreakPenalty = PENALTY_NORMAL;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst totalCost = lineCost + breakPenalty + dp[j];\n\n\t\t\tif (totalCost < dp[i]) {\n\t\t\t\tdp[i] = totalCost;\n\t\t\t\tnextBreak[i] = j;\n\t\t\t}\n\t\t}\n\t}\n\n\tconst breaks: number[] = [];\n\tlet curr = 0;\n\twhile (curr < n) {\n\t\tcurr = nextBreak[curr];\n\t\tif (curr > 0 && curr < n) {\n\t\t\tbreaks.push(curr);\n\t\t}\n\t}\n\n\treturn breaks;\n}\n","import { clampPositive } from \"./clamp.ts\";\nimport { type ChildNodeInfo, calcBalancedBreaks } from \"./lyric-line-break.ts\";\n\nlet sharedCanvasCtx: CanvasRenderingContext2D | null = null;\nexport function getMeasurementContext(): CanvasRenderingContext2D | null {\n\tif (!sharedCanvasCtx) {\n\t\tconst canvas = document.createElement(\"canvas\");\n\t\tsharedCanvasCtx = canvas.getContext(\"2d\");\n\t}\n\treturn sharedCanvasCtx;\n}\n\ninterface LineBalanceAdapter {\n\tresetDOM(): void;\n\tbuildChildInfos(): { childInfos: ChildNodeInfo[]; fullText: string };\n\tapplyBreaks(breaks: number[], childInfos: ChildNodeInfo[]): void;\n\tneedsCalibration: boolean;\n}\n\n/**\n * 用于平衡歌词行在换行后的各行长度\n */\nexport class LineBalancer {\n\tprivate isBalancing = false;\n\tprivate lastBalancedContainerWidth = -1;\n\n\tconstructor(private mainElement: HTMLDivElement) {}\n\n\tpublic balanceLineBreaks(\n\t\tisNonDynamic: boolean,\n\t\thasSplittedWords: boolean,\n\t\twordSegmenter: Intl.Segmenter,\n\t): void {\n\t\tif (this.isBalancing || !this.mainElement) return;\n\n\t\tconst computedStyle = getComputedStyle(this.mainElement);\n\t\tconst paddingLeft = Number.parseFloat(computedStyle.paddingLeft) || 0;\n\t\tconst paddingRight = Number.parseFloat(computedStyle.paddingRight) || 0;\n\t\tconst containerWidth =\n\t\t\tthis.mainElement.clientWidth - paddingLeft - paddingRight;\n\n\t\tif (containerWidth <= 0) return;\n\n\t\tif (isNonDynamic) {\n\t\t\tthis.balanceNonDynamicLineBreaks(\n\t\t\t\tcontainerWidth,\n\t\t\t\tcomputedStyle,\n\t\t\t\twordSegmenter,\n\t\t\t);\n\t\t\treturn;\n\t\t}\n\n\t\tif (!hasSplittedWords) return;\n\t\tthis.balanceDynamicLineBreaks(containerWidth, wordSegmenter);\n\t}\n\n\tpublic reset(): void {\n\t\tthis.lastBalancedContainerWidth = -1;\n\t}\n\n\tprivate executeLineBalance(\n\t\tcontainerWidth: number,\n\t\tadapter: LineBalanceAdapter,\n\t\twordSegmenter: Intl.Segmenter,\n\t): void {\n\t\tconst existingBrs = this.mainElement.querySelectorAll(\"br\");\n\t\tif (\n\t\t\tcontainerWidth === this.lastBalancedContainerWidth &&\n\t\t\texistingBrs.length > 0\n\t\t) {\n\t\t\treturn;\n\t\t}\n\n\t\tadapter.resetDOM();\n\n\t\t// 临时设置 white-space: nowrap 以便测量单个歌词行的宽度\n\t\tconst prevWhiteSpace = this.mainElement.style.whiteSpace;\n\t\tthis.mainElement.style.whiteSpace = \"nowrap\";\n\n\t\t// 临时移除父级的 transform 以便让 getBoundingClientRect 返回纯粹的布局尺寸\n\t\t// 基类在 enableScale 时设置的 0.97 缩放倍率会影响到计算的宽度\n\t\tconst parentElement = this.mainElement.parentElement;\n\t\tlet prevTransform = \"\";\n\t\tlet transformChanged = false;\n\n\t\tif (parentElement) {\n\t\t\tprevTransform = parentElement.style.transform;\n\t\t\tif (prevTransform && prevTransform !== \"none\") {\n\t\t\t\tparentElement.style.transform = \"none\";\n\t\t\t\ttransformChanged = true;\n\t\t\t}\n\t\t}\n\n\t\tlet lockAcquired = false;\n\n\t\ttry {\n\t\t\tconst { childInfos, fullText } = adapter.buildChildInfos();\n\n\t\t\tlet layoutWidth = childInfos.reduce((sum, c) => sum + c.width, 0);\n\n\t\t\t// 非动态歌词(用 Canvas 测量)才用 range 来缩放校准;动态歌词的强调 wrapper 有 1em 的 padding 和\n\t\t\t// margin,用 range 测会把首尾溢出的 1em 也加进来,极大地增大了行长度,视觉上就是非常激进地换行\n\t\t\tif (adapter.needsCalibration) {\n\t\t\t\tconst range = document.createRange();\n\t\t\t\trange.selectNodeContents(this.mainElement);\n\t\t\t\tconst visualWidth = range.getBoundingClientRect().width;\n\n\t\t\t\tif (layoutWidth > 0 && visualWidth > 0) {\n\t\t\t\t\tconst scale = visualWidth / layoutWidth;\n\t\t\t\t\tfor (const info of childInfos) {\n\t\t\t\t\t\tinfo.width *= scale;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tlayoutWidth = visualWidth;\n\t\t\t}\n\n\t\t\tconst safeContainerWidth = Math.max(1, containerWidth);\n\n\t\t\tif (layoutWidth <= safeContainerWidth) {\n\t\t\t\tthis.lastBalancedContainerWidth = containerWidth;\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst breaks = calcBalancedBreaks(\n\t\t\t\tchildInfos,\n\t\t\t\tsafeContainerWidth,\n\t\t\t\tfullText,\n\t\t\t\twordSegmenter,\n\t\t\t);\n\n\t\t\tif (breaks.length === 0) {\n\t\t\t\tthis.lastBalancedContainerWidth = containerWidth;\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tthis.isBalancing = true;\n\t\t\tlockAcquired = true;\n\n\t\t\tadapter.applyBreaks(breaks, childInfos);\n\t\t\tthis.lastBalancedContainerWidth = containerWidth;\n\t\t\tthis.isBalancing = false;\n\t\t} finally {\n\t\t\tthis.mainElement.style.whiteSpace = prevWhiteSpace;\n\t\t\tif (transformChanged && parentElement) {\n\t\t\t\tparentElement.style.transform = prevTransform;\n\t\t\t}\n\n\t\t\tif (lockAcquired) {\n\t\t\t\tthis.isBalancing = false;\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate balanceDynamicLineBreaks(\n\t\tcontainerWidth: number,\n\t\twordSegmenter: Intl.Segmenter,\n\t): void {\n\t\tconst infoToNode: Node[] = [];\n\n\t\tconst dynamicAdapter: LineBalanceAdapter = {\n\t\t\tresetDOM: () => {\n\t\t\t\tthis.mainElement.querySelectorAll(\"br\").forEach((br) => {\n\t\t\t\t\tbr.remove();\n\t\t\t\t});\n\t\t\t},\n\t\t\tbuildChildInfos: () => {\n\t\t\t\tinfoToNode.length = 0;\n\t\t\t\tconst childNodes = Array.from(this.mainElement.childNodes);\n\t\t\t\tconst childInfos: ChildNodeInfo[] = [];\n\t\t\t\tconst range = document.createRange();\n\n\t\t\t\tfor (const node of childNodes) {\n\t\t\t\t\tif (node.nodeType === Node.TEXT_NODE) {\n\t\t\t\t\t\tconst text = node.textContent ?? \"\";\n\t\t\t\t\t\tif (text.length === 0) continue;\n\t\t\t\t\t\trange.selectNodeContents(node);\n\t\t\t\t\t\tchildInfos.push({\n\t\t\t\t\t\t\twidth: range.getBoundingClientRect().width,\n\t\t\t\t\t\t\ttext,\n\t\t\t\t\t\t\tisSpace: text.trim().length === 0,\n\t\t\t\t\t\t});\n\t\t\t\t\t\tinfoToNode.push(node);\n\t\t\t\t\t} else if (node.nodeType === Node.ELEMENT_NODE) {\n\t\t\t\t\t\tconst el = node as HTMLElement;\n\t\t\t\t\t\tconst rect = el.getBoundingClientRect();\n\t\t\t\t\t\tconst elStyle = getComputedStyle(el);\n\t\t\t\t\t\tconst marginLeft = Number.parseFloat(elStyle.marginLeft) || 0;\n\t\t\t\t\t\tconst marginRight = Number.parseFloat(elStyle.marginRight) || 0;\n\t\t\t\t\t\tchildInfos.push({\n\t\t\t\t\t\t\twidth: clampPositive(rect.width + marginLeft + marginRight),\n\t\t\t\t\t\t\ttext: el.textContent ?? \"\",\n\t\t\t\t\t\t\tisSpace: false,\n\t\t\t\t\t\t});\n\t\t\t\t\t\tinfoToNode.push(node);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn { childInfos, fullText: childInfos.map((c) => c.text).join(\"\") };\n\t\t\t},\n\t\t\tapplyBreaks: (breaks) => {\n\t\t\t\tfor (let i = breaks.length - 1; i >= 0; i--) {\n\t\t\t\t\tconst breakIndex = breaks[i];\n\t\t\t\t\tif (breakIndex >= 0 && breakIndex < infoToNode.length) {\n\t\t\t\t\t\tthis.mainElement.insertBefore(\n\t\t\t\t\t\t\tdocument.createElement(\"br\"),\n\t\t\t\t\t\t\tinfoToNode[breakIndex],\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t},\n\t\t\tneedsCalibration: false,\n\t\t};\n\n\t\tthis.executeLineBalance(containerWidth, dynamicAdapter, wordSegmenter);\n\t}\n\n\tprivate balanceNonDynamicLineBreaks(\n\t\tcontainerWidth: number,\n\t\tcomputedStyle: CSSStyleDeclaration,\n\t\twordSegmenter: Intl.Segmenter,\n\t): void {\n\t\tconst fullText = this.mainElement.textContent ?? \"\";\n\t\tif (fullText.trim().length === 0) return;\n\n\t\tconst nonDynamicAdapter: LineBalanceAdapter = {\n\t\t\tresetDOM: () => {\n\t\t\t\tthis.mainElement.innerHTML = \"\";\n\t\t\t\tthis.mainElement.textContent = fullText;\n\t\t\t},\n\t\t\tbuildChildInfos: () => {\n\t\t\t\tconst ctx = getMeasurementContext();\n\n\t\t\t\tif (!ctx) {\n\t\t\t\t\tconsole.debug(\n\t\t\t\t\t\t\"Canvas 2D context is not supported, skipping line balancing\",\n\t\t\t\t\t);\n\t\t\t\t\treturn { childInfos: [], fullText };\n\t\t\t\t}\n\n\t\t\t\tctx.font = `${computedStyle.fontWeight} ${computedStyle.fontSize} ${computedStyle.fontFamily}`;\n\n\t\t\t\tif (\"letterSpacing\" in ctx) {\n\t\t\t\t\tctx.letterSpacing =\n\t\t\t\t\t\tcomputedStyle.letterSpacing !== \"normal\"\n\t\t\t\t\t\t\t? computedStyle.letterSpacing\n\t\t\t\t\t\t\t: \"0px\";\n\t\t\t\t}\n\t\t\t\tif (\"wordSpacing\" in ctx) {\n\t\t\t\t\tctx.wordSpacing =\n\t\t\t\t\t\tcomputedStyle.wordSpacing !== \"normal\"\n\t\t\t\t\t\t\t? computedStyle.wordSpacing\n\t\t\t\t\t\t\t: \"0px\";\n\t\t\t\t}\n\n\t\t\t\tconst childInfos: ChildNodeInfo[] = [];\n\t\t\t\tfor (const { segment } of wordSegmenter.segment(fullText)) {\n\t\t\t\t\tchildInfos.push({\n\t\t\t\t\t\twidth: ctx.measureText(segment).width,\n\t\t\t\t\t\ttext: segment,\n\t\t\t\t\t\tisSpace: segment.trim().length === 0,\n\t\t\t\t\t});\n\t\t\t\t}\n\n\t\t\t\treturn { childInfos, fullText };\n\t\t\t},\n\t\t\tapplyBreaks: (breaks, childInfos) => {\n\t\t\t\tthis.mainElement.innerHTML = \"\";\n\t\t\t\tconst breakSet = new Set(breaks);\n\t\t\t\tconst fragment = document.createDocumentFragment();\n\n\t\t\t\tfor (let i = 0; i < childInfos.length; i++) {\n\t\t\t\t\tif (breakSet.has(i)) {\n\t\t\t\t\t\tfragment.appendChild(document.createElement(\"br\"));\n\t\t\t\t\t}\n\t\t\t\t\tfragment.appendChild(document.createTextNode(childInfos[i].text));\n\t\t\t\t}\n\t\t\t\tthis.mainElement.appendChild(fragment);\n\t\t\t},\n\t\t\tneedsCalibration: true,\n\t\t};\n\n\t\tthis.executeLineBalance(containerWidth, nonDynamicAdapter, wordSegmenter);\n\t}\n}\n","import type { LyricWord } from \"../interfaces.ts\";\nimport { isCJK } from \"./is-cjk.ts\";\n\nconst SPLIT_WHITESPACE_RE = /(\\s+)/;\nconst WHITESPACE_RE = /\\s/g;\n\n/**\n * 将输入的单词重新分组,之间没有空格的单词将会组合成一个单词数组\n *\n * 例如输入:`[\"Life\", \" \", \"is\", \" a\", \" su\", \"gar so\", \"sweet\"]`\n *\n * 应该返回:`[\"Life\", \" \", \"is\", \" a\", [\" su\", \"gar\"], \"so\", \"sweet\"]`\n * @param words 输入的单词数组\n * @returns 重新分组后的单词数组\n */\nexport function chunkAndSplitLyricWords(\n\twords: LyricWord[],\n): (LyricWord | LyricWord[])[] {\n\tconst result: (LyricWord | LyricWord[])[] = [];\n\tlet currentGroup: LyricWord[] = [];\n\n\tconst flushGroup = () => {\n\t\tif (currentGroup.length > 0) {\n\t\t\tresult.push(\n\t\t\t\tcurrentGroup.length === 1 ? currentGroup[0] : [...currentGroup],\n\t\t\t);\n\t\t\tcurrentGroup = [];\n\t\t}\n\t};\n\n\tconst processAtom = (atom: LyricWord) => {\n\t\tconst isSpace = atom.word.trim().length === 0;\n\t\tconst hasRuby = (atom.ruby?.length ?? 0) > 0;\n\t\tconst isCJKChar = isCJK(atom.word);\n\n\t\tconst isMergeable = !isSpace && !hasRuby && !isCJKChar;\n\n\t\tif (isMergeable) {\n\t\t\tcurrentGroup.push(atom);\n\t\t} else {\n\t\t\tflushGroup();\n\t\t\tresult.push(atom);\n\t\t}\n\t};\n\n\tfor (const w of words) {\n\t\tconst content = w.word.trim();\n\t\tconst isSpace = content.length === 0;\n\t\tconst romanWord = w.romanWord ?? \"\";\n\t\tconst obscene = w.obscene ?? false;\n\t\tconst hasRuby = (w.ruby?.length ?? 0) > 0;\n\n\t\tif (isSpace) {\n\t\t\tprocessAtom({ ...w, obscene });\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (hasRuby) {\n\t\t\tconst leadingSpaceMatch = w.word.match(/^\\s+/);\n\t\t\tconst trailingSpaceMatch = w.word.match(/\\s+$/);\n\t\t\tconst leadingSpace = leadingSpaceMatch ? leadingSpaceMatch[0] : \"\";\n\t\t\tconst trailingSpace = trailingSpaceMatch ? trailingSpaceMatch[0] : \"\";\n\n\t\t\tif (leadingSpace) {\n\t\t\t\tprocessAtom({\n\t\t\t\t\tword: leadingSpace,\n\t\t\t\t\tromanWord: \"\",\n\t\t\t\t\tstartTime: w.startTime,\n\t\t\t\t\tendTime: w.startTime,\n\t\t\t\t\tobscene: obscene,\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tprocessAtom({\n\t\t\t\t...w,\n\t\t\t\tword: content,\n\t\t\t\tobscene: obscene,\n\t\t\t});\n\n\t\t\tif (trailingSpace) {\n\t\t\t\tprocessAtom({\n\t\t\t\t\tword: trailingSpace,\n\t\t\t\t\tromanWord: \"\",\n\t\t\t\t\tstartTime: w.endTime,\n\t\t\t\t\tendTime: w.endTime,\n\t\t\t\t\tobscene: obscene,\n\t\t\t\t});\n\t\t\t}\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst parts = w.word.split(SPLIT_WHITESPACE_RE).filter((p) => p.length > 0);\n\n\t\tconst totalLength = w.word.replace(WHITESPACE_RE, \"\").length || 1;\n\t\tconst timeSpan = w.endTime - w.startTime;\n\t\tconst timePerUnit = timeSpan / totalLength;\n\n\t\tconst wordParts = w.word\n\t\t\t.trim()\n\t\t\t.split(/\\s+/)\n\t\t\t.filter((p) => p.length > 0);\n\t\tconst romanTrimmed = romanWord.trim();\n\t\tconst romanParts =\n\t\t\tromanTrimmed.length > 0\n\t\t\t\t? romanTrimmed.split(/\\s+/).filter((p) => p.length > 0)\n\t\t\t\t: [];\n\t\tconst isMatched =\n\t\t\twordParts.length > 0 && wordParts.length === romanParts.length;\n\n\t\tlet currentOffset = 0;\n\t\tlet nonSpaceIndex = 0;\n\n\t\tfor (const part of parts) {\n\t\t\tif (!part.trim()) {\n\t\t\t\tconst startTime = w.startTime + currentOffset * timePerUnit;\n\t\t\t\tprocessAtom({\n\t\t\t\t\tword: part,\n\t\t\t\t\tromanWord: \"\",\n\t\t\t\t\tstartTime: startTime,\n\t\t\t\t\tendTime: startTime,\n\t\t\t\t\tobscene: obscene,\n\t\t\t\t});\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tlet partRomanWord = \"\";\n\t\t\tif (romanParts.length > 0) {\n\t\t\t\tif (isMatched) {\n\t\t\t\t\tpartRomanWord = romanParts[nonSpaceIndex] ?? \"\";\n\t\t\t\t} else if (nonSpaceIndex === 0) {\n\t\t\t\t\tpartRomanWord = romanWord;\n\t\t\t\t}\n\t\t\t}\n\t\t\tnonSpaceIndex++;\n\n\t\t\tif (isCJK(part) && part.length > 1 && romanTrimmed.length === 0) {\n\t\t\t\tconst chars = part.split(\"\");\n\t\t\t\tfor (const char of chars) {\n\t\t\t\t\tconst startTime = w.startTime + currentOffset * timePerUnit;\n\t\t\t\t\tprocessAtom({\n\t\t\t\t\t\tword: char,\n\t\t\t\t\t\tromanWord: \"\",\n\t\t\t\t\t\tstartTime: startTime,\n\t\t\t\t\t\tendTime: startTime + timePerUnit,\n\t\t\t\t\t\tobscene: obscene,\n\t\t\t\t\t});\n\t\t\t\t\tcurrentOffset += 1;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tconst partRealLen = part.length;\n\t\t\t\tconst startTime = w.startTime + currentOffset * timePerUnit;\n\t\t\t\tconst duration = partRealLen * timePerUnit;\n\n\t\t\t\tprocessAtom({\n\t\t\t\t\tword: part,\n\t\t\t\t\tromanWord: partRomanWord,\n\t\t\t\t\tstartTime: startTime,\n\t\t\t\t\tendTime: startTime + duration,\n\t\t\t\t\tobscene: obscene,\n\t\t\t\t});\n\t\t\t\tcurrentOffset += partRealLen;\n\t\t\t}\n\t\t}\n\t}\n\n\tflushGroup();\n\n\treturn result;\n}\n","// biome-ignore format: matrix\nexport type Matrix4 = [\n\tnumber, number, number, number,\n\tnumber, number, number, number,\n\tnumber, number, number, number,\n\tnumber, number, number, number,\n];\n\nexport function createMatrix4(): Matrix4 {\n\t// biome-ignore format: matrix\n\treturn [\n 1, 0, 0, 0,\n 0, 1, 0, 0,\n 0, 0, 1, 0,\n 0, 0, 0, 1\n ];\n}\n\nexport function scaleMatrix4(\n\tm: Matrix4,\n\tscale = 1,\n\torigin = { x: 0, y: 0 },\n): Matrix4 {\n\tconst [ox, oy] = [origin.x, origin.y];\n\t// biome-ignore format: matrix\n\treturn [\n m[0] * scale , m[1] * scale , m[2] * scale , m[3],\n m[4] * scale , m[5] * scale , m[6] * scale , m[7],\n m[8] * scale , m[9] * scale , m[10] * scale, m[11],\n m[12] - ox * scale + ox, m[13] - oy * scale + oy, m[14] , m[15]\n ];\n}\n\nexport function translateMatrix4(m: Matrix4, x = 0, y = 0, z = 0): Matrix4 {\n\t// biome-ignore format: matrix\n\treturn [\n m[0] , m[1] , m[2] , m[3] ,\n m[4] , m[5] , m[6] , m[7] ,\n m[8] , m[9] , m[10] , m[11],\n m[12] + x, m[13] + y, m[14] + z, m[15]\n ];\n}\n\nexport function matrix4ToCSS(m: Matrix4, fractionDigits = 4): string {\n\tconst format = (n: number, _: number) => n.toFixed(fractionDigits);\n\treturn `matrix3d(${m.map(format).join(\", \")})`;\n}\n","import bezier from \"bezier-easing\";\nimport type { LyricWord } from \"#interfaces\";\nimport { clamp01, clampPositive } from \"#utils/clamp.ts\";\nimport { createMatrix4, matrix4ToCSS, scaleMatrix4 } from \"#utils/matrix.ts\";\n\n//#region 工具函数和类型\nconst ANIMATION_FRAME_QUANTITY = 32;\n\nconst norNum = (min: number, max: number) => (x: number) =>\n\tclamp01((x - min) / (max - min));\nconst EMP_EASING_MID = 0.5;\nconst beginNum = norNum(0, EMP_EASING_MID);\nconst endNum = norNum(EMP_EASING_MID, 1);\n\nconst bezIn = bezier(0.2, 0.4, 0.58, 1.0);\nconst bezOut = bezier(0.3, 0.0, 0.58, 1.0);\n\nconst makeEmpEasing = (mid: number) => {\n\treturn (x: number) => (x < mid ? bezIn(beginNum(x)) : 1 - bezOut(endNum(x)));\n};\nconst empEasing = makeEmpEasing(EMP_EASING_MID);\n\n/**\n * 强调动画的配置选项\n */\nexport interface EmphasizeAnimationOptions {\n\t/**\n\t * 当前正在处理的单词\n\t */\n\tword: LyricWord;\n\n\t/**\n\t * 属于该单词、且已经被拆分为单个字符的 DOM 元素数组\n\t */\n\tcharacterElements: HTMLElement[];\n\n\t/**\n\t * 单词的持续时间(毫秒)\n\t */\n\tduration: number;\n\n\t/**\n\t * 单词相对于歌词行起始时间的延迟(毫秒)\n\t */\n\tdelay: number;\n\n\t/**\n\t * Ruby 字符的总数量,用于辅助计算字符间错落起步的延迟差\n\t */\n\trubyCharCount: number;\n\n\t/**\n\t * 当前行是否为背景人声(背景人声的上浮幅度会成倍增加)\n\t */\n\tisBG: boolean;\n\n\t/**\n\t * 当前单词是否为整行歌词的最后一个词(若是,则会加剧形变与辉光的幅度)\n\t */\n\tisLastWord: boolean;\n}\n\n/**\n * 内部传递的预计算动画参数容器\n */\ninterface EmphasizeParams {\n\tamount: number;\n\tblur: number;\n\tdu: number;\n\tde: number;\n\tanchorCharCount: number;\n\tanimateDu: number;\n}\n//#endregion\n\n//#region 外部 API\n/**\n * 为单词元素的所有字符创建强调动画序列,\n * 该效果会使得逐个字符依次进行辉光缩放和上浮\n *\n * 创建后的动画默认处于暂停状态,外部需要根据播放进度进行调度\n *\n * @param options 强调动画配置项\n * @returns 构建完毕的 Animation 对象列表\n */\nexport function createEmphasizeAnimation(\n\toptions: EmphasizeAnimationOptions,\n): Animation[] {\n\tconst params = calculateEmphasizeParams(options);\n\tconst totalChars = options.characterElements.length;\n\tconst result: Animation[] = [];\n\n\toptions.characterElements.forEach((el, i) => {\n\t\tconst wordDe = params.de + (params.du / 2.5 / params.anchorCharCount) * i;\n\n\t\tresult.push(createCharGlowAnimation(el, i, totalChars, wordDe, params));\n\t\tresult.push(createCharFloatAnimation(el, wordDe, options.isBG, params));\n\t});\n\n\treturn result;\n}\n//#endregion\n\n//#region 参数计算\nfunction calculateEmphasizeParams(\n\toptions: EmphasizeAnimationOptions,\n): EmphasizeParams {\n\tconst { duration, delay, rubyCharCount, characterElements, isLastWord } =\n\t\toptions;\n\n\tconst de = clampPositive(delay);\n\tlet du = Math.max(1000, duration);\n\tconst anchorCharCount =\n\t\trubyCharCount > 0 ? rubyCharCount : Math.max(1, characterElements.length);\n\n\tlet amount = du / 2000;\n\tamount = amount > 1 ? Math.sqrt(amount) : amount ** 3;\n\n\tlet blur = du / 3000;\n\tblur = blur > 1 ? Math.sqrt(blur) : blur ** 3;\n\n\tamount *= 0.6;\n\tblur *= 0.5;\n\n\t// 为了演出效果,给最后一个词应用更强的效果\n\tif (isLastWord) {\n\t\tamount *= 1.6;\n\t\tblur *= 1.5;\n\t\tdu *= 1.2;\n\t}\n\n\tamount = Math.min(1.2, amount);\n\tblur = Math.min(0.8, blur);\n\n\tconst animateDu = Number.isFinite(du) ? du : 0;\n\n\treturn {\n\t\tamount,\n\t\tblur,\n\t\tdu,\n\t\tde,\n\t\tanchorCharCount,\n\t\tanimateDu,\n\t};\n}\n//#endregion\n\n//#region 帧生成器\nfunction generateGlowKeyframes(\n\tcharIndex: number,\n\ttotalChars: number,\n\tamount: number,\n\tblur: number,\n): Keyframe[] {\n\treturn new Array(ANIMATION_FRAME_QUANTITY).fill(0).map((_, j) => {\n\t\tconst x = (j + 1) / ANIMATION_FRAME_QUANTITY;\n\t\tconst transX = empEasing(x);\n\t\tconst glowLevel = transX * blur;\n\n\t\tconst mat = scaleMatrix4(createMatrix4(), 1 + transX * 0.1 * amount);\n\n\t\t// 结合字符在单词中的位置(偏左或偏右),产生轻微的相互推挤效果\n\t\tconst offsetX = -transX * 0.03 * amount * (totalChars / 2 - charIndex);\n\t\tconst offsetY = -transX * 0.025 * amount;\n\n\t\treturn {\n\t\t\toffset: x,\n\t\t\ttransform: `${matrix4ToCSS(mat, 4)} translate(${offsetX}em, ${offsetY}em)`,\n\t\t\ttextShadow: `0 0 ${Math.min(0.3, blur * 0.3)}em rgba(255, 255, 255, ${glowLevel})`,\n\t\t};\n\t});\n}\n\nfunction generateFloatKeyframes(isBG: boolean): Keyframe[] {\n\treturn new Array(ANIMATION_FRAME_QUANTITY).fill(0).map((_, j) => {\n\t\tconst x = (j + 1) / ANIMATION_FRAME_QUANTITY;\n\t\tlet y = Math.sin(x * Math.PI);\n\t\tif (isBG) {\n\t\t\ty *= 2;\n\t\t}\n\n\t\treturn {\n\t\t\toffset: x,\n\t\t\ttransform: `translateY(${-y * 0.05}em)`,\n\t\t};\n\t});\n}\n//#endregion\n\n//#region 单字符动画实例化\nfunction createCharGlowAnimation(\n\tel: HTMLElement,\n\tcharIndex: number,\n\ttotalChars: number,\n\twordDelay: number,\n\tparams: EmphasizeParams,\n): Animation {\n\tconst frames = generateGlowKeyframes(\n\t\tcharIndex,\n\t\ttotalChars,\n\t\tparams.amount,\n\t\tparams.blur,\n\t);\n\n\tconst glow = el.animate(frames, {\n\t\tduration: params.animateDu,\n\t\tdelay: Number.isFinite(wordDelay) ? wordDelay : 0,\n\t\tid: `emphasize-word-${el.textContent}-${charIndex}`,\n\t\titerations: 1,\n\t\tcomposite: \"replace\",\n\t\tfill: \"both\",\n\t});\n\tglow.onfinish = () => glow.pause();\n\tglow.pause();\n\n\treturn glow;\n}\n\nfunction createCharFloatAnimation(\n\tel: HTMLElement,\n\twordDelay: number,\n\tisBG: boolean,\n\tparams: EmphasizeParams,\n): Animation {\n\tconst frames = generateFloatKeyframes(isBG);\n\n\tconst float = el.animate(frames, {\n\t\tduration: params.animateDu * 1.4,\n\t\t// 上浮动画比辉光动画提前 400ms 开始\n\t\tdelay: Number.isFinite(wordDelay) ? wordDelay - 400 : 0,\n\t\tid: \"emphasize-word-float\",\n\t\titerations: 1,\n\t\tcomposite: \"add\",\n\t\tfill: \"both\",\n\t});\n\tfloat.onfinish = () => float.pause();\n\tfloat.pause();\n\n\treturn float;\n}\n//#endregion\n","import type { LyricWord } from \"#interfaces\";\n\n/**\n * 上浮动画的配置选项\n */\nexport interface FloatAnimationOptions {\n\t/**\n\t * 当前绑定的歌词单词数据,用于计算动画的时长与绝对起始时间\n\t */\n\tword: LyricWord;\n\n\t/**\n\t * 当前单词所在歌词行的起始时间(毫秒),用于计算该单词动画的相对延迟时间\n\t */\n\tlineStartTime: number;\n\n\t/**\n\t * 是否为背景歌词行\n\t *\n\t * 背景歌词行的上浮位移幅度是主歌词行的两倍\n\t */\n\tisBG: boolean;\n}\n\n/**\n * 创建常规歌词单词的上浮动画\n *\n * 基于 Web Animations API 实现,动画会使传入的单词元素产生一个轻微向上平移的效果\n *\n * 创建后的动画默认处于暂停状态,外部需要根据播放进度进行调度\n *\n * @param wordEl - 需要应用上浮动画的歌词单词 DOM 元素\n * @param options - 动画相关的上下文配置选项\n * @returns 一个处于暂停状态的 {@link Animation} 对象\n */\nexport function createFloatAnimation(\n\twordEl: HTMLElement,\n\toptions: FloatAnimationOptions,\n): Animation {\n\tconst { word, lineStartTime, isBG } = options;\n\n\tconst delay = word.startTime - lineStartTime;\n\tconst duration = Math.max(1000, word.endTime - word.startTime);\n\n\tlet up = 0.05;\n\tif (isBG) {\n\t\tup *= 2;\n\t}\n\n\tconst a = wordEl.animate(\n\t\t[{ transform: \"translateY(0px)\" }, { transform: `translateY(${-up}em)` }],\n\t\t{\n\t\t\tduration: Number.isFinite(duration) ? duration : 0,\n\t\t\tdelay: Number.isFinite(delay) ? delay : 0,\n\t\t\tid: \"float-word\",\n\t\t\tcomposite: \"add\",\n\t\t\tfill: \"both\",\n\t\t\teasing: \"ease-out\",\n\t\t},\n\t);\n\n\ta.pause();\n\treturn a;\n}\n","const bright = \"rgb(0 0 0 / var(--bright-mask-alpha, 1))\";\nconst dark = \"rgb(0 0 0 / var(--dark-mask-alpha, 1))\";\n\nexport function generateFadeGradient(\n\twidth: number,\n): readonly [gradient: string, totalAspect: number] {\n\tconst totalAspect = 2 + width;\n\tconst halfFadePercent = (width / totalAspect) * 50;\n\tconst leftPercent = 50 - halfFadePercent;\n\tconst rightPercent = 50 + halfFadePercent;\n\n\treturn [\n\t\t`linear-gradient(to right, ${bright} ${leftPercent}%, ${dark} ${rightPercent}%)`,\n\t\ttotalAspect,\n\t] as const;\n}\n","import type { LineMaskAnimator, MaskContext, MaskTargetWord } from \"./types.ts\";\nimport { generateFadeGradient } from \"./utils.ts\";\n\n/**\n * 使用 CSS calc() 表达式为行内所有单词应用逐词点亮的遮罩样式\n *\n * 运行环境不支持 Web Animations 驱动 mask-position 时的回退方案,\n * 依赖播放器在每帧更新 `--amll-player-time` CSS 变量来驱动遮罩移动,\n * 因此无需外部调度任何动画\n */\nexport class CalcMaskAnimator implements LineMaskAnimator {\n\tconstructor(\n\t\tprivate readonly words: ReadonlyArray<MaskTargetWord>,\n\t\tprivate readonly context: MaskContext,\n\t) {}\n\n\tpublic apply(): void {\n\t\tfor (const word of this.words) {\n\t\t\tconst {\n\t\t\t\tmainElement: wordEl,\n\t\t\t\twidth: textWidth,\n\t\t\t\tpadding: paddingLeft,\n\t\t\t\theight,\n\t\t\t\tstartTime,\n\t\t\t\tendTime,\n\t\t\t} = word;\n\n\t\t\tconst totalWordWidth = textWidth + paddingLeft * 2;\n\t\t\tconst fadeWidth = height * this.context.wordFadeWidth;\n\t\t\tconst [maskImage, totalAspect] = generateFadeGradient(\n\t\t\t\tfadeWidth / totalWordWidth,\n\t\t\t);\n\t\t\tconst totalAspectStr = `${totalAspect * 100}% 100%`;\n\n\t\t\tconst duration = Math.max(Math.abs(endTime - startTime), 1);\n\t\t\tconst speed = textWidth / duration;\n\t\t\tconst startPos = paddingLeft - totalWordWidth - fadeWidth / 2;\n\t\t\tconst minOffset = -totalWordWidth - fadeWidth;\n\n\t\t\tconst maskPos = `clamp(${minOffset}px, ${startPos}px + (var(--amll-player-time) - ${startTime}) * ${speed}px, 0px) 0px`;\n\n\t\t\tObject.assign(wordEl.style, {\n\t\t\t\tmaskImage,\n\t\t\t\twebkitMaskImage: maskImage,\n\t\t\t\tmaskRepeat: \"no-repeat\",\n\t\t\t\twebkitMaskRepeat: \"no-repeat\",\n\t\t\t\tmaskSize: totalAspectStr,\n\t\t\t\twebkitMaskSize: totalAspectStr,\n\t\t\t\tmaskPosition: maskPos,\n\t\t\t\twebkitMaskPosition: maskPos,\n\t\t\t});\n\t\t}\n\t}\n\n\tpublic setCurrentTime(_timeRelative: number, _isPlaying: boolean): void {}\n\tpublic pause(): void {}\n\tpublic resume(): void {}\n\n\tpublic dispose(): void {\n\t\tfor (const word of this.words) {\n\t\t\tconst wordEl = word.mainElement;\n\t\t\tif (wordEl) {\n\t\t\t\t[\"mask\", \"-webkit-mask\"].forEach((prop) => {\n\t\t\t\t\twordEl.style.removeProperty(prop);\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t}\n}\n","import type { LineMaskAnimator, MaskContext, MaskTargetWord } from \"./types.ts\";\nimport { generateFadeGradient } from \"./utils.ts\";\n\ninterface KeyframeTimelineCursor {\n\tcurPos: number;\n\tlastPos: number;\n\ttimeOffset: number;\n\tlastTime: number;\n\tlastTimeStamp: number;\n\tframes: Keyframe[];\n}\n\ninterface KeyframeConfig {\n\treadonly minOffset: number;\n\treadonly fadeWidth: number;\n}\n\n/**\n * 使用 Web Animations API 为行内所有单词创建逐词点亮的遮罩动画\n *\n * 创建后的动画均处于暂停状态,外部需要根据播放进度进行调度\n */\nexport class WebMaskAnimator implements LineMaskAnimator {\n\tprivate readonly animations: Animation[] = [];\n\tprivate readonly totalFadeDuration: number;\n\n\tconstructor(\n\t\tprivate readonly words: ReadonlyArray<MaskTargetWord>,\n\t\tprivate readonly context: MaskContext,\n\t) {\n\t\tthis.totalFadeDuration =\n\t\t\tthis.context.lineEndTime - this.context.lineStartTime;\n\t}\n\n\tpublic apply(): void {\n\t\tthis.buildAnimations();\n\t}\n\n\tpublic setCurrentTime(timeRelative: number, isPlaying: boolean): void {\n\t\tconst t = Math.min(this.totalFadeDuration, Math.max(0, timeRelative));\n\t\tfor (const a of this.animations) {\n\t\t\ta.currentTime = t;\n\t\t\ta.playbackRate = 1;\n\t\t\tconst endTime = this.getAnimationEndTime(a);\n\n\t\t\tif (isPlaying && t < endTime) {\n\t\t\t\ta.play();\n\t\t\t} else {\n\t\t\t\ta.pause();\n\t\t\t}\n\t\t}\n\t}\n\n\tpublic pause(): void {\n\t\tfor (const a of this.animations) {\n\t\t\ta.pause();\n\t\t}\n\t}\n\n\tpublic resume(): void {\n\t\tfor (const a of this.animations) {\n\t\t\tconst endTime = this.getAnimationEndTime(a);\n\t\t\tconst currentTime = Number(a.currentTime ?? 0);\n\n\t\t\tif (a.playState !== \"finished\" && currentTime < endTime) {\n\t\t\t\ta.play();\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate buildAnimations(): void {\n\t\tfor (const [i, word] of this.words.entries()) {\n\t\t\tconst wordEl = word.mainElement;\n\t\t\tif (!wordEl) continue;\n\n\t\t\tconst fadeWidth = word.height * this.context.wordFadeWidth;\n\n\t\t\tthis.updateWordMaskStyles(wordEl, word, fadeWidth);\n\n\t\t\tconst frames = this.generateWordKeyframes(word, i, fadeWidth);\n\n\t\t\ttry {\n\t\t\t\tconst ani = wordEl.animate(frames, {\n\t\t\t\t\tduration: Math.max(this.totalFadeDuration, 1),\n\t\t\t\t\tid: `fade-word-${word.word}-${i}`,\n\t\t\t\t\tfill: \"both\",\n\t\t\t\t});\n\t\t\t\tani.pause();\n\t\t\t\tthis.animations.push(ani);\n\t\t\t} catch (err) {\n\t\t\t\tconsole.warn(\n\t\t\t\t\t\"应用渐变动画发生错误\",\n\t\t\t\t\tframes,\n\t\t\t\t\tthis.totalFadeDuration,\n\t\t\t\t\terr,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * 为单个单词 DOM 元素配置 CSS 渐变遮罩样式\n\t */\n\tprivate updateWordMaskStyles(\n\t\twordEl: HTMLElement,\n\t\tword: MaskTargetWord,\n\t\tfadeWidth: number,\n\t): void {\n\t\tconst [maskImage, totalAspect] = generateFadeGradient(\n\t\t\tfadeWidth / (word.width + word.padding * 2),\n\t\t);\n\n\t\tObject.assign(wordEl.style, {\n\t\t\tmaskImage,\n\t\t\tmaskRepeat: \"no-repeat\",\n\t\t\tmaskSize: `${totalAspect * 100}% 100%`,\n\t\t});\n\t}\n\n\t/**\n\t * 推导时间轴并生成单个单词在播放周期内的所有遮罩关键帧\n\t */\n\tprivate generateWordKeyframes(\n\t\ttargetWord: MaskTargetWord,\n\t\ttargetIndex: number,\n\t\tfadeWidth: number,\n\t): Keyframe[] {\n\t\t// 计算目标单词的前置累加宽度与有效位移边界\n\t\tconst widthBeforeSelf =\n\t\t\tthis.words.slice(0, targetIndex).reduce((a, b) => a + b.width, 0) +\n\t\t\t(this.words[0] ? fadeWidth : 0);\n\n\t\tconst minOffset = -(targetWord.width + targetWord.padding * 2 + fadeWidth);\n\t\tconst initialPos =\n\t\t\t-widthBeforeSelf - targetWord.width - targetWord.padding - fadeWidth;\n\n\t\tconst config: KeyframeConfig = { minOffset, fadeWidth };\n\t\tconst cursor: KeyframeTimelineCursor = {\n\t\t\tcurPos: initialPos,\n\t\t\tlastPos: initialPos,\n\t\t\ttimeOffset: 0,\n\t\t\tlastTime: 0,\n\t\t\tlastTimeStamp: 0,\n\t\t\tframes: [],\n\t\t};\n\n\t\t// 压入起始帧\n\t\tthis.pushClampedKeyframe(cursor, config.minOffset);\n\n\t\t// 遍历整行所有音节推进时间线\n\t\tfor (const [j, otherWord] of this.words.entries()) {\n\t\t\t// 处理单词开始前的停顿区间\n\t\t\tthis.advancePauseTimeline(cursor, otherWord.startTime, config);\n\n\t\t\t// 处理单词播放时的移动区间\n\t\t\tconst rubySegments =\n\t\t\t\totherWord.ruby?.filter((r) => Boolean(r?.word?.trim())) ?? [];\n\t\t\tif (rubySegments.length > 0) {\n\t\t\t\tthis.advanceRubyWordTimeline(\n\t\t\t\t\tcursor,\n\t\t\t\t\totherWord,\n\t\t\t\t\trubySegments,\n\t\t\t\t\tconfig,\n\t\t\t\t\tj,\n\t\t\t\t);\n\t\t\t} else {\n\t\t\t\tthis.advancePlainWordTimeline(cursor, otherWord, config, j);\n\t\t\t}\n\t\t}\n\n\t\treturn cursor.frames;\n\t}\n\n\tprivate advancePauseTimeline(\n\t\tcursor: KeyframeTimelineCursor,\n\t\ttargetStartTime: number,\n\t\tconfig: KeyframeConfig,\n\t): void {\n\t\tconst curTimeStamp = targetStartTime - this.context.lineStartTime;\n\t\tconst staticDuration = curTimeStamp - cursor.lastTimeStamp;\n\n\t\tif (staticDuration > 0) {\n\t\t\tthis.advanceTimelineStep(cursor, config, staticDuration, 0);\n\t\t}\n\t\tcursor.lastTimeStamp = curTimeStamp;\n\t}\n\n\t/**\n\t * 推导带有 Ruby 注音的多音节单词时间线\n\t *\n\t * 原理是把每个主音节的总宽度均分给 ruby 片段总数,并应用每个 ruby 片段的时间给主音节\n\t *\n\t * 此功能具有诸多缺陷,如下所示:\n\t * 1. 汉字是一个紧凑的表意单位,内部由形旁、声旁或笔画构成,与读音之间不存在从左到右的序列关系,\n\t * 像是一个多音节英语单词按连字符分开时间轴和停顿这才有语义\n\t * 2. 在主音节中间分时间和停顿会导致用户必须将视线焦点从主音节上移到上方的 ruby\n\t * 注音,以寻找音节锚点,显然破坏用户预期\n\t * 3. ruby 的注音功能已由逐字音译承担\n\t *\n\t * 但考虑到功能已进入生产环境,因此保留此功能\n\t */\n\tprivate advanceRubyWordTimeline(\n\t\tcursor: KeyframeTimelineCursor,\n\t\totherWord: MaskTargetWord,\n\t\trubySegments: NonNullable<MaskTargetWord[\"ruby\"]>,\n\t\tconfig: KeyframeConfig,\n\t\twordIndex: number,\n\t): void {\n\t\tconst rubyCharCount = rubySegments.reduce(\n\t\t\t(sum, r) => sum + r.word.length,\n\t\t\t0,\n\t\t);\n\t\tconst widthPerChar = otherWord.width / rubyCharCount;\n\t\tlet charIndex = 0;\n\n\t\tfor (const ruby of rubySegments) {\n\t\t\tconst rubyStart = Math.max(ruby.startTime, otherWord.startTime);\n\t\t\tconst rubyEnd = Math.min(\n\t\t\t\tMath.max(ruby.endTime, rubyStart),\n\t\t\t\totherWord.endTime,\n\t\t\t);\n\n\t\t\tconst rubyStartStamp = rubyStart - this.context.lineStartTime;\n\t\t\tconst rubyStaticDuration = rubyStartStamp - cursor.lastTimeStamp;\n\t\t\tif (rubyStaticDuration > 0) {\n\t\t\t\tthis.advanceTimelineStep(cursor, config, rubyStaticDuration, 0);\n\t\t\t}\n\t\t\tcursor.lastTimeStamp = rubyStartStamp;\n\n\t\t\tconst rubyDuration = Math.max(0, rubyEnd - rubyStart);\n\t\t\tconst perCharDuration = rubyDuration / ruby.word.length;\n\n\t\t\tfor (let i = 0; i < ruby.word.length; i++) {\n\t\t\t\tlet movePx = widthPerChar;\n\t\t\t\tif (wordIndex === 0 && charIndex === 0)\n\t\t\t\t\tmovePx += config.fadeWidth * 1.5;\n\t\t\t\tif (\n\t\t\t\t\twordIndex === this.words.length - 1 &&\n\t\t\t\t\tcharIndex === rubyCharCount - 1\n\t\t\t\t)\n\t\t\t\t\tmovePx += config.fadeWidth * 0.5;\n\n\t\t\t\tthis.advanceTimelineStep(cursor, config, perCharDuration, movePx);\n\t\t\t\tcursor.lastTimeStamp += perCharDuration;\n\t\t\t\tcharIndex++;\n\t\t\t}\n\t\t}\n\n\t\tconst wordEndStamp = Math.max(\n\t\t\totherWord.endTime - this.context.lineStartTime,\n\t\t\tcursor.lastTimeStamp,\n\t\t);\n\t\tconst wordTailDuration = wordEndStamp - cursor.lastTimeStamp;\n\t\tif (wordTailDuration > 0) {\n\t\t\tthis.advanceTimelineStep(cursor, config, wordTailDuration, 0);\n\t\t}\n\t\tcursor.lastTimeStamp = wordEndStamp;\n\t}\n\n\tprivate advancePlainWordTimeline(\n\t\tcursor: KeyframeTimelineCursor,\n\t\totherWord: MaskTargetWord,\n\t\tconfig: KeyframeConfig,\n\t\twordIndex: number,\n\t): void {\n\t\tconst { startTime, endTime, width } = otherWord;\n\t\tconst fadeDuration = Math.max(0, endTime - startTime);\n\n\t\tlet movePx = width;\n\t\tif (wordIndex === 0) {\n\t\t\tmovePx += config.fadeWidth * 1.5;\n\t\t}\n\t\tif (wordIndex === this.words.length - 1) {\n\t\t\tmovePx += config.fadeWidth * 0.5;\n\t\t}\n\n\t\tthis.advanceTimelineStep(cursor, config, fadeDuration, movePx);\n\t\tcursor.lastTimeStamp += fadeDuration;\n\t}\n\n\tprivate advanceTimelineStep(\n\t\tcursor: KeyframeTimelineCursor,\n\t\tconfig: KeyframeConfig,\n\t\tduration: number,\n\t\tmovePx: number,\n\t): void {\n\t\tcursor.timeOffset += duration / this.totalFadeDuration;\n\t\tcursor.curPos += movePx;\n\n\t\tif (duration > 0) {\n\t\t\tthis.pushClampedKeyframe(cursor, config.minOffset);\n\t\t}\n\t}\n\n\tprivate pushClampedKeyframe(\n\t\tcursor: KeyframeTimelineCursor,\n\t\tminOffset: number,\n\t): void {\n\t\tconst moveOffset = cursor.curPos - cursor.lastPos;\n\t\tconst time = Math.min(1, Math.max(0, cursor.timeOffset));\n\t\tconst duration = time - cursor.lastTime;\n\t\tconst msPerPixel = moveOffset !== 0 ? Math.abs(duration / moveOffset) : 0;\n\n\t\t// 穿越左侧不可见边界进入有效视野时,插值一个折点\n\t\tif (cursor.curPos > minOffset && cursor.lastPos < minOffset) {\n\t\t\tconst staticTime = Math.abs(cursor.lastPos - minOffset) * msPerPixel;\n\t\t\tcursor.frames.push({\n\t\t\t\toffset: cursor.lastTime + staticTime,\n\t\t\t\tmaskPosition: `${Math.min(Math.max(cursor.lastPos, minOffset), 0)}px 0`,\n\t\t\t});\n\t\t}\n\n\t\t// 穿越右侧越界边界时,插值一个折点\n\t\tif (cursor.curPos > 0 && cursor.lastPos < 0) {\n\t\t\tconst staticTime = Math.abs(cursor.lastPos) * msPerPixel;\n\t\t\tcursor.frames.push({\n\t\t\t\toffset: cursor.lastTime + staticTime,\n\t\t\t\tmaskPosition: `${Math.min(Math.max(cursor.curPos, minOffset), 0)}px 0`,\n\t\t\t});\n\t\t}\n\n\t\tcursor.frames.push({\n\t\t\toffset: time,\n\t\t\tmaskPosition: `${Math.min(Math.max(cursor.curPos, minOffset), 0)}px 0`,\n\t\t});\n\n\t\tcursor.lastPos = cursor.curPos;\n\t\tcursor.lastTime = time;\n\t}\n\n\tprivate getAnimationEndTime(animation: Animation): number {\n\t\tconst timing = animation.effect?.getComputedTiming();\n\t\treturn Number(timing?.delay ?? 0) + Number(timing?.duration ?? 0);\n\t}\n\n\tpublic dispose(): void {\n\t\tfor (const a of this.animations) {\n\t\t\ta.cancel();\n\t\t}\n\t\tthis.animations.length = 0;\n\n\t\tfor (const word of this.words) {\n\t\t\tconst wordEl = word.mainElement;\n\t\t\tif (wordEl) {\n\t\t\t\twordEl.style.removeProperty(\"mask\");\n\t\t\t}\n\t\t}\n\t}\n}\n","import { CalcMaskAnimator } from \"./animator-calc.ts\";\nimport { WebMaskAnimator } from \"./animator-web.ts\";\nimport type { LineMaskAnimator, MaskContext, MaskTargetWord } from \"./types.ts\";\n\nexport * from \"./types.ts\";\n\nexport function createLineMaskAnimator(\n\twords: ReadonlyArray<MaskTargetWord>,\n\tcontext: MaskContext,\n): LineMaskAnimator {\n\tif (context.supportMaskImage) {\n\t\treturn new WebMaskAnimator(words, context);\n\t} else {\n\t\treturn new CalcMaskAnimator(words, context);\n\t}\n}\n","import type { LyricLine, LyricWord } from \"#interfaces\";\nimport { LyricLineRenderMode } from \"#lyric/base/consts.ts\";\nimport { LyricLineBase } from \"#lyric/base/line.ts\";\nimport styles from \"#styles/lyric-player.module.css\";\nimport { clampPositive } from \"#utils/clamp.ts\";\nimport { isCJK } from \"#utils/is-cjk.ts\";\nimport { LineBalancer } from \"#utils/line-balancer.ts\";\nimport { chunkAndSplitLyricWords } from \"#utils/lyric-split-words.ts\";\nimport { Duration } from \"#utils/time.ts\";\nimport type { DomLyricPlayer } from \".\";\nimport {\n\tcreateEmphasizeAnimation,\n\tcreateFloatAnimation,\n\tcreateLineMaskAnimator,\n\ttype LineMaskAnimator,\n} from \"./animation/index.ts\";\n\ninterface RealWord extends LyricWord {\n\tmainElement: HTMLSpanElement;\n\tsubElements: HTMLSpanElement[];\n\telementAnimations: Animation[];\n\twidth: number;\n\theight: number;\n\tpadding: number;\n\tshouldEmphasize: boolean;\n}\n\nexport class LyricLineEl extends LyricLineBase {\n\tprivate readonly element: HTMLElement = document.createElement(\"div\");\n\tprivate splittedWords: RealWord[] = [];\n\t// 标记是否已经构建了行内的实际 DOM(单词与动画等)\n\tprivate built = false;\n\n\tprivate renderMode: LyricLineRenderMode = LyricLineRenderMode.SOLID;\n\tprivate maskAnimator?: LineMaskAnimator;\n\n\tprivate lastScaleNum = -1;\n\n\tprivate readonly lineHasRubyWords: boolean;\n\tprivate readonly lineHasRomanWords: boolean;\n\n\t/**\n\t * 用于平衡换行、尽量减少各行长度差异的类\n\t */\n\tprivate readonly balancer?: LineBalancer;\n\n\tconstructor(\n\t\tprivate readonly lyricPlayer: DomLyricPlayer,\n\t\tprivate readonly lyricLine: LyricLine = {\n\t\t\twords: [],\n\t\t\ttranslatedLyric: \"\",\n\t\t\tromanLyric: \"\",\n\t\t\tstartTime: 0,\n\t\t\tendTime: 0,\n\t\t\tisBG: false,\n\t\t\tisDuet: false,\n\t\t},\n\t) {\n\t\tsuper();\n\t\tthis.lineHasRubyWords = this.lyricLine.words.some(\n\t\t\t(word) => (word.ruby?.length ?? 0) > 0,\n\t\t);\n\t\tthis.lineHasRomanWords = this.lyricLine.words.some(\n\t\t\t(word) => (word.romanWord?.trim().length ?? 0) > 0,\n\t\t);\n\t\tthis.element.setAttribute(\"class\", styles.lyricLine);\n\t\tif (this.lyricLine.isBG) {\n\t\t\tthis.element.classList.add(styles.lyricBgLine);\n\t\t}\n\t\tif (this.lyricLine.isDuet) {\n\t\t\tthis.element.classList.add(styles.lyricDuetLine);\n\t\t}\n\t\tthis.element.appendChild(document.createElement(\"div\")); // 歌词行\n\t\tthis.element.appendChild(document.createElement(\"div\")); // 翻译行\n\t\tthis.element.appendChild(document.createElement(\"div\")); // 音译行\n\t\tconst main = this.element.children[0] as HTMLDivElement;\n\t\tconst trans = this.element.children[1] as HTMLDivElement;\n\t\tconst roman = this.element.children[2] as HTMLDivElement;\n\t\tmain.setAttribute(\"class\", styles.lyricMainLine);\n\t\ttrans.setAttribute(\"class\", styles.lyricSubLine);\n\t\troman.setAttribute(\"class\", styles.lyricSubLine);\n\t\tif (LyricLineBase.wordSegmenter) {\n\t\t\tthis.balancer = new LineBalancer(main);\n\t\t}\n\t\t// 延迟构建具体行内容,进入可视区(含 overscan)时再构建\n\t\tthis.rebuildStyle();\n\t}\n\n\tprivate isEnabled = false;\n\tasync enable(\n\t\tmaskAnimationTime: number = this.lyricPlayer.getCurrentTime(),\n\t\tshouldPlay: boolean = this.lyricPlayer.getIsPlaying(),\n\t): Promise<void> {\n\t\tthis.isEnabled = true;\n\t\tthis.element.classList.add(styles.active);\n\t\tconst main = this.element.children[0] as HTMLDivElement;\n\n\t\tconst relativeTime = clampPositive(\n\t\t\tmaskAnimationTime - this.lyricLine.startTime,\n\t\t);\n\n\t\tfor (const word of this.splittedWords) {\n\t\t\tfor (const a of word.elementAnimations) {\n\t\t\t\ta.currentTime = relativeTime;\n\t\t\t\ta.playbackRate = 1;\n\n\t\t\t\tconst timing = a.effect?.getComputedTiming();\n\t\t\t\tconst endTime =\n\t\t\t\t\tNumber(timing?.delay ?? 0) + Number(timing?.duration ?? 0);\n\t\t\t\tif (shouldPlay && relativeTime < endTime) a.play();\n\t\t\t\telse a.pause();\n\t\t\t}\n\t\t}\n\n\t\tthis.maskAnimator?.setCurrentTime(relativeTime, shouldPlay);\n\n\t\tmain.classList.add(styles.active);\n\t}\n\n\tdisable(): void {\n\t\tthis.isEnabled = false;\n\t\tthis.element.classList.remove(styles.active);\n\t\tthis.setRenderMode(LyricLineRenderMode.SOLID);\n\n\t\tconst main = this.element.children[0] as HTMLDivElement;\n\n\t\tfor (const word of this.splittedWords) {\n\t\t\tfor (const a of word.elementAnimations) {\n\t\t\t\tif (\n\t\t\t\t\ta.id === \"float-word\" ||\n\t\t\t\t\ta.id.includes(\"emphasize-word-float-only\")\n\t\t\t\t) {\n\t\t\t\t\ta.playbackRate = -1;\n\t\t\t\t\ta.play();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tthis.maskAnimator?.pause();\n\t\tmain.classList.remove(styles.active);\n\t}\n\n\tprivate lastWord?: RealWord;\n\n\tasync resume(): Promise<void> {\n\t\tif (!this.isEnabled) return;\n\t\tfor (const word of this.splittedWords) {\n\t\t\tfor (const a of word.elementAnimations) {\n\t\t\t\tif (\n\t\t\t\t\t!this.lastWord ||\n\t\t\t\t\tthis.splittedWords.indexOf(this.lastWord) <\n\t\t\t\t\t\tthis.splittedWords.indexOf(word)\n\t\t\t\t) {\n\t\t\t\t\tconst timing = a.effect?.getComputedTiming();\n\t\t\t\t\tconst endTime =\n\t\t\t\t\t\tNumber(timing?.delay ?? 0) + Number(timing?.duration ?? 0);\n\t\t\t\t\tif (\n\t\t\t\t\t\ta.playState !== \"finished\" &&\n\t\t\t\t\t\t((a.currentTime as number) || 0) < endTime\n\t\t\t\t\t)\n\t\t\t\t\t\ta.play();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tthis.maskAnimator?.resume();\n\t}\n\n\tasync pause(): Promise<void> {\n\t\tif (!this.isEnabled) return;\n\t\tfor (const word of this.splittedWords) {\n\t\t\tfor (const a of word.elementAnimations) {\n\t\t\t\ta.pause();\n\t\t\t}\n\t\t}\n\t\tthis.maskAnimator?.pause();\n\t}\n\n\tgetLine(): LyricLine {\n\t\treturn this.lyricLine;\n\t}\n\t// private _hide = true;\n\n\tshow(): void {\n\t\tif (!this.built) {\n\t\t\tthis.rebuildElement();\n\t\t\tthis.built = true;\n\t\t\tthis.updateMaskImageSync();\n\t\t}\n\t}\n\n\tprivate rebuildStyle(): void {\n\t\tconst style = this.element.style;\n\t\tconst currentScale = this.lineTransforms.scale.getCurrentPosition() / 100;\n\n\t\tif (Math.abs(currentScale - this.lastScaleNum) >= 0.0001) {\n\t\t\tthis.lastScaleNum = currentScale;\n\t\t\tstyle.transform = `scale(${currentScale.toFixed(3)})`;\n\t\t}\n\t}\n\n\toverride rebuildElement(): void {\n\t\tthis.disposeElements();\n\t\tconst main = this.element.children[0] as HTMLDivElement;\n\t\tconst trans = this.element.children[1] as HTMLDivElement;\n\t\tconst roman = this.element.children[2] as HTMLDivElement;\n\t\t// 非动态歌词,直接渲染整行与副行\n\t\tif (this.lyricPlayer._getIsNonDynamic()) {\n\t\t\tmain.textContent = this.lyricLine.words.map((w) => w.word).join(\"\");\n\t\t\tthis.setSubLinesText(trans, roman);\n\t\t\treturn;\n\t\t}\n\n\t\tconst chunkedWords = chunkAndSplitLyricWords(this.lyricLine.words);\n\t\tmain.innerHTML = \"\";\n\n\t\tfor (const chunk of chunkedWords) {\n\t\t\tthis.buildWord(chunk, main);\n\t\t}\n\n\t\tthis.setSubLinesText(trans, roman);\n\t}\n\n\t/** 设置翻译与音译行文本 */\n\tprivate setSubLinesText(trans: HTMLDivElement, roman: HTMLDivElement) {\n\t\ttrans.textContent = this.lyricLine.translatedLyric;\n\t\troman.textContent = this.lyricLine.romanLyric;\n\t}\n\n\tprivate getRubyCharCount(word: LyricWord) {\n\t\treturn (word.ruby ?? []).reduce(\n\t\t\t(total, ruby) => total + ruby.word.length,\n\t\t\t0,\n\t\t);\n\t}\n\n\tprivate getRubySegments(word: LyricWord) {\n\t\treturn (word.ruby ?? []).filter(\n\t\t\t(ruby) => (ruby?.word?.trim().length ?? 0) > 0,\n\t\t);\n\t}\n\n\tprivate createWord(word: LyricWord, shouldEmphasize: boolean): RealWord {\n\t\tconst mainWordEl = document.createElement(\"span\");\n\t\tconst subElements: HTMLSpanElement[] = [];\n\t\tconst romanWord = word.romanWord?.trim() ?? \"\";\n\t\tconst wordContainer = this.lineHasRubyWords\n\t\t\t? document.createElement(\"span\")\n\t\t\t: mainWordEl;\n\t\tconst wordTextContainer = this.lineHasRubyWords\n\t\t\t? document.createElement(\"span\")\n\t\t\t: wordContainer;\n\n\t\tif (this.lineHasRubyWords) {\n\t\t\tconst rubyWordEl = document.createElement(\"span\");\n\t\t\tconst rubySegments = this.getRubySegments(word);\n\t\t\tfor (const ruby of rubySegments) {\n\t\t\t\tconst rubyPartEl = document.createElement(\"span\");\n\t\t\t\trubyPartEl.textContent = ruby.word;\n\t\t\t\trubyPartEl.dataset.startTime = String(ruby.startTime);\n\t\t\t\trubyPartEl.dataset.endTime = String(ruby.endTime);\n\t\t\t\trubyWordEl.appendChild(rubyPartEl);\n\t\t\t}\n\t\t\trubyWordEl.classList.add(styles.rubyWord);\n\t\t\tmainWordEl.classList.add(styles.wordWithRuby);\n\t\t\twordContainer.classList.add(styles.wordBody);\n\t\t\twordTextContainer.classList.add(styles.rubyBaseWord);\n\t\t\twordContainer.appendChild(wordTextContainer);\n\t\t\tmainWordEl.appendChild(rubyWordEl);\n\t\t\tmainWordEl.appendChild(wordContainer);\n\t\t}\n\n\t\tconst displayWord = word.word;\n\n\t\tif (shouldEmphasize) {\n\t\t\tmainWordEl.classList.add(styles.emphasize);\n\t\t\tconst trimmedWord = displayWord.trim();\n\n\t\t\tif (LyricLineBase.graphemeSegmenter) {\n\t\t\t\tfor (const { segment } of LyricLineBase.graphemeSegmenter.segment(\n\t\t\t\t\ttrimmedWord,\n\t\t\t\t)) {\n\t\t\t\t\tconst charEl = document.createElement(\"span\");\n\t\t\t\t\tcharEl.textContent = segment;\n\t\t\t\t\tsubElements.push(charEl);\n\t\t\t\t\twordTextContainer.appendChild(charEl);\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tfor (const segment of Array.from(trimmedWord)) {\n\t\t\t\t\tconst charEl = document.createElement(\"span\");\n\t\t\t\t\tcharEl.textContent = segment;\n\t\t\t\t\tsubElements.push(charEl);\n\t\t\t\t\twordTextContainer.appendChild(charEl);\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\tif (this.lineHasRomanWords) {\n\t\t\t\tconst wordEl = document.createElement(\"span\");\n\t\t\t\twordEl.textContent = displayWord.trim();\n\t\t\t\twordTextContainer.appendChild(wordEl);\n\t\t\t} else if (romanWord.length === 0) {\n\t\t\t\twordTextContainer.textContent = displayWord.trim();\n\t\t\t}\n\t\t}\n\n\t\tif (this.lineHasRomanWords) {\n\t\t\tconst romanWordEl = document.createElement(\"span\");\n\t\t\tromanWordEl.textContent = romanWord.length > 0 ? romanWord : \"\\u00A0\";\n\t\t\tromanWordEl.classList.add(styles.romanWord);\n\t\t\twordContainer.appendChild(romanWordEl);\n\t\t}\n\n\t\tconst realWord: RealWord = {\n\t\t\t...word,\n\t\t\tmainElement: mainWordEl,\n\t\t\tsubElements: subElements,\n\t\t\telementAnimations: [\n\t\t\t\tcreateFloatAnimation(mainWordEl, {\n\t\t\t\t\tword: word,\n\t\t\t\t\tlineStartTime: this.lyricLine.startTime,\n\t\t\t\t\tisBG: this.lyricLine.isBG,\n\t\t\t\t}),\n\t\t\t],\n\t\t\twidth: 0,\n\t\t\theight: 0,\n\t\t\tpadding: 0,\n\t\t\tshouldEmphasize: shouldEmphasize,\n\t\t};\n\n\t\treturn realWord;\n\t}\n\n\tprivate buildWord(input: LyricWord | LyricWord[], main: HTMLDivElement) {\n\t\tconst chunk = Array.isArray(input) ? input : [input];\n\t\tif (chunk.length === 0) return;\n\n\t\tconst isPureSpace = chunk.every((w) => !w.word.trim());\n\t\tif (isPureSpace) {\n\t\t\tconst textContent = chunk.map((w) => w.word).join(\"\");\n\t\t\tmain.appendChild(document.createTextNode(textContent));\n\t\t\treturn;\n\t\t}\n\n\t\tconst merged = chunk.reduce(\n\t\t\t(a, b) => {\n\t\t\t\ta.endTime = Math.max(a.endTime, b.endTime);\n\t\t\t\ta.startTime = Math.min(a.startTime, b.startTime);\n\t\t\t\ta.word += b.word;\n\t\t\t\treturn a;\n\t\t\t},\n\t\t\t{\n\t\t\t\tword: \"\",\n\t\t\t\tromanWord: \"\",\n\t\t\t\tstartTime: Number.POSITIVE_INFINITY,\n\t\t\t\tendTime: Number.NEGATIVE_INFINITY,\n\t\t\t\twordType: \"normal\",\n\t\t\t\tobscene: false,\n\t\t\t} as LyricWord,\n\t\t);\n\n\t\tlet emp = chunk.some((word) => LyricLineBase.shouldEmphasize(word));\n\t\tif (!isCJK(merged.word)) {\n\t\t\temp = emp || LyricLineBase.shouldEmphasize(merged);\n\t\t}\n\n\t\tconst wrapperWordEl = document.createElement(\"span\");\n\t\twrapperWordEl.classList.add(styles.emphasizeWrapper);\n\n\t\tconst characterElements: HTMLElement[] = [];\n\n\t\tfor (const word of chunk) {\n\t\t\tif (!word.word.trim()) {\n\t\t\t\twrapperWordEl.appendChild(document.createTextNode(word.word));\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst realWord = this.createWord(word, emp);\n\n\t\t\tif (emp) {\n\t\t\t\tcharacterElements.push(...realWord.subElements);\n\t\t\t}\n\n\t\t\tthis.splittedWords.push(realWord);\n\t\t\twrapperWordEl.appendChild(realWord.mainElement);\n\t\t}\n\n\t\tif (emp && this.splittedWords.length > 0) {\n\t\t\tconst lastWordOfChunk = this.splittedWords[this.splittedWords.length - 1];\n\t\t\tconst rubyCharCount = chunk.reduce(\n\t\t\t\t(total, word) => total + this.getRubyCharCount(word),\n\t\t\t\t0,\n\t\t\t);\n\n\t\t\tconst lineWords = this.lyricLine.words;\n\t\t\tconst isLastWord =\n\t\t\t\tlineWords.length > 0 &&\n\t\t\t\tmerged.word.includes(lineWords[lineWords.length - 1].word);\n\n\t\t\tlastWordOfChunk.elementAnimations.push(\n\t\t\t\t...createEmphasizeAnimation({\n\t\t\t\t\tword: merged,\n\t\t\t\t\tcharacterElements: characterElements,\n\t\t\t\t\tduration: merged.endTime - merged.startTime,\n\t\t\t\t\tdelay: merged.startTime - this.lyricLine.startTime,\n\t\t\t\t\trubyCharCount: rubyCharCount,\n\t\t\t\t\tisBG: this.lyricLine.isBG,\n\t\t\t\t\tisLastWord: isLastWord,\n\t\t\t\t}),\n\t\t\t);\n\t\t}\n\n\t\tmain.appendChild(wrapperWordEl);\n\t}\n\n\toverride onLineSizeChange(_size: [number, number]): void {\n\t\tthis.updateMaskImageSync();\n\t}\n\tupdateMaskImageSync(): void {\n\t\tfor (const word of this.splittedWords) {\n\t\t\tconst el = word.mainElement;\n\t\t\tif (el) {\n\t\t\t\tword.padding = Number.parseFloat(getComputedStyle(el).paddingLeft);\n\t\t\t\tword.width = el.clientWidth - word.padding * 2;\n\t\t\t\tword.height = el.clientHeight - word.padding * 2;\n\t\t\t} else {\n\t\t\t\tword.width = 0;\n\t\t\t\tword.height = 0;\n\t\t\t\tword.padding = 0;\n\t\t\t}\n\t\t}\n\t\tif (this.balancer && LyricLineBase.wordSegmenter) {\n\t\t\tthis.balancer.balanceLineBreaks(\n\t\t\t\tthis.lyricPlayer._getIsNonDynamic(),\n\t\t\t\tthis.splittedWords.length > 0,\n\t\t\t\tLyricLineBase.wordSegmenter,\n\t\t\t);\n\t\t}\n\n\t\tthis.maskAnimator?.dispose();\n\n\t\t// 因为歌词行有可能比行内单词的结束时间早,有可能导致过渡动画提早停止出现瑕疵\n\t\t// 所以要以单词的结束时间为准\n\t\tconst maxEndTime = Math.max(\n\t\t\t0,\n\t\t\t...this.splittedWords.map((w) => w.endTime),\n\t\t\tthis.lyricLine.endTime,\n\t\t);\n\n\t\tthis.maskAnimator = createLineMaskAnimator(this.splittedWords, {\n\t\t\tlineStartTime: this.lyricLine.startTime,\n\t\t\tlineEndTime: maxEndTime,\n\t\t\twordFadeWidth: this.lyricPlayer.getWordFadeWidth(),\n\t\t\tsupportMaskImage: this.lyricPlayer.supportMaskImage,\n\t\t});\n\n\t\tthis.maskAnimator.apply();\n\n\t\tif (this.isEnabled) {\n\t\t\tconst isPlayerRunning = this.lyricPlayer.getIsPlaying?.() ?? true;\n\t\t\tthis.enable(this.lyricPlayer.getCurrentTime(), isPlayerRunning);\n\t\t}\n\t}\n\n\tgetElement(): HTMLElement {\n\t\treturn this.element;\n\t}\n\n\tprivate setRenderMode(mode: LyricLineRenderMode): void {\n\t\tif (this.renderMode === mode) return;\n\t\tthis.renderMode = mode;\n\t\tthis.element.classList.toggle(\n\t\t\tstyles.gradientMask,\n\t\t\tmode === LyricLineRenderMode.GRADIENT,\n\t\t);\n\t}\n\n\toverride setTransform(\n\t\tscale: number = this.scale,\n\t\topacity: number = this.opacity,\n\t\tblur = 0,\n\t\tdelay: Duration = Duration.ZERO,\n\t\tmode: LyricLineRenderMode = LyricLineRenderMode.SOLID,\n\t): void {\n\t\tsuper.setTransform(scale, opacity, blur, delay);\n\n\t\tthis.setRenderMode(mode);\n\t\tthis.top = 0;\n\t\tthis.scale = scale;\n\t\tthis.delay = delay;\n\n\t\tif (this.lyricPlayer.getEnableSpring()) {\n\t\t\tthis.lineTransforms.scale.setTargetPosition(scale);\n\t\t} else {\n\t\t\tthis.lineTransforms.scale.setPosition(scale);\n\t\t}\n\t}\n\n\tupdate(delta: Duration = Duration.ZERO): void {\n\t\tif (!this.lyricPlayer.getEnableSpring()) return;\n\n\t\tconst scaleMoving = !this.lineTransforms.scale.arrived();\n\t\tthis.lineTransforms.scale.update(delta);\n\n\t\tif (scaleMoving) {\n\t\t\tthis.isUiDirty = true;\n\t\t}\n\t}\n\n\toverride commitChanges(): void {\n\t\tif (this.isUiDirty) {\n\t\t\tthis.rebuildStyle();\n\t\t\tthis.isUiDirty = false;\n\t\t}\n\t}\n\n\t/** @internal */\n\t_getDebugTargetPos(): string {\n\t\treturn `[位移: ${this.top}; 缩放: ${this.scale}; 延时: ${this.delay}]`;\n\t}\n\n\tprivate disposeElements() {\n\t\tthis.balancer?.reset();\n\t\tthis.maskAnimator?.dispose();\n\t\tthis.maskAnimator = undefined;\n\n\t\tfor (const realWord of this.splittedWords) {\n\t\t\tfor (const a of realWord.elementAnimations) {\n\t\t\t\ta.cancel();\n\t\t\t}\n\t\t\tfor (const sub of realWord.subElements) {\n\t\t\t\tsub.remove();\n\t\t\t\tsub.parentNode?.removeChild(sub);\n\t\t\t}\n\t\t\trealWord.elementAnimations = [];\n\t\t\trealWord.subElements = [];\n\t\t\tif (realWord.mainElement?.parentNode) {\n\t\t\t\trealWord.mainElement.parentNode.removeChild(realWord.mainElement);\n\t\t\t}\n\t\t}\n\t\tthis.splittedWords = [];\n\t\tconst main = this.element.children[0] as HTMLDivElement;\n\t\tconst trans = this.element.children[1] as HTMLDivElement;\n\t\tconst roman = this.element.children[2] as HTMLDivElement;\n\t\tif (main) main.innerHTML = \"\";\n\t\tif (trans) trans.innerHTML = \"\";\n\t\tif (roman) roman.innerHTML = \"\";\n\t}\n\toverride dispose(): void {\n\t\tthis.disposeElements();\n\t\tthis.lyricPlayer.resizeObserver.unobserve(this.element);\n\t\tthis.element.remove();\n\t}\n}\n","/**\n * @fileoverview\n * 一个播放歌词的组件\n * @author SteveXMH\n */\n\nimport \"#styles/index.css\";\nimport type { BottomLine } from \"#lyric/base/bottom-line.ts\";\nimport { MAX_FRAME_DELTA } from \"#lyric/base/consts.ts\";\nimport { LyricPlayerBase } from \"#lyric/base/index.ts\";\nimport type { LyricLineBase } from \"#lyric/base/line.ts\";\nimport styles from \"#styles/lyric-player.module.css\";\nimport { Duration } from \"#utils/time.ts\";\nimport { BottomLineEl } from \"./bottom-line.ts\";\nimport { InterludeDotsEl } from \"./interlude-dots.ts\";\nimport { LyricLineGroup } from \"./lyric-group.ts\";\nimport { LyricLineEl } from \"./lyric-line.ts\";\n\n/**\n * 歌词行鼠标相关事件,可以获取到歌词行的索引、主歌词行以及背景歌词行(如果有)元素\n */\nexport class LyricLineMouseEvent extends MouseEvent {\n\t/**\n\t * 自定义标志位,用于记录外部是否调用了 `stopPropagation`\n\t */\n\tpublic isPropagationStopped = false;\n\n\tconstructor(\n\t\t/**\n\t\t * 歌词行索引\n\t\t */\n\t\tpublic readonly lineIndex: number,\n\t\t/**\n\t\t * 歌词行元素\n\t\t */\n\t\tpublic readonly line: LyricLineBase,\n\t\t/**\n\t\t * 背景人声歌词行元素 (如果存在)\n\t\t */\n\t\tpublic readonly bgLine: LyricLineBase | undefined,\n\t\tevent: MouseEvent,\n\t) {\n\t\tsuper(`line-${event.type}`, event);\n\t}\n\n\toverride stopPropagation(): void {\n\t\tthis.isPropagationStopped = true;\n\t\tsuper.stopPropagation();\n\t}\n\n\toverride stopImmediatePropagation(): void {\n\t\tthis.isPropagationStopped = true;\n\t\tsuper.stopImmediatePropagation();\n\t}\n}\n\nexport type LyricLineMouseEventListener = (evt: LyricLineMouseEvent) => void;\n\n/**\n * 歌词播放组件,本框架的核心组件\n *\n * 尽可能贴切 Apple Music for iPad 的歌词效果设计,且做了力所能及的优化措施\n */\nexport class DomLyricPlayer extends LyricPlayerBase {\n\tprivate abortController = new AbortController();\n\toverride currentLyricGroups: LyricLineGroup[] = [];\n\n\toverride onResize(): void {\n\t\tconst computedStyles = getComputedStyle(this.element);\n\t\tthis._baseFontSize = Number.parseFloat(computedStyles.fontSize);\n\t\tthis.rebuildStyle();\n\t}\n\n\treadonly supportPlusLighter: boolean = CSS.supports(\n\t\t\"mix-blend-mode\",\n\t\t\"plus-lighter\",\n\t);\n\treadonly supportMaskImage: boolean = CSS.supports(\"mask-image\", \"none\");\n\treadonly innerSize: [number, number] = [0, 0];\n\n\tprivate readonly onMouseEventHandler = (e: MouseEvent) => {\n\t\tconst target = e.target;\n\t\tif (!(target instanceof Element)) return;\n\n\t\tconst groupEl = target.closest(`.${styles.lyricLineWrapper}`);\n\t\tif (!groupEl) return;\n\n\t\tconst group = this.lyricGroupElementMap.get(groupEl);\n\t\tif (!group) return;\n\n\t\tconst mainLine = group.mainLine;\n\t\tconst bgLine = group.bgLine;\n\t\tconst lineIndex = this.lyricLinesIndexes.get(mainLine) ?? -1;\n\n\t\tconst evt = new LyricLineMouseEvent(lineIndex, mainLine, bgLine, e);\n\t\tconst isDispatched = this.dispatchEvent(evt);\n\n\t\tif (!isDispatched || evt.defaultPrevented) {\n\t\t\te.preventDefault();\n\t\t}\n\n\t\tif (evt.isPropagationStopped) {\n\t\t\te.stopPropagation();\n\t\t\te.stopImmediatePropagation();\n\t\t}\n\t};\n\n\t/**\n\t * 是否为非逐词歌词\n\t * @internal\n\t */\n\t_getIsNonDynamic(): boolean {\n\t\treturn this.isNonDynamic;\n\t}\n\tprivate _baseFontSize = Number.parseFloat(\n\t\tgetComputedStyle(this.element).fontSize,\n\t);\n\tpublic get baseFontSize(): number {\n\t\treturn this._baseFontSize;\n\t}\n\tconstructor() {\n\t\tsuper();\n\t\tthis.onResize();\n\t\tthis.element.classList.add(\"amll-lyric-player\", \"dom\");\n\t\tif (this.disableSpring) {\n\t\t\tthis.element.classList.add(styles.disableSpring);\n\t\t}\n\n\t\tthis.element.addEventListener(\"click\", this.onMouseEventHandler, {\n\t\t\tsignal: this.abortController.signal,\n\t\t});\n\t\tthis.element.addEventListener(\"contextmenu\", this.onMouseEventHandler, {\n\t\t\tsignal: this.abortController.signal,\n\t\t});\n\t}\n\n\tprivate rebuildStyle() {\n\t\t// const width = this.innerSize[0];\n\t\t// const height = this.innerSize[1];\n\t\t// this.element.style.setProperty(\"--amll-lp-width\", `${width.toFixed(4)}px`);\n\t\t// this.element.style.setProperty(\n\t\t// \t\"--amll-lp-height\",\n\t\t// \t`${height.toFixed(4)}px`,\n\t\t// );\n\t}\n\n\toverride setWordFadeWidth(value = 0.5): void {\n\t\tsuper.setWordFadeWidth(value);\n\t\tfor (const group of this.currentLyricGroups) {\n\t\t\tgroup.mainLine.updateMaskImageSync();\n\t\t\tgroup.bgLine?.updateMaskImageSync();\n\t\t}\n\t}\n\n\tprotected override createInterludeDots(): InterludeDotsEl {\n\t\treturn new InterludeDotsEl();\n\t}\n\n\tprotected override createBottomLine(): BottomLine {\n\t\treturn new BottomLineEl(this);\n\t}\n\n\t/**\n\t * 重新构建歌词行和时间状态\n\t *\n\t * 一般用于在调用 {@link setLyricProcessConfig} 更新配置后手动刷新视图,\n\t * 或在外部样式/DOM 结构发生改变后重置歌词视图\n\t *\n\t * @param initialTime 重建后对齐的初始时间(毫秒),默认使用当前播放进度\n\t */\n\tprotected override buildLyricGroups(): void {\n\t\tif (this.hasDuetLine) {\n\t\t\tthis.element.classList.add(styles.hasDuetLine);\n\t\t} else {\n\t\t\tthis.element.classList.remove(styles.hasDuetLine);\n\t\t}\n\n\t\tlet currentGroup: LyricLineGroup | null = null;\n\n\t\tfor (let i = 0; i < this.processedLines.length; i++) {\n\t\t\tconst line = this.processedLines[i];\n\t\t\tconst lineEl = new LyricLineEl(this, line);\n\n\t\t\tthis.lyricLinesIndexes.set(lineEl, i);\n\n\t\t\tif (!line.isBG || !currentGroup) {\n\t\t\t\tcurrentGroup = new LyricLineGroup(this, lineEl);\n\t\t\t\tthis.currentLyricGroups.push(currentGroup);\n\t\t\t\tthis.lyricGroupElementMap.set(currentGroup.element, currentGroup);\n\t\t\t} else {\n\t\t\t\tcurrentGroup.addBgLine(lineEl);\n\t\t\t}\n\t\t}\n\t}\n\n\tpublic override rebuildLyricView(\n\t\tinitialTime: number = this.getCurrentTime(),\n\t): void {\n\t\tsuper.rebuildLyricView(initialTime);\n\t\tthis.setLinePosXSpringParams({});\n\t\tthis.setLinePosYSpringParams({});\n\t\tthis.setLineScaleSpringParams({});\n\t\tthis.update(0);\n\t}\n\n\toverride pause(): void {\n\t\tsuper.pause();\n\t\tthis.element.classList.remove(styles.playing);\n\t\tfor (const group of this.currentLyricGroups) {\n\t\t\tgroup.mainLine.pause();\n\t\t\tgroup.bgLine?.pause();\n\t\t}\n\t}\n\n\toverride resume(): void {\n\t\tsuper.resume();\n\t\tthis.element.classList.add(styles.playing);\n\t\tfor (const group of this.currentLyricGroups) {\n\t\t\tgroup.mainLine.resume();\n\t\t\tgroup.bgLine?.resume();\n\t\t}\n\t}\n\n\toverride update(delta = 0): void {\n\t\tconst d = Duration.min(Duration.fromMillis(delta), MAX_FRAME_DELTA);\n\t\tsuper.update(Duration.asMillis(d));\n\t\tif (!this.supportMaskImage) {\n\t\t\tthis.element.style.setProperty(\n\t\t\t\t\"--amll-player-time\",\n\t\t\t\t`${this.getCurrentTime()}`,\n\t\t\t);\n\t\t}\n\t\tif (!this.isPageVisible) return;\n\t\tfor (const group of this.currentLyricGroups) {\n\t\t\tgroup.update(d);\n\t\t}\n\n\t\tfor (const group of this.currentLyricGroups) {\n\t\t\tgroup.commitChanges();\n\t\t}\n\t}\n\n\toverride dispose(): void {\n\t\tsuper.dispose();\n\t\tthis.abortController.abort();\n\t\tthis.element.remove();\n\t\tfor (const group of this.currentLyricGroups) {\n\t\t\tgroup.dispose();\n\t\t}\n\t}\n}\n"],"mappings":"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"}