下载 App

【聚光灯21天】DAY 13–16 · H5 版四天:从六个页面到能上线

修改于10/205 浏览综合 包含 AI 合成内容
TapTap
DAY 12 封存了 Lua 版、开了 H5 的壳。这四天把整个游戏在浏览器里重建,并推到接近可上线。
四天的主线:
天做了什么
DAY 13六个页面 + 罗盘 + 双音频系统 + 四条资产管线 + 七套浏览器验收
DAY 14全量审查 → 修 5 条高危 + 15 条中危;存档语义换代(v2.2.0 轮次存档)
DAY 15存档页重做(自动档 6 条 + 暂存)、设置页改滑杆、剧本内容缩减
DAY 16TapTap 云存档对接 + 青史图鉴 + 朝代预告页 + 封面/分享卡素材
horizontal linehorizontal line

一、为什么能一天做完六个页面

因为规则早就写好了,今天只做"渲染层"。
这个项目的规则真源一直是 JS(prot/engine.js),Lua 是它的逐位移植。所以 H5 版:
ts复制
ts
// h5/vite.config.ts alias: { '@engine': resolve(repoRoot, 'prot/engine.js'), // 规则:原样复用 '@data': resolve(repoRoot, 'prot/lua-data'), // 数据:原样 import }
不拷贝、不转译。 prot/ 的测试因此继续守护同一份代码。
于是活就变成了纯粹的**“把状态渲染成 DOM”**。game/session.ts 933 行,控制流严格对齐已封存的 scripts/qingshi/ui/game.lua。

六个页面 + 罗盘

模块行数说明
ui/menu.ts263主菜单
ui/select.ts286选择页(剧本卡 + 难度 + 入局漩涡)
ui/wheel.ts299朝代罗盘
ui/settings.ts115设置页
ui/savepage.ts107存档页
ui/cast.ts77立绘列
game/session.ts933会话与流程
罗盘是最难的一块。 wheel.ts 头注写明:模型与手感参数与 Lua 完全一致 ——
  • 朝代名固定在自己的方位(第 1 项在正上方),不随盘转
  • 盘面(环带 + 烘焙在顶部的指针)旋转,由指针去指当前选中的那一格
  • 拖拽跟手 → 松手惯性 → 欠阻尼弹簧吸附(冲过再回摆)→ 整体归位
与 Lua 的差异只在渲染层:NanoVG 即时绘制换成 DOM + CSS transform,每帧只写 transform/位置,不重排布局。
这块的手感在 Lua 版调了很多轮(DAY 8 的"罗盘四版"),今天照搬结论,不重新调。
horizontal linehorizontal line

二、DAY 14:一次审查,修掉 5 高 15 中

DAY 13 搭得快,DAY 14 就做了全量审查(三路并行深审 + 主审查人逐条核实)。
基线:tsc --noEmit 通过、8/8 套浏览器测试全绿、数据门禁通过。

报告里最有价值的一句话

最值得警惕的模式是「注释里正确诊断了问题,代码却没跟上自己的诊断」。
两个实例:
  • 懒加载被自检抵消 —— scenarios.ts 精心做了按需加载,但 main.ts 的启动自检串行拉全部五份 JSON(280KB),首屏被迫下载全部数据。注释还自承"这是刻意取舍"。
  • 版本号第三副本 —— vite.config.ts 注入 __APP_VERSION__ 并专门注释警告"版本号漂移事故",而 settings.ts 又手抄了一份 APP_VERSION,注入值全仓零引用。下次升版本必然静默漂移 —— 正是注释警告的那件事。

五条高危

#问题后果
H1「回溯」按钮每开一局累积一个,旧按钮闭包绑定旧对局第二局起顶栏叠出 N 个按钮;点旧的会污染正在进行的对局
H2顶栏返回钮每次开局 addEventListener 且从不移除第 N 局点返回会触发 N 次 goSelect()
H3存档页「存 入」是永远走不通的死功能所有入口都先 session = null;且返回路径硬编码 'normal' 重开,难度被悄悄改写
U-M1罗盘缺 pointercancel 处理移动端切后台 → 相位永久卡在 drag
M1启动自检抵消懒加载首屏多下 280KB
H1 和 H2 是同一个根因:shell.bar 是常驻元素,而每局的 Session 往上面挂东西却从不摘除。

修复:两个"出口"侧的洞

