Folia 技术科普
开源项目 · Folia · 2025-11 → 2026-11 · 完整克隆 3,125 次提交

一个「歌词播放器」
写出了 74 万行代码

2026 年 10 月这一个月,这个仓库提交了 1,186 次;一年累计 3,125 次提交、59 位作者、177 个版本标签。 它对外只叫「音乐播放器」,但代码的大头不在播放:把歌词做成 17 种图形引擎级的动画、把拍点检测和人声分离做成端侧神经网络、把壁纸模式写进三个操作系统的窗口系统。 本页把它拆成产品、技术、生态、方法四层,每个结论都标出处与口径,并区分「已定案」「待核」「已推翻」。

提交
3,125 次(一年)
代码
约 74 万行(含注释)
歌词动画
17 种 + 6 背景
阅读
约 18 分钟
01 / 导览

先把「厉害」拆成四层,否则只能记住一堆数字

这一节不铺细节,只给一张地图:同一个项目,功能表解释不了它为什么重、为什么稳,四层拆开才解释得了。

第 1 层

产品层:它到底能干什么

9 种音源(7 个在线平台 + Navidrome + 本地库)、17 种全屏歌词动画、桌面三平台 + Web + PWA、三条发布通道。这些是用户看得见的部分,也是最容易被误当成「全部」的部分。

量级:一次正式发版产出 11 个平台安装包。
第 2 层

技术层:三个引擎拼在一起

视觉引擎(17 个插件、11.4 万行)、音频引擎(Web Audio 双 deck + mpv HiFi + 两个神经网络)、桌面外壳(Electron 主进程 8 千行 + 三套系统级壁纸实现)。

量级:视觉系统单目录 634 个文件、114,268 行。
第 3 层

生态层:别人可以接进来

Folium 模组平台(11 种注册表)、Stage API(12 个 HTTP 接口 + 1 个 WebSocket)、OBS 浏览器源、歌词 HTTP 接口、跨设备同步服务、四种服务端部署形态。

量级:模组系统 116 个文件、约 2.16 万行。
第 4 层 / 一句话判据

前三层任何一层单拎出来,都够一个团队做半年;真正让它少见的是第四层:为「代码规模 × AI 参与」造出的工程体系——生成物取代手维护清单、测试盯住契约、代码地图变成可查询工具。所以本页的读法不是「数功能」,而是「看每层做到了什么程度」。

这份文档怎么读:想弄懂「为什么这么重」,读 02–04(来历、视觉、音频);想弄懂「为什么这么广」,读 05–07(音源、桌面、模组);想知道「为什么这么多代码还没散架」,直接读 08;只想避坑和入门,跳到 09–11;每个数字的出处与口径在 12。
一个必须先说明的量级问题:本页基于一次完整克隆(4,494 个受控文件、3,125 次提交)与四条主线的抽样精读:视觉渲染、音源与音频内核、桌面与发布、AI·模组·工具链。四条线之外的约 1,400 个文件只做了结构与测试层面的扫描,没有逐文件读。行数统计含注释与样式文件,只用于量级比较,不等于「有效代码行」。所有数据快照截止 2026-11-01。
02 / 来历

答案不在功能表里:它用一年时间把每件事都做到底

先看时间线。提交节奏和版本密度能解释一部分「重」:不是一次性堆出 74 万行,而是持续一年、每月上千次地改。

2025-11首提交

仓库从「init」开始

2025 年 11 月 28 日出现第一个提交。这是版本历史的起点,不等于创意的起点:首提交之后大量功能是逐步长出来的。

来源:本地 git log 最早提交(clone 快照)

2026-07密集期

单月提交 462 次,三条主线成型

视觉、本地资料库、桌面端三条线在这一时期同时高速推进。代码量不是一次设计出来的,而是被真实需求一轮轮压出来的。

来源:git log 按月统计(本地克隆)

2026-10峰值月

单月 1,186 次提交,峰值单日 75 次

这是 v0.7.25 发布的月份。一个月 1,186 次提交意味着平均每天约 38 次;这个节奏下,没有自动化与测试体系是撑不住的。

来源:git log --format=%ad 统计(本地克隆)

2026-10-30版本

v0.7.25 发布:mac / Windows / Linux 全平台

正式版提供 Windows 安装包、macOS 双架构 dmg/zip、Linux 的 tar.gz / deb / rpm;另有 Nightly 与 Canary 两条预览通道。

来源:GitHub Releases(v0.7.25 资产清单)

2026-11-01快照

研究快照:59 位作者、177 个 tag、3,125 次提交

