基于对 template.html / template-swiss.html 两份模板与全部 references 的逐行对比分析(2026-07)。 本文档是方案建议,尚未整体实施;按阶段推进,每个阶段独立可交付、可回滚。2026-08-07 已先为演讲者 CSS / JS 加入边界标记、字节级同步脚本和 GitHub Actions,但尚未提取共享源文件。
两个主题是"复制粘贴后各自演化"的关系,同一份基础设施存在多份副本,并已实际漂移:
| 模块 | A 杂志风 | B 瑞士风 |
|---|---|---|
| 低功耗事件名 | ppt-low-power-change |
swiss-low-power-change |
| localStorage key | guizang-ppt-low-power(共用!) |
同左 |
| ESC 索引缩略图可见性修复 | ✅(本次补齐) | ✅ |
?slide=N 直达参数 |
✅(本次补齐) | ✅ |
Windows 字重补偿 is-win |
缺失 | ✅ |
| prefers-reduced-motion 自动降级 | ✅(本次补齐) | ✅ |
| 翻页/滚轮/触屏/键盘核心 | 两份逐字符几乎相同 | 同左 |
--sp-3~13 8px 间距阶梯 + motion token + --nav-safe-bottom.lead/.chrome/.foot 在模板内部重复定义(v1 与 v2 API 叠加)#hint 引用了未定义变量 --ink-tint(靠 fallback 兜底)__pipeAdvance 恒返 false,但 43 行 pipeline CSS 和动效 CSS 还在--ease-prod,JS 里又硬编码 EASE_PROD=[.2,0,.38,.9].display/.h1-zh 等),说明测量层本来就通用不建议把两个模板合并成一个"大一统模板"——两种风格的美学规则互斥(直角 vs 圆角、衬线 vs 无衬线),强行合并会让类名前缀和条件分支爆炸,也违背"每份 deck 单文件交付"的定位。
建议的整合层次:共享的是"基建"和"契约",不共享"皮肤"。
把各主题漂移的 JS 收敛为一份 assets/runtime.js(构建时内联进各模板,保持单文件交付):
deck-low-power-change,统一 localStorage key,保留各主题旧事件名一个版本作为 alias?slide=N、prefers-reduced-motion、Motion One 加载器initDeck({ darkClass:'dark', onSlideChange(){...} })实施方式二选一:
scripts/build-templates.mjs 把 src/runtime.js + 各主题 src/style-*.css + 皮肤 HTML 组装成各 template*.html。模板仍是完整单文件,但源头唯一。<!-- SHARED-RUNTIME v3 --> 注释标记,改动时用脚本校验各份一致。成本低但漂移风险仍在。当前演讲者模式已先落地 Phase 1b 的防漂移护栏:scripts/check-presenter-runtime-sync.mjs 与 .github/workflows/presenter-runtime-sync.yml。它不替代长期的共享源提取,但可以防止修改只落到其中一份模板。
如果未来合并 Bento 分支,以 main 上的演讲者运行时为上游,采用 main → bento 的合并方向;不要用旧 Bento 模板反向覆盖 main。
在各模板间统一命名和语义(值可以不同):
--sp-* 8px 阶梯(A 补齐)--text-primary/secondary/helper/on-color + --border-subtle/strong 各主题同名(A 需要从 opacity 方案迁移)--nav-safe-bottom + .nav-safe-bottom(-tight) 各主题同名(已完成:B 有,A 待补)--ease-*/--dur-* 统一命名,JS 从 CSS var 读取,消除双维护抽 scripts/lib/validate-core.mjs:
validate-swiss-deck.mjs(版式锁定)、新增 validate-magazine-deck.mjs(A 目前裸奔,公共核直接就能给它 M1/M2 测量)themes*.md 各份结构完全同构 → 统一"主题卡片 schema",每主题只留数据references/images.md,分叉处显式按主题参数化<SKILL_ROOT> 的路径或删除.lead/.chrome/.foot 双定义合并--nav-safe-bottom 安全区 token__pipeAdvance--ink-tint 未定义引用/Users/guohao/... 绝对路径(已完成)file:// 直开时 module 动态 import 本地 ./assets/motion.min.js 被 Chrome CORS 拦截,实际总是走 jsDelivr CDN;离线 + 直开的组合只能拿到静态降级。共享 runtime 时考虑把 motion 关键函数直接内联进模板,或文档明确"离线演示请起本地 server"完成 Phase 1+3 后,再增加"新主题"的边际成本会从"复制 2000 行再改"降到"写一份皮肤 CSS + 一份 layouts 文档 + 一个 validator config"。