ts复制
ts
// Session.dispose():对局离场时必须调 // bar/main 都是常驻壳节点,挂上去的回溯按钮与 pointerdown 监听 // 不摘掉的话,每开一局就叠一层 —— 旧按钮的闭包还绑着旧 Game, // 点了会污染正在进行的对局。
wireBack 改成幂等:用 Symbol 属性记住旧回调,先 removeEventListener 再挂新。
修完后测试从 8 套扩到 11 套 —— 新增 ending / settings / hardcore 三套,专补审查指出的"测试盲测面"。
horizontal linehorizontal line

三、DAY 14 重头:存档从「回到章首」改成「回到那一刻」

旧语义的问题

原来的存档是章首档:读档 = 回到本章开头。
问题是:一章里有 3–5 轮经营,每轮 3 张牌。 玩家玩到第 4 轮想存档去吃饭 —— 回来发现前 3 轮白打了。

新语义:两件套(v2.2.0)

snapshot  章首快照(供章内回溯用)
live      当前时刻的全量状态(发牌/相位/随机轨迹)

最硬的一块:随机轨迹也要存

原设计有条原则写得明明白白:
回溯恢复历史状态,不恢复随机命运(不存 rng 状态)
理由是 SL 问题:随机数能存能读,玩家就能"穷举读穿骰子"。
但跨会话存档是另一回事 —— 你存了档关掉游戏,明天打开,总不能让世界重新掷骰子。
所以取舍是分开对待:
场景随机数理由
章内回溯不存,重新掷防 SL:可以试错,不可重播
跨会话读档存,原样续接存档是"暂停",不是"重开"
实现上让 rng 可序列化:
js复制
js
f._getState = function () { return a | 0; }; // 取出内部状态 f._setState = function (s) { a = s | 0; }; // 写回
主 rng 与已派生的流(risk / event / corr)都随档存取。

四类相位的 round-trip 测试

新语义最容易错的是"相位"—— 存档时可能停在四种不同相位:
测试存/读的位置
Around —— 第 2 轮已发牌时存;读档后相位/手牌/倒计时/属性/计次一致
B随机轨迹 —— 同一存档读进两个新对局,后续同操作逐位一致
Cchoice —— 抉择中存档;读档仍在抉择页
Dsummary —— 章末结算中存档;读档可推进下一章
B 是最关键的一条:它证明随机轨迹真的随档恢复了。

顺带补的两道校验

① 剧本身份绑定(scenKey) —— 五剧本属性维度同名,原校验只看难度,于是跨剧本的档能导入他本对局(带着别人的 flags 进不可达内容)。
② 脏档拒收 —— 存档存在 localStorage,是不可信输入:
js复制
js
if (!this.d.ATTR_NAMES[ak2]) return false; // 未知属性键 = 跨剧本脏档 if (!numRange(s.attrs[ak2], 0, this.attrMax(ak2))) return false; // 范围须落在本剧本上限内
horizontal linehorizontal line

四、DAY 15:存档页重做 + 设置页改滑杆

存档结构(用户二次拍板)

类型键数量写入时机
自动档qingshi.autos.v1每剧本最多 6 条只有一个:对局页点「返回」时玩家确认
暂存qingshi.stash.v1每剧本只留最近 1 条关页/刷新(pagehide)自动落,防丢兜底
原来的 6 个手动槽位,改成展示这 6 条自动档 —— 不再有手动存。从"玩家自己管理存档槽"变成"系统自动管,玩家只管要不要留"。
槽位还会显示轮次标识(经营过才显示)—— 因为存档现在能精确到轮次了。

设置页:开关+三档 → 横向滑杆

音频三项(音乐/音效/朗读)各一条横向滑杆:拖到最左即静音,
没有独立开关键(2026-10-15 用户拍板,参照常见音量滑杆的交互)。
滑杆左侧的喇叭图标随音量档位变化:0 打叉 / 低无波 / 中一波 / 高两波。
一个实现细节值得记:
拖动期间不重画整行(重画会销毁滑杆、打断拖拽),只就地更新图标与填充。
老存档的三档值(0.3/0.6/0.9)直接映射为滑杆位置 30/60/90,无需迁移。

剧本内容缩减

建了 备份_缩减前_2026-10-15,对五本剧本做了一轮压缩:
剧本行数变化
李斯5,896 → 5,793
荆轲4,838 → 4,803
韩信5,135 → 5,086
项羽4,899 → 4,875
陈胜4,668 → 4,629
horizontal linehorizontal line

