---
name: reuse-project-utilities
description: Use when implementing, refactoring, or reviewing code in this repository and the task may duplicate existing helpers, libraries, visualizer utilities, lyrics utilities, font/color helpers, list virtualization, icon usage, i18n, playback adapters, or service patterns. Trigger before writing new utility functions or installing/hand-rolling functionality already present in the project.
---

# Reuse Project Utilities

## Purpose

这个 skill 用于防止“造一个颜色不同的轮子”。写代码前先查已有 helper、组件模式和项目已安装库，优先复用它们。

核心规则：

- 新增工具函数前，先用 `rg` 搜相同领域的现有函数。
- 外部库已经覆盖的能力，不要手写低配版。
- 复用项目里已经承载语义的 helper，而不是复制局部实现。
- 如果已有 helper 不够，优先扩展原 helper 并补测试，而不是另起相似名字。

## Fast Lookup

按任务类型先查这些入口：

- 歌词解析、时序、render end：`src/utils/lyrics/*`
- visualizer 运行时、背景、颜色：`src/components/visualizer/*`
- 字体栈和自定义字体：`src/utils/fontStacks.ts`、`src/services/customLyricsFont.ts`
- 播放队列、播放适配：`src/services/playbackAdapters.ts`、`src/utils/appPlaybackHelpers.ts`
- 网易云 / Navidrome / 本地音乐 API：`src/services/*`
- 主题、封面、取色、缓存：`src/hooks/themeControllerState.ts`、`src/utils/colorExtractor.ts`、`src/services/themeCache.ts`、`src/services/coverCache.ts`
- UI 图标、动画、弹窗、选择器：`lucide-react`、`framer-motion`、`components/shared/*`

推荐搜索：

```bash
rg -n "目标词|函数名|相邻概念" src test
rg -n "prepareWithSegments|layoutWithLines|useVisualizerRuntime|getLineRenderEndTime|resolveThemeFontStack|colorWithAlpha|mixColors" src
```

## Common Utilities

### Text Layout And Measurement

已安装 `@chenglou/pretext`，用于文字准备、测量和排版。

优先用：

```ts
import { prepareWithSegments, layoutWithLines } from '@chenglou/pretext';

const prepared = prepareWithSegments(text, fontSpec);
const layout = layoutWithLines(prepared, maxWidth, lineHeightPx);
const width = layout.lines[0]?.width ?? fallbackWidth;
```

适用场景：

- visualizer 文本宽度测量
- 歌词自动换行
- 气泡、块状文本、canvas overlay 的排版
- 需要和 CJK / grapheme 排版更接近真实浏览器表现的场景

不要手写 `text.length * fontSize` 作为主测量逻辑；只能作为 fallback。

### Visualizer Runtime

visualizer 当前行、上一行、下一行、预热窗口已有共享入口：

- `useVisualizerRuntime`
- `prepareActiveAndUpcoming`
- `shouldPreheatLine`
- `getUpcomingLine`
- `getUpcomingLines`

位置：`src/components/visualizer/runtime.ts`

新增 visualizer 时优先使用它们，不要重新写“当前行/下一行/最近完成行”扫描逻辑。

### Lyrics Timing Hints

歌词行显示结束时间和过短行处理已有统一 helper：

- `getLineRenderHints`
- `getLineRenderEndTime`
- `getLineTransitionTiming`
- `ensureLyricLinesRenderHints`

位置：`src/utils/lyrics/renderHints.ts`

需要决定 line exit、subtitle 保留、短行 fast/instant reveal 时，先用这些 helper。不要直接假设 `line.endTime` 就是视觉渲染结束时间。

写 visualizer 时同时遵守 `frontend-runtime-guardrails` 里的歌词输入契约：renderer 消费统一 `LyricData`，不要重新处理原始歌词格式或翻译对齐。

### Lyrics Layout Units

CJK 语义分组、sticky 标点、英文 contraction 已有布局工具：

- `buildPostLyricLayoutUnits`
- `buildDisplayWordsFromLayoutUnits`
- `createSingleWordLayoutUnits`

位置：`src/utils/lyrics/cjkSemanticLayout.ts`

新增按词/按块 visualizer 时，优先使用 layout units。不要在组件里临时拼接标点、撇号、CJK 字符。

### Font Stacks

主题字体和自定义字体已有 resolver：

- `resolveThemeFontStack`
- `resolveThemeTranslationFontStack`
- `getBuiltinThemeFontStack`

位置：`src/utils/fontStacks.ts`

需要 CSS `fontFamily`、canvas `font`、pretext `fontSpec` 时，先用 resolver。不要手写一份新的 fallback font stack。

