从本地原型到在线小游戏合集:前端架构、体验优化与 Cloudflare Pages 发布
一个小游戏如何逐渐变成合集
“洛一把”最初只有一个功能:随机选择一首洛天依传说曲,让玩家根据线索不断猜测。随着曲库扩展和玩法增加,主页逐渐变成了一个中文虚拟歌声主题的小游戏合集。
目前项目包含曲目猜猜看、闪耀的 Producer、歌曲大排序、谁是老资历/小资历、曲名填字和歌曲数据库等模块,也为多人猜曲保留了测试入口。
这种变化带来的问题并不只是“多写几个页面”。路由、共享数据、音乐播放、移动端布局、构建脚本和部署规则都必须能够支持不断增加的模块。
React + Vite 的单页应用结构
网站使用 React 和 Vite 构建。主页只是整个应用的入口,主要页面使用固定路由区分,例如:
/modes:曲目猜猜看的曲库范围;/play/...:曲目猜猜看;/crossword:曲名填字;/sorting:歌曲大排序;/seniority:老资历/小资历;/producer:闪耀的 Producer;/database:数据库选择与浏览。
全局播放器挂载在应用最外层,因此页面切换只改变路由内容,不会卸载音频组件。刷新页面会重新开始当前游戏,但普通的站内导航不会打断音乐。
页面不直接读取原始资料
项目的数据来源经历过 Markdown、Excel 和 JSON 的多次扩展。如果每个页面分别解析这些文件,字段规则很快就会失控。
当前做法是在开发、测试和生产构建前执行数据生成脚本:
人工审核 Excel / 歌曲 Markdown / P 主 Excel ↓ 数据生成与校验 ↓ 前端可直接读取的 generated JSON ↓ 各玩法服务与页面生成阶段负责字段命名、成员拆分、URL 规范化、跨歌姬作品去重、预设构建和错误检查。页面只面对稳定的数据结构。
这种方式还有一个很实际的好处:如果数据缺字段、月份格式错误、作品重复或预设引用了不存在的曲名,构建会直接失败并指出记录,而不是等到玩家打开某一题时才出现空白。
游戏服务层与 UI 分离
每个玩法都有独立的状态与规则,但 React 组件不直接承担选题和判定。例如曲目猜猜看服务负责随机答案、提交反馈和提示状态;老资历服务负责时间候选、生命值和承接歌曲;排序服务负责得分和年份分配。
页面组件主要完成三件事:
- 展示服务返回的状态;
- 把玩家操作传给服务;
- 根据屏幕宽度选择表格、卡片或抽屉布局。
这使随机逻辑可以在测试中替换为固定随机源,规则也可以脱离浏览器界面单独验证。
数据库从附属页面成长为独立模块
随着收录歌姬和歌曲增加,数据库不再只是开发时检查资料的工具,而成为网站中的一个正式入口。
数据库选择页包含“全曲库”、各歌姬曲库和 P 主数据库。全曲库按照规范化 VCPedia 页面 URL 合并共享作品,歌姬页面则保留各自的收录关系,因此一首合唱曲可以出现在多个歌姬页面中,但在全站玩法题库中只保留一份。
歌曲表格支持关键词搜索、歌姬、声库、特殊标注、年份范围、表头排序和详情抽屉。桌面端保持类似电子表格的横向浏览体验,移动端允许横向滚动,并把右侧抽屉切换为底部详情面板。
这一模块还验证了一件事:经过人工审核的数据不应该只服务于猜题,也可以直接成为方便浏览和查错的资料产品。
全局 BGM 播放器
网站早期只有一首《一花依世界》伴奏。随后曲目增加,播放器被重构为独立播放列表。
当前播放器会:
- 首次进入网站时随机选择一首;
- 播放结束后按照列表顺序自动切换;
- 提供播放/暂停、下一首和音量控制;
- 允许玩家主动选择要播放的曲目;
- 在路由切换时保持播放状态;
- 记忆音量设置;
- 在浏览器阻止自动播放时,等待首次用户交互后恢复。
音频配置与播放器组件分离,文件名称会转换成用户可读的歌曲标题。新增 BGM 时不需要改动游戏页面。
浏览器的自动播放策略是实现中绕不开的限制。所谓“默认播放”只能主动尝试,不能保证在所有设备上无条件成功。因此界面必须明确显示当前状态,并为首次点击后的恢复播放做好准备。
用应援色建立模块识别
首页不同玩法使用不同歌姬应援色,让功能卡片在保持同一结构的同时具备辨识度。卡片右上角使用统一编号,数据库则作为资料入口不显示玩法编号。
颜色从来不是唯一反馈手段。猜测结果、排序状态、输入错误和固定格子还会配合边框、文字、图标或标签,避免绿色和黄色成为玩家理解页面的唯一依据。
开发过程中也处理了许多看似细小、实际很影响体验的问题:
- 搜索联想框被表格覆盖,需要提升层级并调整定位;
- 长曲名在手机卡片中换行后与 STAFF 重叠;
- 两张比较卡片在移动端留下过多空白,或超出首屏;
- 结算说明在窄弹窗中出现“第二行只剩两个字”;
- 新题替换旧题时缺少视觉反馈,需要加入过渡动画;
- 标签内容过长时必须允许合理换行,而不能撑破表格。
这些调整很难在最初设计图中一次完成,通常都来自真实游玩后的观察。
开发者工具只在本地出现
随机题目不利于测试指定歌曲。因此多个玩法在开发环境提供了指定下一题或查看谜底的工具,但入口使用 import.meta.env.DEV 控制,生产构建中不会显示。
这是一种简单但非常有效的测试辅助:它既能快速复现特定长标题、多歌姬、多声库或特殊 STAFF 的边界情况,又不会把作弊入口带到线上版本。
自动测试与构建检查
项目的验证不只依赖手动打开页面。测试大致分为三层:
- 数据测试:检查字段、数量、URL、重复作品、歌姬归属和预设;
- 服务层测试:检查随机选题、反馈规则、提示顺序、计分、生命值与投降状态;
- React 交互测试:检查输入、按钮、弹窗、路由和移动端可用流程。
生产构建本身也是最后一道数据校验。只要生成脚本发现非法记录,Cloudflare Pages 就不会发布一份数据不完整的版本。
Git 与持续迭代
项目使用 Git 管理版本并同步到 GitHub。更新通常包含数据、页面、测试、README 和更新日志,完成本地验证后再提交和推送。
在 Windows 环境中,自动化工具创建的仓库曾触发 Git 的 dubious ownership 检查。通过把明确的项目路径加入 safe.directory,可以告诉 Git 当前用户信任这个仓库。这个设置应当只针对具体目录,而不是关闭所有权保护。
曲库项目还有一个额外挑战:音频和审核表会明显增加仓库体积,推送时也更容易受到网络中断影响。长期来看,可以进一步评估 Git LFS、外部对象存储或发布阶段下载资源,但首版仍以一个可完整构建的仓库为目标。
从 Netlify 迁移到 Cloudflare Pages
网站最初部署在 Netlify。免费额度到期后,项目迁移到 Cloudflare Pages,目前的试玩地址是:
Cloudflare Pages 直接连接 GitHub 仓库,每次推送后自动安装依赖、生成数据并执行 Vite 生产构建,最终发布 web/dist。
旧的 netlify.toml 已经删除,但 web/public/_redirects 继续保留。原因是这是 SPA 子路由回退规则:用户直接访问 /database/all 或 /seniority 时,服务器仍需返回应用入口,再由前端路由决定显示哪个页面。
迁移并不要求购买域名。pages.dev 地址已经可以公开访问;自定义域名只是后续品牌化选择,不是网站上线的必要条件。
README、更新日志与项目说明
README 负责向第一次打开仓库的用户说明项目内容、启动方法、数据来源和在线试玩地址。更新日志则记录歌姬曲库、新玩法、BGM 和界面调整。
网站底部也保留参考项目和数据来源链接,并提供作者联系方式:
对于依赖社区资料的网站,清楚写明来源、参考项目和纠错入口,比只展示成品更重要。
目前仍然存在的边界
“洛一把”目前仍是纯前端应用,因此存在一些明确限制:
- 完整题库和答案会下载到浏览器,无法阻止开发者工具查看答案;
- Excel 和数据网站信息仍需人工审核,自动解析不能替代事实核对;
- 远程图片可能失效,所以必须保留占位图;
- BGM 会增加加载与仓库体积,需要注意版权、带宽和缓存;
- 没有账号、云存档、排行榜或真正的多人房间。
如果未来实现多人猜曲,Cloudflare Workers、Durable Objects 或其他实时后端可以负责房间状态、答案保密和 WebSocket 通信。但这应当作为独立阶段开发,而不是把服务端复杂度提前带入所有单机玩法。
回头看这段开发过程
项目真正困难的部分并不是写出第一个输入框,而是让数据、玩法和维护方式能够一起增长。
从一个洛天依传说曲猜谜,到多歌姬曲库、时间游戏、填字、P 主资料和数据库浏览,许多早期结构都被重写过。每次重构的目标不是追求抽象本身,而是解决下一个真实需求:更可靠的数据、更清楚的反馈、更方便的测试,以及更稳定的发布。
这也让我逐渐确认,一个个人项目即使从很小的点子开始,也值得建立数据校验、测试、版本记录和部署流程。它们不是大型团队的专属工具,而是让兴趣项目能够持续做下去的基础。
项目仓库:LonakoBc/luo-yi-ba
在线试玩:luo-yi-ba.pages.dev
支持与分享
如果这篇文章对你有帮助,欢迎分享给更多人或打赏支持!