五、DAY 16:TapTap 云存档 + 图鉴 + 朝代预告

云存档(game/tapcloud.ts)

这是第一个"平台相关"的模块。运行环境是 TapTap H5 容器注入的全局 tap 对象;普通浏览器没有 tap,本模块全部降级为 no-op。
三个设计决策写在头注里:
① 整包单存档,不打散
本地是「自动档按剧本分桶 + 暂存每剧本一条」的多槽结构,云端不打散成一存档一槽(存档数量有上限,且逐槽上传会撞上「一分钟一次」的频控),而是把两个 store 打包成一个 JSON,对应云端唯一一份名为 qingshi_saves_v1 的存档。
② 冲突取舍:整包新者胜
云端 modifiedTime 比本地最近变动新 → 云端整包覆写本地(覆写前留本地备份);反之上传本地。官方 QA 建议的「逐档对比引导玩家选」对整包方案不适用,多设备同时玩的冲突场景接受这个粒度。
③ 频控:一分钟一次
本地每次写档只标脏(lastChange),由调度器在距上次上传满 60s 后(debounce 1.5s)合并上传;关页 pagehide 时若已满 60s 补一次末班车。
还留了测试挂钩:window.__QS_TAP_UPLOAD_INTERVAL__ 可覆写上传间隔,测试把它缩到 1.5s 级别,不用真等一分钟。

跨局收藏(game/collection.ts)

审查时发现的缺口:成就/图鉴只活在当局内存里,关页面就全丢。
新增跨局收藏,键 qingshi.col.v1.<scenId>,与封存 Lua 版的 col_v1_ 同代不同名(两个平台各自的收藏各自累计)。
脏档收窄不拒收 —— 结局达成记录(endings)是 H5 新增字段,旧档没有它,读取时按空表收窄,不因为缺一个字段就拒收整份。

青史图鉴(ui/gallery.ts)

版式:左栏三 panel(收集总览环 / 印章收集条 / 筛选),右栏按剧本分节的结局卡片(已达成实线卡 / 未达成虚线卡,同名同尺寸不跳动)。
一个取舍:
五个剧本 JSON 在这里会全部按需下载(与首屏瘦身是 trade-off):图鉴页本来就是「我要看全部剧本」的场景,且 loadScenario 有缓存,入过局的剧本不再重复下载。
未达成的结局只留谜面,不剧透名字与赞文。

朝代预告页(ui/teaser.ts)

未开卷朝代(汉/唐/宋/明)在选择页右列展示的内容,替代原先的竖排「准备中」:
① 题头(朝代大字 + 年代 + 英文 + 金线)
② 一句话定位(lede,可带朱色高亮段)
③ 时代关键词(胶囊样式)
④ 开卷进度(考据/编纂/校验/开卷 四节点三态图)
⑤ 即将登场(只显示四字剧名+年代,不显示人物名、无人立绘 —— 用户拍板)
⑥ 底注(回秦提示 + 罗盘提示)

测试扩到 16 套

四天里测试从 7 套扩到 16 套:
chain / viewports / backtrack / save / audio / voice / reveal
ending / settings / hardcore / stash / gallery / tapcloud   ← 新增
scenarios(纯 Node)/ dev-check(专盯 dev 模式)
其中 hardcore.cjs 补的是一个从未被触发过的硬约束:硬核难度不可存档。
tapcloud.cjs 用 Page.addScriptToEvaluateOnNewDocument 在页面脚本前注入一个内存版 tap mock —— 真容器只在 TapTap 客户端里存在。
horizontal linehorizontal line

六、四天的数据

[图片:暂不支持黏贴,请手动导入]
项值
H5 源码6,192 → 约 9,000 行(16 个 .ts 模块)
浏览器验收7 套 → 16 套
engine.js+298 / −64(轮次存档 + 两道校验)
h5 四天改动+3,686 / −1,363
新增引擎方法makeStateRng / makeLiveState / _importLive / _validStateFields
审查三路并行深审 → 5 高危 + 15 中危,当日全部修完
评级5 级 → 10 级(甲乙丙上下中 + 丁)
资产管线4 条(美术 131MB→WebP / BGM 41MB / 配音 249MB / 截图)
horizontal linehorizontal line

七、四天最值钱的三条

① 换载体能一天做完六个页面,不是因为写得快