### Visualizer Colors

visualizer 颜色混合和 alpha 已有 helper：

- `colorWithAlpha(color, alpha)`
- `mixColors(from, to, amount, alpha?)`

位置：`src/components/visualizer/colorMix.ts`

需要 `rgba(...)`、主题色混合、canvas gradient、shadow color 时，先用这些 helper。不要重复写 hex/rgb parser。

组件颜色必须来自当前 `Theme` / `DualTheme` 流程。新增 UI 或 visualizer 颜色时，不要把只适合单一明暗背景的固定 hex / rgba 当成主色长期写死；应从 `theme.backgroundColor`、`theme.primaryColor`、`theme.accentColor`、`theme.secondaryColor` 或由 `buildBuiltinDualTheme` / `useThemeController` 选出的当前明暗主题动态派生，并确保 light / dark 两套颜色都有可读对比。临时 alpha、shadow 和 gradient 也应基于主题色再用 `colorWithAlpha` / `mixColors` 生成。

### Icons

项目使用 `lucide-react`。按钮、tab、控制项、状态动作优先从 lucide 导入图标。

不要手写 SVG，除非现有 icon 库没有合适图标或需要项目专属图形。

### Animation

项目使用 `framer-motion`：

- 普通 enter/exit：`motion`、`AnimatePresence`
- 播放进度和时间值：`MotionValue`、`useMotionValueEvent`
- 派生动画值：`useTransform`、`useSpring`

新增动画先看相邻组件模式。涉及高频运行时，再结合 `frontend-runtime-guardrails`。

### i18n

UI 文案使用 `react-i18next`：

```ts
const { t } = useTranslation();
```

任何新增到 UI 上的用户可见文本都必须准备 i18n key，并同步写入 `src/i18n/locales/en.ts` 和 `src/i18n/locales/zh-CN.ts`。不要把按钮、标题、提示、空态、设置项、tooltip、toast 或模式文案只写成硬编码字符串；短 fallback 只能作为现有 registry / 兼容模式的兜底，不能替代字典项。

### Long Lists

项目已使用 `react-window` 的 `List` 和 `useListRef`。

需要渲染队列、字体列表、大量歌曲列表时，先查现有 `react-window` 用法。不要用普通 `.map()` 渲染大量可滚动项目。

## Service And Data Patterns

不要绕过现有 service：

- 网易云 API：`src/services/netease.ts`
- Navidrome / Subsonic：`src/services/navidromeService.ts`
- 本地音乐：`src/services/localMusicService.ts`
- 在线播放和歌词加载：`src/services/onlinePlayback.ts`
- 播放结构统一：`src/services/playbackAdapters.ts`
- IndexedDB：`src/services/db.ts`
- 队列预取：`src/services/prefetchService.ts`

新增数据流时，先判断是 service、hook、util 还是 component：

- 请求、缓存、接口适配放 service。
- React 生命周期和用户动作编排放 hook 或 app-level builder。
- 纯计算、映射、格式化放 util。
- 展示和交互结构放 component。

## Extension Rule

如果找到已有 helper 但不完全够用：

- 优先扩展已有 helper 的参数或返回值。
- 保持现有调用兼容。
- 给扩展后的 helper 补单测。
- 避免创建同领域的第二套 `formatXxx`、`parseXxx`、`measureXxx`、`mixXxx`。

只有在职责确实不同、现有 helper 会变得混乱时，才新建工具。

## Review Checklist

审查代码时检查：

- 是否手写了已由 `@chenglou/pretext`、`fontStacks`、`colorMix`、lyrics utils 覆盖的逻辑？
- 是否复制了 visualizer runtime 的当前行/下一行扫描？
- 是否直接使用 `line.endTime`，但应该使用 `getLineRenderEndTime`？
- 是否手写 SVG，而 lucide 已有图标？
- 是否新建了 service 请求逻辑，但已有 service 已经封装同类 API？
- 是否对大量列表使用普通 `.map()` 而不是虚拟列表？
- 是否新增硬编码文案却没有更新 i18n 字典？
- 是否新增固定颜色却没有从 `Theme` / `DualTheme` 动态派生并检查明暗两套表现？
- 是否创建了相似 helper，却没有搜索已有实现或测试？

## Validation

- 纯工具、歌词、颜色、字体：优先补或跑相关 Vitest 单测。
- visualizer UI：按 `testing-strategy` 判断是否需要 UI 截图测试。
- service 改动：优先看现有 service 单测或相邻 mock 模式；不要直接打真实外部服务。