HEAD 是 PR #984 之后的合并提交。177 个 tag 说明发版频率极高:平均每两天就有一个版本标记。

来源:本地 git shortlog / git tag 统计

一个常见的误读

看到这种完成度,很多人第一反应是「一个人写的吧」。数据不支持这个说法:主作者提交 2,286 次,约占 73%;另有多位长期贡献者(动画、平台接入、工具链),作者名单里还能看到 all-contributors 与 GitHub Actions 这类机器人,以及显式署名的 AI 提交。

它不是单人神话,而是「一个主作者 + 自动化 + AI 助手」的现代协作样本。这也是为什么它的工程体系值得看:规模已经不是靠个人记忆能兜住的了。

读法

高频发版不是勤奋的证明,是工程体系能承受高频的证明:三条发布通道、草稿 Release、自动更新元数据、按平台产物的自检——这些基础设施让「一个月 1,186 次提交」没有变成「一个月 1,186 个事故」。

03 / 视觉

17 种歌词动画不是 17 套 if-else,而是 17 个热插拔插件

这一节纠正「动画多等于堆人力」的直觉:规模来自注册表加共享契约,中心代码里没有 17 条分支。它也是全仓最大的单目录。

歌词 → 屏幕:一条共享管线pipeline
// 1. 解析:7 种格式统一成 Line[](行、词、翻译、罗马音)LyricParserFactory.parse(source) → ensureLyricDataRenderHints()// 2. 每帧只算一个数:当前行索引,且读的是渲染提示里的结束时间findLatestActiveLineIndex(lines, t) → currentLineIndex// 3. 组装 40 多个共享 props,交给注册表找到的样式插件useVisualizerRendererModel() → VisualizerRenderer// 4. 懒加载 + useDeferredValue:新样式的代码到位后,才把旧样式换下registry[mode].render(props) → 17 个 entry.tsx 之一// 5. 样式内再派生:字素级时间轴、中文语义分词、布局单位buildLineGraphemeTimeline() · segmentLyricWords()

为什么这套管线重要:它把「渲染一个样式」所需知道的一切都收进契约里(definition.ts 的共享 props 加 tuning.ts 的声明式设置)。加一种新动画只需新建一个目录、写一个 entry.tsx 和一个 tuning.ts,注册表用构建期 glob 自动发现,不需要碰任何中心代码——这是它能容纳 17 种风格的前提。

样式(中文名)渲染基质它难在哪
静止
still
DOM/CSS唯一不挂背景的样式,只做文字排版,是最小样板(129 行)。
流光
classic
DOM/CSS逐词动画 + 共享 GlowWord 组件;Canvas 只用来量字宽。
心象
cadenza
Canvas2D先用文本测量预排,再整屏 Canvas 逐帧绘制。
云阶
partita
DOM/CSS先把歌词编译成分块/分栏排版,再逐词入场。
浮名
fume
Canvas2D把整首歌排成一篇文章,相机在其中穿行;布局分片计算、快照缓存。
莫奈
monet
DOM/CSS + Worker歌词栏加逐字扫光;背景图放进 OffscreenCanvas worker 里调色编码。
群唱
cappella
DOM/CSS群聊式消息行/气泡与逐字显现,头像、表情是用户可替换资源。
倾诉
tilt
DOM/CSS用文本测量库断行,逐字素做运动,按 1–4 行分栏。
回环
claddagh
DOM/CSS环形 SVG 行 + 时间线,绕环排字本身就要自己算坐标。
镜台
diorama
three.js / R3F走廊式 3D 文字:弃用 SDF、用 Canvas 双遍光栅化保证笔画与辉光对齐;点云自发光 shader。
时计
pendolo
DOM + WebGL2/Canvas2D歌词是 DOM,机芯优先 WebGL2、退回 Canvas2D。
商籁
sonnet
PixiJS段落→镜头编译,60 个文件的分镜/排版/后处理族。
凝彩
tempera
PixiJS121 种镜头类型、拼贴排版、difference 滤镜反色。
绘光
lumiere
PixiJS编译整首的「段落-镜头-光位」,体积光、线稿、浮尘。
雾笺
nebbia
原生 WebGL2雨夜车窗写字:6 个 program 后台编译、楼群环形缓存、笔顺数据。
花火
hanabi
PixiJS烟花 MG + 拼贴 + 全屏 bloom,世界持续上升。
町景
machi
three.js(原生)程序化街角微缩模型、手写散景景深、8 级画质自动降级。
町景machi
14,762
花火hanabi
13,641
凝彩tempera
12,566
商籁sonnet
11,697
绘光lumiere
11,332
静止still
129