是因为规则不在渲染层里。 DAY 6 把规则抽成 JS 真源 + Lua 移植,当时只是为了做对拍网。但 DAY 12 换载体、DAY 13 一天重建六个页面 —— 这份"规则与渲染分离"的架构,决定了项目的迁移成本。

② “存/读"不是"保存数据”,是"保存状态机"

做轮次存档时才发现难点不在"把更多字段塞进 JSON",而在:
  • 相位 —— 四种不同相位都要能恢复
  • 随机轨迹 —— 不只是"存几个数",是"让随机流能在另一个时间点续接"
  • 可信边界 —— 存档来自 localStorage,是不可信输入
一个"存档功能"的复杂度,几乎等于它要保存的那个状态机的复杂度。

③ 最危险的 bug,是"注释诊断对了,代码没跟上"

审查报告里最值得记的一条:
最值得警惕的模式是「注释里正确诊断了问题,代码却没跟上自己的诊断」。
懒加载被自检抵消、版本号第三副本 —— 两个都是同一个模式:注释里写着"要注意 X",代码却做了非 X。
这类问题测试抓不到(代码本身没坏,只是没做它声称要做的事),review 才抓得到。
horizontal linehorizontal line

明天

  1. 真机验收 —— 云存档需在 TapTap 容器内实测(普通浏览器只能验降级路径)
  2. 配音全量转码 —— 试点已验证机制,--all 跑全量(约 100MB,谨慎)
  3. 首屏体积 —— 美术已瘦身,再核一遍实际下载量
  4. 成就图标 64 缺失 —— P3 美术批次待补
  5. 审查 backlog 的打磨项(低危清单)
horizontal linehorizontal line
载体:H5(Vite + TypeScript),规则引擎复用 prot/engine.js · 状态:六页面 + 罗盘 + 双音频 + 云存档 + 图鉴 + 朝代预告;16 套浏览器验收 · 存档语义换代(v2.2.0 轮次存档)· 验证:prot 全绿、tsc 通过、浏览器 11/11

