Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ Android-native Apple Music-like lyric renderer for YAQMC.

## Current replication status

The first thirty AMLL-parity passes now cover the main timing, annotation, interaction, focus-motion, measured layout, background-vocal geometry, line-transform, group-opacity, mask, responsive-wrapper, playback-control, end-of-song and emphasized-shadow behavior instead of relying on generic Compose defaults:
The first thirty-one AMLL-parity passes now cover the main timing, annotation, interaction, focus-motion, measured layout, background-vocal geometry, line-transform, group-opacity, mask, responsive-wrapper, playback-control, end-of-song, emphasized-shadow and annotation-mask behavior instead of relying on generic Compose defaults:

- active/inactive main-line scale follows AMLL's `1.0 / 0.97` behavior using the upstream physical scale spring
- `enableScale` mirrors upstream `setEnableScale()` and disables only the main-line 97% treatment; background-vocal 75% inactive scale remains independent
Expand All @@ -44,6 +44,9 @@ The first thirty AMLL-parity passes now cover the main timing, annotation, inter
- emphasized grapheme glow uses a zero-offset native text shadow with the upstream white color, direct `emphasis * blur` alpha and direct `min(0.3, blur * 0.3)em` blur radius; the renderer no longer adds halo scaling or extra alpha/radius attenuation
- the shadow is rendered per grapheme on Android 8+ without depending on API-31-only `RenderEffect`, while the existing karaoke bright/dark mask path remains unchanged
- ruby annotations and per-word romanization participate in merged word layout and ruby character count drives AMLL emphasis stagger anchors
- ruby, base glyphs and per-word romanization now sample one shared word-level bright-to-dark mask, matching upstream's `mainWordEl` mask ownership instead of using independent annotation progress clips
- ruby segment timing drives the whole measured word-mask sweep using UTF-16 code-unit counts like JavaScript `string.length`; the sweep pauses across ruby timing gaps and clamps segment timing to the word bounds
- annotation-aware mask geometry uses the full visual word-box width and stacked ruby + base + roman content height, with no native-only inter-band gap; roman text also preserves upstream's `0.3em` inline-end padding offset
- annotation layout reserves explicit above-baseline space so ruby/romanized text does not distort main-word timing geometry
- word/character motion is reconstructed directly from media time, so seeking is deterministic rather than free-running
- ordinary playback-clock `update(...)` samples are distinct from explicit host `seekTo(...)` calls, so explicit seeks always use seek-motion semantics
Expand All @@ -69,7 +72,7 @@ The first thirty AMLL-parity passes now cover the main timing, annotation, inter
- lyric typography uses the react-full default weight 600 consistently across main, secondary and background content; active-state changes no longer alter glyph metrics or wrapping
- CI builds the library/demo and runs native grouping, word-motion, text-shadow, annotation, interlude, interaction, spring, seek, focus-geometry, end-of-song, line-layout, background-motion, line-scale, opacity, continuous-mask, responsive-padding, behavior-flag, transform-policy and typography unit tests

The renderer is still evolving. Remaining fidelity work includes browser-CSS versus Android/Skia shadow-kernel rasterization differences, deeper ruby/roman annotation-mask parity, additional upstream configuration parity where useful, and platform-specific performance tuning.
The renderer is still evolving. Remaining fidelity work includes browser-CSS versus Android/Skia shadow-kernel rasterization differences, residual DOM-versus-Compose/Skia font-metric and subpixel annotation-layout differences, additional upstream configuration parity where useful, and platform-specific performance tuning.

## Non-goals for the first milestone

Expand Down
5 changes: 3 additions & 2 deletions docs/USAGE.zh-CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ LyricRuby(
)
```

同一个词可以有多个 ruby segment;每段有自己的高亮时间。
同一个词可以有多个 ruby segment;每段有自己的高亮时间。当前 renderer 与 upstream 一样,让 ruby、主字和逐词 `romanText` 共用同一个 word-level bright→dark mask;存在 ruby segment 时,segment 的时间会驱动整个词的 mask 扫描,并在 segment 间的时间空档保持当前位置。

### `LyricLine`

Expand Down Expand Up @@ -423,6 +423,7 @@ fun NativeFullScreenLyrics(
- 如果宿主只能低频提供 position,renderer 仍可工作,但逐词运动和 seek 判定精度会随采样精度下降;必要时可关闭 auto seek detection,但真实跳转仍应调用 `state.seekTo(...)`。
- 曲末判定来自所有主歌词 group 的最大 `endTimeMs`,不需要单独同步 media duration/end signal。
- emphasized grapheme glow 在 API 26+ 使用 native text shadow,直接采用 upstream 的零偏移、白色 shadow、em blur 半径和动画 alpha,不依赖 API 31 `RenderEffect`。
- ruby、主字与逐词 roman 共用同一个 word mask;ruby segment 的时间会驱动整个 visual word box 的扫描,宿主不需要额外同步 annotation progress。
- API 31+ 的歌词行距离模糊使用原生 blur effect;Android 8-11 会保留其它视觉层级而不强行使用不可用的 Gaussian RenderEffect。
- 手动触摸/滚轮滚动会暂停 auto-align;滚动与惯性停止后默认再等待 5 秒恢复。
- `horizontalPadding = Dp.Unspecified` 是默认值,表示使用 AMLL 的响应式 20dp/1em 规则;只有确实需要固定边距时再显式传 Dp。
Expand All @@ -433,7 +434,7 @@ fun NativeFullScreenLyrics(
当前重点是 AMLL 动态逐词歌词的 Android-native parity。仍在继续收敛的部分包括:

- emphasized text-shadow 的半径、颜色、alpha envelope、零偏移和逐 grapheme transform 已与 upstream 对齐,但浏览器 CSS 与 Android/Skia 的 blur kernel 仍可能产生少量像素级栅格差异;
- ruby/逐词 roman annotation 的 mask/DOM 几何还存在少量实现差异;
- ruby/逐词 roman 已与主字共用 word-level mask,并按 annotation-aware word box 与 ruby segment 时间推进;剩余差异主要来自 DOM 与 Compose/Skia 的字体度量、字形 shaping 和亚像素排版;
- 其它较少使用的上游配置与平台细节仍可继续补齐;
- 更多针对实际 YAQMC 大型歌词数据的性能压测。

Expand Down
Loading