口径:各样式目录内 ts/tsx/css 行数(wc -l,含注释与样式),仅作量级比较;「静止」是最小样板,用来对照一个样式最少需要多少代码。

让它像「引擎」的其实是一组约束:首帧前把所有 shader 并行预编译好,避免开场卡顿;Pixi 纹理按 2 的幂分桶,1.5 倍分辨率会浪费 71% 显存,桶对齐后显存降到约四分之一;换样式时旧场景不整批销毁,而是一帧退役一个;全站统一帧率闸门(60/90/120/关闭);WebGL 上下文有预算(Chromium 每页约 16 个,播放页峰值 14,所以小图预览串行生成)。
一句话

真正难的不是「画出 17 种效果」,而是让 17 种效果共用一套时间语义、设置系统与性能预算,还能在播放页、选择器缩略图、OBS 源、模组导出页四个宿主里复用。

04 / 音频

播放路径上不只有解码器:还有两个神经网络和一个乐理引擎

这一节纠正「音乐播放器就是 HTML5 audio 加个进度条」的直觉。它的播放链路里同时有实时音频图、端侧模型推理和一套按乐理做决定的自动混音。

Web 引擎的信号链(两曲之和 → 一只喇叭)web audio
deck A ┐deck B ┴→ mix → EQ → effects → volume → fade → analyser → out// 三个非显然的决定:// 1. 两个 deck 先汇合,再经同一份 EQ / 分析器 —— 过渡时音色不跳// 2. 音量推子在效果器之后 —— 黑胶噪声/bitcrush 是绝对效果,不在推子前// 3. fade 是独立节点 —— setValueCurveAtTime 独占参数,别人再写会抛错
模型体积在播放器里干什么被谁消费
Beat This!
beat_this
41.1 MB拍点与强拍检测(ISMIR 2024 论文模型)自动混音选接点、智能动感特效、部分歌词样式的节拍驱动
htdemucs
htdemucs
91.8 MB四轨分离:人声 / 鼓 / 贝斯 / 其他自动混音的 stem 交接、鼓面特效、雾笺样式的人声包络

两个模型共 133 MB,随安装包分发,不联网下载;MIT 许可,权重文件的字节数与 sha256 钉死在清单里。清单注释里有一句很说明问题的话:「下载成功」和「能用」是两件事——四次发布方的权重完整,却加载不了。所以校验不只是防断网,是防「安静地算错拍」。

更硬的一点:一份权重,两套运行时。渲染进程里跑 WebGPU 的 WGSL 计算着色器;桌面版 CPU 路径用 C++ 的 MNN 推理,带 AVX2 手写卷积核。为什么不能偷懒只留一套:桌面版的原生推理必须搬进 utilityProcess——因为某个推理库的「异步」其实是同步实现,一首歌的模型窗口能让主进程冻结 30–45 秒;搬出去之后,主进程最长停顿从 1,450 毫秒降到 25 毫秒。
接法什么时候用动作
beatCut进场曲一开始就满电平,或速度差超过阈值出场曲直接被切,切口约 40 毫秒
bassSwap两曲可重叠时的默认选择长重叠,但低频同一时刻只属于一方
tailRide出场曲有衰减尾 + 进场曲有前奏长重叠,从尾巴底下浮上来
plainBlend什么信息都不知道时的兜底等功率交叉淡化

自动混音(automix)分四层:证据层测量音频事实(BPM、小节线、响度、段落),决策层用乐理规则产出纯数据的过渡方案,执行层把它变成采样级的音频节点事件,绑定层才是 React 与两个 audio 元素。除绑定层外整个目录不依赖 React 或 DOM,所以单元测试不需要声卡。

桌面版还有第二套引擎:HiFi。本地曲库与 Navidrome 的歌可以交给 mpv 子进程,按源文件格式直接送到输出设备,并逐级报告信号链(bit-perfect、DoP、采样率直通或被转换)。代价是均衡器、音效、淡入淡出、自动混音、频谱全部不可用——它把「要音质」和「要效果」做成了两条明确互斥的路线。
网页版的边界要说清:浏览器里没有桌面端的原生推理与 stem 分离能力,自动混音会退回到交叉淡化兜底;节拍检测也退回简单的速度估计(仓库自述约 30 首里只有 20% 左右可用)。同一份代码,不同宿主能力不同,产品选择是显式降级而不是假装完整。
反直觉

一个「播放器」最难的音频部分,不是解码,而是在播放的同时做分析,还不让分析吃掉音频线程:模型、进程、线程数、缓存、调度策略全是围绕这一条重建的。

05 / 音源

九种音源,一个门面:平台差异被压进数据表