#聚光灯gamejam开发者日志
【童谣镇】聚光灯第二次开发日志截图
【童谣镇】聚光灯第二次开发日志
开发进度: 美术 1、主角人物立绘已细化完成 2、所有NPC的QQ人形象与呼吸动画已设计完成 3、大部分UI界面已设计完成 4、面包房建模与树屋建模以及基础房屋、路灯、树木模型已完成。 5、制作过场动效,制作通用动效材质ing 6、广场资产替换、永续桥和植被的资产替换、房屋资产替换,河流制作 7、学校模型的材质完成 8、石墩子、小道具模型制作ing 9、NPC正比胸像绘制ing 策划 1、任务系统
16 赞
10 回复
目前个人认为目前聚光灯值得一玩的游戏截图
目前个人认为目前聚光灯值得一玩的游戏
T0是美术风格优秀,并且以玩法为主。 T1是玩法或者美术稍微弱一点,但也很推荐一玩。 排名不分先后: 1️⃣寂静园:复古像素风格的横版解密游戏,关卡设计精妙,很好的运用了"金币"这一关键机制,初解密会感到有些困难,不过当熟练机制之后,便会茅塞顿开 2️⃣spectreX:运用光影折射的横版解密,通关方式多样,不同的光影运用会有意想不到的效果。 3️⃣光与影:同样也是光影解密,和spectreX不同
11 赞
5 回复
00:30
《失心》游戏开发者日志01|游戏UI迭代及实机演示截图
《失心》游戏开发者日志01|游戏UI迭代及实机演示
进入《失心》之前,玩家首先看到的是我们工作室 UNLOOK 的标识。我们将原来的标识转成 SVG,并让其中的红色瞳点转动、观察,再逐步显露完整字形,希望这个短暂的开场能带出一点好奇和不安。 这次《失心》的开局 UI,我们围绕小灵通(因为游戏的主要交互道具就是小灵通)做了几轮调整,希望玩家从打开游戏开始,就能感受到故事里的年代和气氛(故事年代背景为2000s)。 早期版本先确定了一个方向:把菜单放进
15 赞
10 回复
00:07
雨天決行 开发者日志02-人工智能的自我修养截图
雨天決行 开发者日志02-人工智能的自我修养
又和大家见面啦!第二篇日志,说实话一开始不知道该怎么编排,但团队里惊喜的成果越来越多,我们已经迫不及待把更新的内容端上来给大家啦!那么事不宜迟,快来看看都有什么新情报吧ദ്ദി˶ー̀֊ー́ )✧ 一.美术(重磅升级) 以主美小为的生命力作为燃料(bushi)本次美术组取得了大进程!首先是各个ui界面的优化和细化,上次大家看到时还只是初具雏形的草稿,现在大多都完整起来了哦! 同时,随着配色的补全,手
43 赞
39 回复
00:34
《荒原复苏指南》开发日志④:关卡演示堂堂袭来!!截图
《荒原复苏指南》开发日志④:关卡演示堂堂袭来!!
- 人类曾因掌握元素合成技术而一度辉煌,又因滥用元素能量而逐渐从内里衰败。 - 30世纪80年代。社会文化充斥着激进乐观主义与庞大机械美学,在这里,污染和能源共生,幸福与痛苦并存。官方广播和宣传画里依旧在宣扬“科学将战胜一切”、“元素能量将再造新农田”的口号,而世界主城却已经因为污染过度而濒临崩溃、空间挤压严重。为了寻找新的生存空间与无污染能源,官方启动了“重构拓荒计划”。 - 玩家将作为前线拓展
18 赞
6 回复
【涌现符】开发日志#1截图
【涌现符】开发日志#1
大家好,我们是电子织机队,核心成员都来自同一个学校社团。 经过了五天的设计大烧烤终于把玩法大概定了下来。虽然题目一出大家立刻都想到了涌现式玩法,但是在这么短的时间内设计出优秀好玩的涌现式玩法对于没有太多经验的学生还是难度颇高,涌现式叙事对于没有专门编剧的我们队也难以达到理想的效果。 皮尔斯提出的"Symbols grow"是一个很有趣的概念,也即一个符号在使用中产生解释,解释引导预期和行动,经验又
4 赞
2 回复
开发者日志03截图
开发者日志03
大家好,第三篇开发日志来了。先公布一件事:我们的游戏正式定名为《尸涌》!这是一款以丧尸战斗和村庄探索为核心的第一人称射击游戏。这次也把最近几轮的战斗、成长、界面和探索进展一起整理出来。 故事从一位旅行者的失踪开始。主角作为她的好友,沿着她的旅行轨迹来到这个村庄,寻找她留下的线索,却逐渐发现村民与城里的制药公司之间,藏着秘密人体实验。村庄里的丧尸灾变究竟是怎么发生的?失踪的好友又去了哪里?这是我们刚
1 赞
01:21
【开发日志07】《我记得》|Windows 里的光与细节截图
【开发日志07】《我记得》|Windows 里的光与细节
第七篇日志,想带大家重新看一遍《我记得》的世界。 最近把录制切到了 Windows,也把 DLSS 加进了这次画面展示。以前日志里放出的主要是 Mac 开发版,这次可以换个角度看看:屋顶追逐时掠过的建筑、第四章跳跃后展开的另一重世界,还有 Boss 战里不断变化的光影和攻击。比起只看静态截图,我更想看看这些细节在奔跑、转场和战斗中能不能保持清楚。 这次实录使用 RTX 4060,开启 DLSS 质
5 赞
5 回复
个人向TapTap聚光灯GameJam经验分享截图
个人向TapTap聚光灯GameJam经验分享
首先简单介绍下我们的项目。 《机类Botkind》,名字借鉴于人类humankind。 核心玩法:编辑指令来控制机器人个体行为,进而在工厂中实现自动化产线 游戏类型:模拟经营,自动化,增量(存疑),编程启蒙(雾) 如题所示,这是一篇个人向GJ经验分享,面向对GJ流程好奇想要尝试或已经在尝试的同学,可能会包含很多主观见解。笔者在这次GJ里作为新人队长和主策划带领了一支十一人的新人为主的学生队伍完成了
4 赞
1 回复
00:30
《涌》第一次30秒实机演示截图
《涌》第一次30秒实机演示
整段都是游戏实机录的,没有单独做动画,中间夹着几段打精英怪和 Boss 的镜头,封面就是片子最后那一帧——血写的「涌」。 声音分两层:打斗声全是游戏里的真实音效,背景音乐是后面加的。 30 秒不长,希望大家喜欢。还有更多内容后面做好了也会录视频! #聚光灯gamejam开发者日志
4 赞
6 回复