这一节纠正「每接一个平台就多一段 if-else」的想象。九个来源背后是同一层门面,差异被收进能力开关、失败分类和平台自己的目录里。

为什么必须有这一层

九个来源的接口、鉴权、音质档位、歌词格式、错误文案全不同;如果让界面直接碰平台,任何一次平台改动都会穿透到 UI。Omni 把「能做什么」变成 19 个能力开关,把「失败了算什么」变成 18 种有名字的情况。

它还有一条架构测试钉着:其它层直接 import 具体平台 provider 或 transport 会失败。规则不靠自觉,靠测试。

注册表是运行时可变的数据

网易云、酷狗、QQ、波点、YouTube Music、Spotify、汽水音乐,加上作为独立 Subsonic 服务的 Navidrome 与本地音乐库——每个来源登记自己的 id 与能力。模组甚至可以在运行时注册或注销 provider,界面会自动失效对应的入口。

一个平台的规则只留在自己的目录

「看着像就合并成通用规则」是这类项目最常见的坏味道。这里的规矩相反:平台的怪癖写在该平台目录里,并有一个测试统计平台名在目录外出现的次数,防止泄漏。

同一平台,桌面与网页两条路

桌面版:网易云在主进程 worker 里起一个只听 127.0.0.1 的 Node 服务;酷狗直接进程内调用;QQ 的包自己起 HTTP 服务;波点、YouTube Music、Spotify、汽水通过 IPC 桥,凭据不出主进程。网页版:网易云/酷狗/QQ 必须指向外部已部署的 API;桌面专属平台直接显示「不可用」,不假装可用。

来源逐字歌词探索页云盘听歌上报备注
网易云有有有有唯一支持播报听歌记录的平台
酷狗有无有无桌面版进程内调用,网页版需自部署 API
QQ 音乐有有有无登录态由服务端加密,扫码有三种形态
波点音乐有无无无仅桌面端;收藏写入尚未实现
YouTube Music无有无无仅桌面端;有隐藏沙箱窗承载第三方登录
Spotify无有无无仅桌面端;歌词只取行级
汽水音乐有有无无仅桌面端;车机协议,没有专辑能力
Navidrome取决于文件无无无独立 Subsonic 服务,不走 Omni
本地音乐库取决于文件无无无本地索引,不上传文件内容

口径:能力开关以仓库 ProviderCapabilities 与各平台 provider 的声明为准(快照 2026-11-01);「逐字歌词」指平台能否提供词级时间,本地/Navidrome 取决于歌词文件本身。

失败被当成一等公民:播放失败被分成 18 种有名字的情况,每种决定「要不要停」「能不能重试」「自动跳过时跳不跳」;平台说「稍后再试」并给了时长,到点前不再请求它的地址;播放失败永远不会回写歌曲可用性、预取或缓存——把「这一次坏了」和「这首歌坏了」分开,是流媒体客户端最容易做错的事。
凭据只认系统加密:登录态用操作系统提供的加密能力(DPAPI / Keychain / libsecret)整包加密,只存在主进程;Linux 上如果只拿到「伪加密」后端,程序会直接拒绝落盘——宁可不记住登录,也不写近似明文。诊断报告里凭据、IP、账号会先洗掉再进日志。
判断

「支持九个平台」不是九个开发量,而是九套失败语义、九套登录态、九套音质档位的统一建模。这一层的价值不在功能表,在把不确定性关进笼子。

06 / 桌面

把播放器沉进桌面:三个系统,三套完全不同的实现

这一节纠正「Electron 就是套个壳」。它的桌面部分有系统级窗口黑魔法、独立音频引擎、170 个渲染进程接口,以及三条互不干扰的发布流水线。

系统实现机制只有做过才知道的坑
Linux
Wayland / X11
外部程序把窗口重新包装成「桌面层表面」,启动方式是把整个进程重新包一层再自重启上游把每个顶层窗口都变成全屏壁纸层,遥控窗和右键菜单会一起沉底;还有一个补丁专门修「不支持的系统请求被当致命错误」,否则右键一弹就断开连接。补丁共 484 行。
Windows
WorkerW
一个 1,828 行的 Rust 常驻进程,把窗口挂进桌面图标层下面,并转发鼠标事件必须在挂载前先取窗口所在显示器,否则壁纸会被永久钉到另一块屏;鼠标不能直接投递消息(系统会立刻判定离开),只能由主进程注入输入事件。
macOS
Cocoa / CGEventTap
用 FFI 把活着的窗口沉到 Finder 桌面层之下,另建只旁听的鼠标事件监听,再加一层透明面板处理台前调度辅助功能权限按「进程身份」判定,派生的子进程不被信任,所以吞掉桌面点击必须留在主进程里(一个 289 行的 Swift 组件);桌面上真的点得到控件,但不能点到桌面本身。
通信面有多大、边界在哪:渲染进程到主进程的桥只暴露一个命名空间,共 170 个 API、217 个绑定;主进程注册 136 条通道,一一显式映射——没有裸的 IPC 对象,也没有「传任意通道名」的通用逃生口。所有窗口都开启渲染器隔离、关闭 Node 集成;外部链接只允许 http/https。代价是接口面很大,好处是它可以被审计。
音频另有一条桌面专属路线(详见 04 的 HiFi):本地库和多设备音乐服务器交给 mpv 子进程,逐级报告从源文件到声卡的每一层——桌面版因此同时存在「效果优先的 Web 引擎」和「音质优先的直通引擎」两套播放路线,按歌曲来源自动选择,失败按单曲回退。
发布通道面向更新方式
稳定版
latest
普通用户正式发版;版本号、提交信息、发布标记三处必须一致才允许打包
Nightly
beta
想尝鲜的用户每日定时构建;版本号用时间戳,避免并发冲突
Canary
alpha
贡献者 / 回归测试任意分支推送触发,可只出安装包不发布

每次正式发版约 11 个平台产物。一个容易被忽略的细节:只有 Windows 是真「应用内自动更新」;macOS 与 Linux 只是定期拉取版本元数据,发现新版本后打开下载页——因为 macOS 包没有开发者签名和公证,系统需要用户手动移除隔离属性(官方文档专门写了这一节)。

诚实降级

Wayland 下「窗口置顶」这个 API 会返回成功但什么都不做(合成器根本收不到请求)。它的处理不是假装可用,而是把置顶开关全部置灰,文档里教用户改用窗口管理器的规则,或显式切到 X11 兼容层并说明代价。工程品味常常体现在「承认做不到」。

07 / 模组

模组不是沙箱,而是一套「内容绑定 + 主进程确认」的信任模型

这一节纠正「给了权限就等于隔离」。官方文档的原话是:模组是可信代码,不是沙箱。那它靠什么保证安全?靠确认、绑定和自救。

机制具体做法
11 种注册表歌词动画、调参、命令、背景、播放页图层、设置分区、播放面板页签、首页页签、进度条按钮/图层、样式——模组往这些位置加东西,而不是改宿主代码。
12 个权限,先拒绝后声明未知权限直接拒绝安装;写权限必须同时声明读权限;未声明就调用会立刻报 permission-denied,不会静默失败。
主进程原生确认窗启用确认必须画在主进程的原生窗口里——因为模组和界面共享同一个渲染进程,渲染进程里的弹窗可能被模组伪造或自动点击。
授权绑定内容摘要用户确认的结果与目录内容的 sha256 一起保存;模组文件只要变过一个字节,摘要就对不上,授权自动失效并要求重新确认。
崩溃自救模组启动前写一条记录,界面完整启动后才撤销。下次启动若记录还在,说明上次没走到终点,会在任何模组代码运行前弹窗问「这次要不要不带模组启动」。
Ed25519 四态签名官方认证 / 先行测试 / 未验证 / 签名无效;签名只贴标签,永远不跳过确认。签名摘要设计成跨机器逐字节一致(Unicode 规范化、按码元排序、拒绝符号链接、跳过系统垃圾文件)。
市场审核作者提 issue → CI 把版本解析成具体 commit 并只取该 commit → 维护者通读代码与依赖、核对权限是否最小 → 人工签名发布。签名绑 commit 而不是 tag,tag 被移动签名即失效。
文档原话

「签名只给模组贴标签,它从不会让模组被启用或跳过原生确认:签过名的模组仍是拥有应用完整权限的可信代码。」这句话把信任模型说透了:安全边界是用户按下的那一次确认,不是签名验证。

生态的深度也是工程化的:模组 API 的类型文件(2,711 行)与 API 文档(2,414 行)都由契约文件自动生成,改了契约不重新生成会被单测拦下;新增一个注册表种类只改一张事实表,API 构造、挂载点标记、文档生成、静态检查四处共用。仓库自带 8 个示范模组,覆盖「歌词动画」「调参」「进度条改造」「透明视频导出」等方向。
边界也要说明:「声明式权限」只决定 API 能不能调,不限制模组代码本身;Node 入口一旦启用就拥有完整的本机能力。所以官方对模组市场定了红线(例如任何导出原始音频流的模组都不上架),并把高风险权限的审查写成流程。这不是技术保证,是治理。
08 / 工程

最厉害的其实是:它为「AI 参与开发」造了一套工业体系

这一节回答「这么多代码为什么没散架」。答案不是作者更自律,而是把「人会忘、AI 会飘」的地方全部变成了机器可检查的东西。

src 前端41.7 万行
56%
test 测试23.5 万行
32%
electron 主进程4.0 万行
5%
dev 开发工具3.2 万行
4%
其余共享/服务端/原生
3%

口径:按目录统计 ts/tsx/cjs/mjs/js/rs/cpp/h 行数(wc -l,含注释),四舍五入到整数百分比,仅用于说明「测试与工具占了四成以上」。

手段它替代了什么人的工作
生成式代码地图手维护的目录清单必然过期。代码地图由编译器生成,main 分支自动重生成并提交;所有计数向下取整到 2 的幂、排序用码元序,从根上消掉「数字变一格就产生一次假提交」的噪声。
自研代码查询工具把仓库自带的 TypeScript 编译器包成 11 个查询工具:查符号、查调用链、查影响面。一个 3,080 行的文件直接读 12.5 万字节,用结构大纲只要 3,377 字节——省 37 倍。
13 个仓库内技能文档把「怎么改代码」「怎么定位」「怎么测」写成 AI 可加载的 skill,入口文件只做索引;文档里禁止写死路径(因为路径必然过期),只写查询方法。
契约测试用源码文本而不是运行行为检查三件事:存储键改名(会静默丢用户设置)、状态模块循环依赖、把逐帧动画值写进全局状态(会导致帧率级重渲染)。
1,071 个单测文件约 10,901 条用例 + 92 个浏览器端测试。测试不是「覆盖率装饰」,而是把上面这些规则变成会红的门禁。
13 条 CI 流水线PR 跑类型检查、单测、服务端构建、Docker 冒烟;专门的「arm64 打包路径检查」在 PR 上提前暴露打包回归;代码地图自动同步;issue/PR 用大模型自动分类。
为什么这套东西对「AI 原生开发」特别重要:AI 写代码的速度很快,但它不会记得「这个设置键不能改名」「这一层不能 import 那一层」。Folia 的答案是:把这些规则从人的记忆迁移到生成物、快照测试、边界规则和技能文档里——让错误在合并前变成机器输出,而不是在用户设备上变成 bug。
一句话

它不是「用了 AI 开发的项目」,而是「为 AI 参与开发建了基础设施的项目」:索引可查询、规则可执行、产物可复现、失败可定位——这四件事恰好也是人类团队最缺的。

09 / 误区

这些「大家都这么说」的说法,其实都错了

每一条都给出「流传说法 → 代码/文档怎么说 → 为什么会传错」。其中第一条是我们自己研究时差点写错的,顺手留在这里当纠偏样本。

纠偏

「浮名样式是车窗雨刷写字」

错。浮名(fume)是把整首歌词排成一篇文章,让相机在文章里穿行——代码注释写得很清楚,布局按「文章 / 块 / 相机」建模。

在雾天车窗上用手指一笔一笔写字的,是雾笺(nebbia):原生 WebGL2、水珠法线、擦痕遮罩按演唱时长一笔笔画出来。

为什么会传错:两者都叫「文字 + 雨/雾氛围」,只看截图很难分辨;最初我们的研究笔记就写反了,后来靠读 fume/VisualizerFume.tsx 与 nebbia/ 的入口注释纠正。

纠偏

「视觉层用了 WebGPU」

错。17 种歌词样式的渲染基质是 DOM/CSS、Canvas2D、PixiJS(WebGL2)、three.js(WebGL)和原生 WebGL2——没有任何一个样式用 WebGPU。

WebGPU 与 WGSL 计算着色器只出现在音频分析:拍点检测与四轨分离的推理。它们算出的节拍、鼓点、人声包络再喂给「智能动感模式」和各歌词样式。

为什么值得强调:「视觉很炫」容易被归因成「用了最新的 GPU API」;真实答案往往更朴素:把 WebGL2 用到极限,加上大量非渲染的性能工程。

纠偏

「17 种动画背后是 17 套 if-else」

错。每个样式是独立目录里的一个插件入口,由构建期 glob 自动注册;共享的是 props 契约、时间语义、设置系统与性能预算。

衡量标准写在项目规范里:加一个同类功能,要改的地方越少越好。注册表、调参声明、设置面板、导出/同步/OBS 都从同一份 declaration 自动生成。

机制:「同类的东西只动它自己的目录 + 注册点」,而不是在总入口里加分支。

纠偏

「模组权限 = 安全沙箱」

错。官方文档原话:模组是可信代码,不是沙箱;权限是给用户在确认框里看的声明,不是运行时隔离。

真正的边界是:主进程绘制的原生确认窗 + 授权绑定目录内容摘要 + 崩溃自救 + 签名四态标签。签名有效也永远不会跳过确认。

为什么这是对的取舍:真正的进程沙箱会限制模组能做的事(改歌词、加动画、调 ffmpeg 导出),对创作型生态来说代价可能比收益大;但代价是必须承认「你在安装一个人的代码」。

纠偏

「AI 功能就是调一下 API」

错——它是一层有协议适配、尝试阶梯和三层降级的推理网关:10 个供应商适配器、3 种协议;温度、推理开关、结构化输出、token 字段、预算全被压成数据表。

最典型的一处:HTTP 200 但内容为空、推理 token 耗尽,被显式建模成「可降级的失败」;否则用户看到的现象是「AI 不说话」,日志里什么都没有。

数字:AI 相关核心文件约 40 个、适配器 10 个;主题生成、歌词分词、测试连接共用同一套规则。

纠偏

「所有平台都支持应用内自动更新」

错。只有 Windows 走真正的自动更新;macOS 与 Linux 只检查版本、然后打开 Release 页面。

原因写在发布代码里:macOS 包没有开发者签名与公证,必须用户手动移除下载隔离属性;Linux 不发布自动更新元数据。这是能力边界,不是 bug。

推论:看到「自动更新」字样时,先问「哪个平台、走什么协议」,再决定要不要相信。

纠偏

「这种完成度,肯定是一个人写的」

不准确。主作者提交 2,286 次(约 73%),但仓库有 59 位作者、177 个版本标签;还有自动化机器人,以及显式署名的 AI 提交。

更准确的描述是:一个主作者主导 + 自动化 + AI 助手 + 社区贡献。理解这一点,才能解释它为什么能在一年里把这么多条线同时推进。

数据来源:本地 git shortlog -sn 与 git rev-list --count 统计,快照 2026-11-01。

误区的共同结构:把它们放在一起看,七条里有五条都是「把工程结果误认成某项单一技术」。这也是本页存在的意义:看见结果很容易,看见结果背后那一整套约束很难。
10 / 存疑

哪些还没定案:证据到哪一步,就说到哪一步

这一节把「已定案」「待核」「作者自述未实测」分开。科普页最容易犯的错,是把「看起来对」写成「已证实」。

待核

全仓找不到内容安全策略(CSP)

安全代码注释把 CSP 列为既有防线,但全仓检索不到任何 CSP 声明(页面 head 里没有,主进程也没有注入响应头)。可能是构建产物或部署层补上,也可能文档与实现漂移。

证据强度:代码检索事实明确;「是否在别处补上」未验证。结论只能写到「存在缺口或文档漂移」,不能写成「没有安全防护」。

已定案

歌词注音(ruby)只解析、未渲染

TTML 歌词里的逐字注音数据被完整解析并保存在歌词行里,但目前没有任何歌词样式消费它——只有歌词重定时逻辑用到。

证据强度:代码检索所有 visualizer 目录,无 ruby 消费点。这是「当前实现局限」,不是 bug 也不是错误声明。

待核

模组签名吊销机制没有被真实事件检验过

代码里有吊销名单机制,但名单目前是空的;签名密钥内置、不联网,意味着「吊销密钥或模组」必须发新版宿主。

证据强度:机制存在、注释清楚;是否可靠未经实战。属于设计取舍,不是缺陷,但应急成本高。

待核

主题生成的两条路由已开始漂移

Gemini 路由与 OpenAI 兼容路由各自维护一份 prompt 与 JSON Schema(约 189 行 vs 408 行),必填字段已出现细微差异。

证据强度:两份文件逐行对照可见差异;这是全仓唯一明显的重复代码,值得抽公共常量,但当前未见故障报告。

存疑

「AI 广泛协助开发」的质量影响无法量化

README 法律段自述项目「在 AI 的广泛协助下开发,仍可能存在细微或不易察觉的问题」。这是作者主动披露,不是缺陷证据。

证据强度:只能引用作者原话;本页不据此推断质量好坏,只提醒读者:关键路径(凭据、播放、平台接口)要自己验证。

存疑

部分能力只有作者声明、没有公开实测

例如某些平台的高音质档位、部分平台在 Windows/Linux 上的行为、Linux 音频服务下「采样率直通」的判定——仓库自己标注了「未实测」或在文档里只读代码未跑真机。

证据强度:「未实测」是项目自己写的,可信;本页不把这些写成已确认能力。

存疑

模型权重本身没有被核对

权重文件不进 git,随安装包分发;本次研究只能核对清单里的字节数与 sha256,无法核对文件本体(需要先运行下载脚本)。

证据强度:清单与校验逻辑已读;文件本体未验证。研究笔记里所有关于模型的数字都来自清单与代码,不是实测推理结果。

统计口径与已知偏差:① 行数用 wc -l 统计,含注释与样式,不能当「有效代码」;② 四条主线之外的文件只做结构与测试扫描,未逐文件精读;③ 所有数字是 2026-11-01 的 main 分支快照,之后会变;④ 平台能力矩阵来自仓库声明,未对每个平台做真机点播验证;⑤ 本页把「我们研究时写错的点」保留在 09 节,作为纠偏样本,而不是删掉装没发生。
11 / 入门

想研究它,别从那 7,997 行的主进程文件开始

这一节给三条按口味分的路线和五个步骤。真实需求不是「读完全部」,而是「第一次打开就知道从哪进、多久能出结果」。

路线 A

视觉与前端

先读视觉目录的代码地图,再读共享契约与渲染入口,然后挑一个中等复杂度的样式精读,最后看性能约束清单。

顺序:视觉 README → definition.ts → VisualizerRenderer → 歌词时间提示 → 一个样式目录
避坑:别从「町景」这种 1.4 万行的样式开始,先从「回环」或「静止」建立骨架认知。
路线 B

音频与端侧 ML

先看播放图与自动混音说明,再读分析服务的目录说明,然后对照模型清单看两套运行时怎么接。

顺序:播放图 → 自动混音 README → 分析服务 README → 模型清单 → 桌面原生推理桥
避坑:权重共 133 MB 且不进仓库;先跑模型下载脚本再谈「怎么推理」。
路线 C

桌面与平台工程

从窗口创建函数与壁纸设计文档入手,再读 IPC 边界与模组信任模型,最后看发布工作流。

顺序:壁纸模式文档 → 主进程窗口函数 → IPC 守卫 → 模组系统 → 发布工作流
避坑:直接读主进程 7,997 行会迷路;先读那份 200 行的壁纸设计文档。
  1. 先跑起来,再读代码

    装依赖(约 1.4 GB)→ 配置环境变量 → 启动 Web 版。桌面版用另一条命令。只有跑起来,才知道读到的代码对应哪块界面。

  2. 用 30 分钟建立地图

    读项目规范索引、代码地图、技术说明三份文档。它们会告诉你区域分布、枢纽模块和动态注册点——比从入口文件硬啃快一个数量级。

  3. 按主线精读,而不是按目录顺序读

    三条路线任选一条,每条约 10 个关键文件、2–4 小时。遇到符号问题用代码查询工具,不要用正则猜。

  4. 做一个小实验

    加一个极简歌词样式、写一个最小模组、或跑一次自动混音决策。动手过的模块,读第二遍时结构会自己浮出来。

  5. 跑检查,理解「为什么不能乱改」

    类型检查、单元测试、代码地图生成。看一眼契约测试在用源码文本防什么——这比读十条规范更有说服力。

四条入坑提醒:① 依赖树很大,首次安装留足磁盘与时间;② 桌面版的 macOS 包没有签名和公证,运行前要移除下载隔离属性(官方文档有专门一节);③ 许可证是 AGPL-3.0,衍生产品(含网络服务)需开源,商用前请找法务;④ 音乐内容版权归各平台,项目明确只供个人学习与非营利测试。
建议的顺序

先当用户用一周(知道功能在讲什么),再按主线读两周(知道它怎么做到),最后改一个小地方(知道代价在哪)。直接读代码是最慢的入门方式。

12 / 附录

来源与核对说明

每条结论对应出处;代码引用给仓库路径(可在本地克隆里直接打开),外部来源给链接。统计类数字的生成方式写在最后。

核对说明与已知偏差:
① 所有「行数 / 文件数 / 提交数」均来自 2026-11-01 的本地完整克隆,用 git 与 find/wc 生成;行数含注释与样式,只用于量级比较。
② 研究过程中修正过的错误:最初把「浮名(fume)」写成车窗写字样式,读入口注释与目录后确认应为「雾笺(nebbia)」,已在 09 节保留纠偏记录。
③ 标为「待核 / 存疑」的条目,表示代码/文档能确认现象、但无法确认影响或可靠性;请勿当作已定案引用。
④ 平台能力矩阵来自仓库内能力声明,不是逐平台真机点播验证;模型相关的数字来自清单与代码,不是实测推理结果。
⑤ 本页是资料整理与科普,不是项目官方文档;项目功能与版本以官方仓库为准。