第15章 - 适龄设计规范与实现

15.1 交互规范清单:规范与代码的对照

产品定位(6–12 岁、核心指标是「记住」)推导出一套交互规范。下表把每条规范与实现方式、当前状态对齐 —— 已实现的给出落点,未实现的明确标注为待做:

规范 实现方式 状态
可点击区域足够大 游戏内按钮 ≥ 88 逻辑像素(BaseScene.addButton 默认 520×136);DOM 顶栏按钮 min-h-14(56 px,2026-10-18 从 48 px 提到 56 px);大厅整张卡可点 ✅
按钮不依赖悬停 按下瞬间下沉 + 音效;无 hover 语义;命中区按左上原点给 (0,0,w,h),外圈再放 12 px ✅
无失败惩罚、无倒计时、无限重试 放错弹回原位;后羿射掉最后一个太阳,天黑后太阳自己回来;诱惑有时限、不会等不到头 ✅
故事必须听完才轮到动手 旁白没念完不出现「继续」小手;story:ready 事件驱动;无语音设备按「读一遍」时长兜底 ✅
关键文本配拼音 大厅卡片与图鉴卡片都带 pinyin 字段 ✅
不靠颜色单独传达信息 对/错同时有图标与音效;女娲配对靠形状不靠颜色(色弱友好) ✅
尊重 prefers-reduced-motion ctx.reducedMotion 跳过场景淡入等动效;DOM 层补了媒体查询 ✅
声音随时可关、且记得住 游戏馆右上角 / 游戏内右上角 / 家长页三处同一状态;localStorage 记忆;setMuted 同时停掉正在念的旁白 ✅
随时能退出、误触不中断 游戏内左上角返回键 + 确认层(「现在回去吗?/ 再玩一会」) ✅
连续游玩 20 分钟提示休息 stores/playtime.ts 只统计玩游戏的时间;大厅一天提醒一次,点「知道啦」收起;家长页可回看 ✅
家长能找到、孩子点不到 长按标题 3 秒进家长页;清档要再长按 3 秒 ✅
二周目可以跳过故事 首次必须听完;completedBefore 为真时才出现「跳过故事」 ✅
通关后有「再来一次」 典故卡两个按钮;requestExit('replay') 原地重开,不回大厅 ✅
星星可解释 卡面一行:有失误 →「这一局有 n 次小失误…」;零失误 →「一次都没点错,真稳!」 ✅
无广告、无外链、无分享诱导、不采集个人信息 遥测只本地缓冲、flush() 空实现;无任何第三方 SDK;调试开关只对开发与自动化开放 ✅
PIN 型家长锁 目前只有「长按进入 / 长按清档」,没有密码锁 ⏳ 待做
失败反馈统一 17 个记失误的模板里,wrong 音效 6 个、抖屏 9 个、红色提示 10 个 —— 口径不统一 ⏳ 待做

这份清单的态度值得说明:项目把「没做的」明确列为「没做」,而不是含糊带过。2026-10-18 的「适龄体验与安全」那一轮,把上一版里的两个「⏳ 规划中」真的做了出来 —— 休息提醒与家长入口从文档承诺变成了代码行为。

15.2 记忆工程的代码落点(回顾与串联)

第 1 章讲过五层记忆机制,这里把每一层的具体实现位置补全,作为一张可坐标化的地图:

层 机制 实现位置
L1 情境代入 分幕绘本 + 旁白;玩家扮演典故中的角色 templates/story.ts;defineGame 强制每局以故事开场,且必须听完
L2 关键抉择 关键动作由交互承载;keyMoment 提供揭晓语与复习题 各游戏场景(曹冲的「秤被压垮」、后羿的「射九留一」);reward.ts 播 keyMoment.reveal
L3 多通道编码 看(画面)+ 听(TTS 念读)+ 做(拖拽 / 连点)+ 说(归位念白)+ 选(复习题) AudioBus.speak、orb.speak 归位念白、ReviewView 的三道题
L4 收集与结构 典故卡 + 图鉴;按分组与年代落位 reward.ts 的 card:unlocked;AlbumView
L5 间隔重复 + 迁移 1/3/7/21/60 天调度;transfer 题 progress/review.ts(纯调度)+ apps/site/src/review/quiz.ts(纯状态机);quiz 数据「每条 3 题含 1 道迁移」由 schema 强制

这张表是整套架构的「为什么」:keyMoment、misconceptions、quiz.kind、card:unlocked、ReviewScheduler 这些看起来零散的设计,全部服务于同一件事。

15.3 「少写字,多动手」的三个案例

五十三部游戏加起来,屏幕上几乎没有教学文字:开场的两句话,加上刚进玩法(或卡住时)出现的一句短提示(故事页点早了,也只会回一句「先听完这个故事」)。其余全靠图形、动画、音效与语音。三个最能说明问题的案例:

曹冲称象:从「点按钮」到「动手做」

第一版被判定「太死板、文字太多、说教」 —— 复盘出的问题是把「关键抉择」做成了文字选择题,孩子始终在读,没有在做。重做后的改动对照:

维度 改前 改后
故事 4 幕 +「下一幕」按钮 2 幕,每屏一句话,必须听完
关键抉择 三选一的文字题 不做题:让玩家自己试出来
玩法 点石头按钮看数字涨 拖拽大象与石头,看水痕
结算 文字测验 3 题 石头过秤,数字累加,与大象并列成等式
屏幕文字 每屏 1–2 句 + 题目 几乎没有,靠图形 / 动画 / 音效

「直接称 → 秤垮了」这第一步是设计的关键:问题是被玩家自己撞见的,不是被告知的。难度上调之后这一点更明显:大象 3300、容差 80,六块大石只有 3000,光搬大的凑不出来 —— 孩子必须自己发现「大小搭配」这个办法。

后羿射日:零惩罚的教学

「不能全射下来」这个分寸感,如果写成文字提示就是说教;做成机制则是:射到只剩一个 → 大地回春;贪心把最后一个也射了 → 天黑,一句「要留一个太阳」,太阳自己回来。孩子自己撞一次就懂了 —— 全程没有失败画面、没有扣分。

烽火戏诸侯:教训落在点火的人身上

信任是「点」出来的,不是「讲」出来的:点一次烽火,信任少一格;第二次来的兵马少了一半,走的时候有人在摇头;第三次「他们连城门都没到」;第四次点火是真的 —— 一个人也没来。全篇没有一句说教文案,孩子是自己把信任点完的。出处还注明「后世学者多存疑」,教训落在信用上,不落在褒姒身上。

15.4 两条硬规矩之一:故事必须听完

2026-10-15 加了一条全站规矩:每一幕旁白没有念完之前,屏幕上不会出现那只「点一下继续」的小手 —— 点哪都不翻页。

理由很直接:故事是这个产品的正片。跳过它,后面的动手环节就成了没有来由的小游戏 —— 孩子记住了操作,却没记住典故。难度的上调也是同一个目的:让「听过的故事」必须被真的用上。

实现上有三个技术点:

  1. 契约升级:AudioBus.speak() 返回 SpeechHandle,其 done 是 Promise<SpeechOutcome>('ended' 或 'unavailable')。念不出来也必须 resolve,否则静音、没装语音包、无头浏览器会永远卡在「正在听」(第 4 章);
  2. 兜底时长:没有语音的设备按「读一遍」的时长等 —— 'unavailable' 时用旁白字数估一个时长,否则「听完才能继续」在那些设备上等于没有;
  3. 可断言:念完发一个 story:ready 事件,无头验证与端到端测试靠它确定性地翻页;只有 ?autoplay=1 与 ?story=instant 这两个调试开关能跳过等待。

还在念的时候,屏幕下方是一个小喇叭 + 一条进度条;点早了只回一句「先听完这个故事」。二周目(completedBefore 为真)才出现「跳过故事」 —— 既不打断首次的沉浸,也不让愿意再玩的孩子每次都等 24–48 秒。

顺带修掉的一个小毛病:story.nag() 的 1.6 秒节流以前把 sfx('tap') 也一起吞了,念旁白时连点只有第一下有反馈。现在节流只节流气泡 —— 这是每个孩子每次玩的第一个交互面(53 个游戏 × 2 幕)。

15.5 两条硬规矩之二:难度上调一档,但失败惩罚依然是零

难度不是「更容易失败」,而是「多几步、判定收紧」。节选(完整表在 README):

典故 调了什么
曹冲称象 大象 3000 → 3300,容差 100 → 80:光搬大石头凑不出来
盘古开天地 撑天 30 下 → 40 下;「归位」的判定宽容度 70 → 52
女娲补天 五个洞的判定半径 74 → 62
精卫填海 / 愚公移山 30 下 / 30 担 → 40 下 / 40 担
夸父追日 一次跑完 6 秒 → 7.2 秒:河渭那一口要自己找时机
神农尝百草 六株草 → 八株(多了野薯与桂皮)
烽火戏诸侯 五座烽火台 → 七座:火光要传得更远才到天边
大禹治水 筑堤 10 筐 → 14 筐;三段河道每段 3 个锚点 → 4 个
狡兔三窟 每个洞 3 铲 → 4 铲;土坡判定半径 120 → 100
百步穿杨 五片柳叶 44/36/30/24/19 → 36/30/25/20/15(画的和判的一起改)

各场景「卡住才出现的提示」统一推后了 1.5–3 秒,扣分与失败依然不存在:点错了只是「再试试」,没有一个操作会让这一局玩不下去。

另一个方向上的调整也有:wait 类玩法原本真的要等 45–58 秒(太公钓鱼 58 秒、隔岸观火 45 秒),7–10 岁很难撑住。内容层改成 25 秒 / 22 秒,仍然保留「点诱惑会延后」的因果 —— 难度与耐心之间需要一条线,这条线是「孩子撑得住」而不是「设计上更纯粹」。

15.6 声音、休息与家长页

这三件事是同一轮(2026-10-18 产品审查)做出来的,代码落点都很小,但对「家长愿不愿意把手机给孩子」影响最大。

声音随时可关

stores/settings.ts 只做三件事:读回上次选择、setMuted 同步给 platform.audio、写回 localStorage。三处入口(游戏馆导航、游戏内右上角、家长页)共用同一个状态;setMuted(true) 会同时停掉正在念的旁白 —— 只关音效不关朗读,等于没关。TTS 音量也从 1.0 降到 0.8:孩子的设备常在耳边、公交上。

20 分钟休息提醒

stores/playtime.ts 的规则:

export const REST_AFTER_SECONDS = 20 * 60;

const restDue = computed(
  () => !record.value.reminded && record.value.seconds >= REST_AFTER_SECONDS,
);
  • 只统计「玩游戏的时间」:PlayView 里每 30 秒上报一次 addSeconds(30),大厅与图鉴的时间不算;
  • 一天只提醒一次:点过「知道啦」就把 reminded 置真,跨天自动归零;
  • 数据最小化:只存 { date, seconds, rounds, reminded },不记任何可识别信息;
  • 跨天与坏数据都不炸:read() 里日期不符就按空档处理,字段缺了也不抛错。

家长页

入口是长按标题 3 秒(App.vue 的 startParentHold),孩子不会误入,家长又找得到。页内四件事:

  1. 安全边界三条:不联网 / 无广告内购 / 存档只在本机(与 README「给家长」一节同口径);
  2. 这周玩过哪些典故:按 lastPlayedAt 倒序、最多 6 个,给家长看标题而不是内部 id;
  3. 声音开关与清除本机存档:清档要再长按 3 秒(parent-clear 的 pointerdown 起计时),避免孩子误触;
  4. 版本号(从 apps/site/package.json 读)。

配合游戏内的退出确认层与「再来一次」,孩子这一侧的可控性也补齐了:误触不会中断一局,想退出随时能退,退出后大厅里还有「继续上次」。

15.7 分级、定性与「孩子能读懂的措辞」

内容层的适龄化口径散落在几个字段里,2026-10-18 这一轮做了一次系统性修订:

维度 做法
定性(kind) 五分:myth / legend / history / fable / strategy。愚公移山原标「信史」(实为《列子》寓言)改成 fable;烽火戏诸侯的 chapter 说「未必是史实」,与定性打架 —— 一并修正
年代(era) 从年号串改成孩子能懂的说法,如「东汉末年 · 约一千八百年前」;yearApprox 仍保留用于排序
年龄(ageRange) 按难度重标 7 条,并同步 manifest 与测试
拼音 统一首字母大写(Mán tiān guò hǎi)
文言原文 53/53 的图鉴卡默认收起为「原文」折叠,孩子先看寓意与迁移句 —— 最长 53 字的文言对 7–10 岁是噪音
三十六计的价值引导 每计必须写 thinkingTag(2–6 字)与 transfer(一句正向迁移,≥12 字):计名与按语保留,但「今天可以怎么用」必须在界面上看得见
防御性计策 笑里藏刀 / 反间计 / 美人计 / 苦肉计只教识别,不教怎么使(写在《三十六计方案》的六条适龄化口径里,由内容审查落实)

「原文折叠」这一条是典型的孩子视角修正:从开发者的角度看,展示出处原文显得严谨;从孩子的角度看,那是看不懂的一屏字。严谨可以放在折叠里,理解必须放在第一屏。

15.8 复习题的防猜设计

到期复习上线后暴露的数据很刺眼:135 道题里 117 道(86.7%)的正确答案是第一个选项,「最长选项 = 答案」占 106/135(78.5%)。孩子只点第一个就能「通关」复习,评级毫无意义。

修法两层(第 10 章有代码):确定性洗牌(种子 = 内容 id + 题目 id,同一条内容每次顺序一致)+ 内容重写(53 条统一 3 题共 159 题,答案位置 53/53/53、「最长项 = 答案」 0/159、选项长度差 ≤4)。

这件事的教训不止于复习题:凡是「孩子能猜」的地方,设计就已经失败了。选对答案的概率不该由排版决定。

15.9 美术与音频策略

几何绘制:「换资源不改代码」

阶段 0 的美术全部用 Phaser Graphics 绘制:零图片资源,先把玩法与学习闭环跑通。统一的画法约定(写进 cartoon.ts):

  • 厚描边(统一 THEME.outline 暖黑,不纯黑)+ 圆角 + 落地阴影;
  • 同一套角色风格:圆脸、腮红、三头身比例;
  • 反馈动画标准化:popIn(出现)、squash(受重)、sparkleAt(成功)、createHand(引导)。

「换资源不改代码」是一条被结构保证的承诺:绘制代码全部收在 games/<id>/src/art.ts 的画法函数里,模板与工具箱只调用它们。将来切真素材时,只改 art.ts —— 模板、契约、外壳、测试全部不动。

配套的待办(方案中已列、实物未建):ASSETS-LICENSES.md 授权台账 —— 字体 / 音效 / 音乐逐个记录来源与许可证。项目文档把这条称为「会踩死人的坑,从第一天就做」;目前因为还没有引入外部资源,台账尚未创建。

音频

  • 音效:六个(tap / correct / wrong / splash / unlock / complete)用 WebAudio 振荡器实时合成,零文件(第 9 章有配方表);另有 tone(freq, ms) 支持「进度听得见」(盘古撑天音调渐高);
  • 旁白:浏览器 TTS(桌面 / 网页)+ 原生 TTS(安卓 —— WebView 没有 Web Speech API),中文 / 英文按 locale 选嗓音,音量 0.8;
  • 静音优先级最高:静音时不只不发音,还会「停掉正在念的」;
  • 将来换真人配音:按 locale 取音频文件,改的只是 AudioBus.speak 的实现;方案给单文件定的预算是 3–8 秒切片、≤ 100 KB。

15.10 性能与体积预算

指标 预算 现状
首屏 JS + CSS ≤ 60 KB gzip / 160 KB 原始 54.1 / 146.1 KB
单个懒加载 chunk ≤ 260 KB gzip / 1000 KB 原始 裁剪版 Phaser 220.6 / 856.3 KB
打开一局的全部新增流量 — ≈226 KB gzip;之后每局 3–8 KB
单图片 / 音频 ≤ 200 KB / 合计 600 KB 阶段 0 无资源文件
单局时长 3–5 分钟 由内容与关卡步数控制
中端安卓帧率 60fps;低端 ≥ 30fps 低端降级策略属后续

体积的守卫随时在跑:check-size.mjs 的七项预算在 pnpm verify、ci.yml 与 release.yml 里都会执行。对低龄玩家的设备而言这不是洁癖,而是「旧手机能不能跑」。

15.11 明确「暂不做」与仍然欠着的

技术方案里有一节专门写「Anti-scope」,列的都是主动不做的事:账号系统 / 后端 API / 排行榜 / 多人联机 / 内购 / 广告 / 3D / 后台 CMS / PWA(计划中,未实现)。

理由不是「不会做」,而是它们都会显著抬高成本与合规风险,且对「让孩子记住典故」这个核心指标几乎无贡献。反过来,清单里每一项都留了触发条件:内容资产超过上百条且需要非程序员编辑时再引入 CMS;路由超过 5 条或需要嵌套路由时再引入 vue-router;需要跨设备时再换 ProgressStore 实现做云存档。

同一份清单也如实记着还欠着的(第 16 章会展开):

  1. Idle 提示阈值不统一(8000 × 5 / 8500 × 1 / 9000 × 13 / 11000 × 3):孩子对「什么时候会帮我」的预期不稳定,统一要改 20+ 模板;
  2. 失败反馈不统一:17 个记失误的模板里只有 6 个有 wrong 音效、9 个抖屏、10 个红色提示;
  3. 复习间隔封顶:现在最长 60 天,对 7–10 岁偏长,建议封顶 21 天(需产品确认);
  4. 图鉴 / 大厅折叠:53 张卡一次铺开,三十六计可考虑按六套折叠;
  5. PIN 型家长锁:目前只有长按,没有密码;
  6. Android 权限收紧与 Tauri CSP:需要真机 / 打包回归;
  7. PWA 与真美术资源:维持「计划未实现」。

对低龄向产品而言,少做一个功能往往比多做一个功能更需要勇气 —— 但把「没做」写清楚,比假装做了要重要得多。

15.12 小结

  • 适龄规范不是口号,逐条都有落点或明确的「待做」标记;2026-10-18 那一轮把休息提醒、家长页、静音、退出确认、再来一次、跳过故事全部落地;
  • 记忆工程五层各有实现位置,keyMoment / quiz.kind / 复习调度这些数据结构是「为什么」的答案;
  • 两条硬规矩:故事必须听完(story:ready + 兜底时长)、难度上调一档但失败惩罚为零;
  • 「少写字、多动手」由三个案例支撑:曹冲的重做、后羿的零惩罚、烽火的信用机制;
  • 复习题的防猜提醒我们:凡是孩子能猜的地方,设计就已经失败了;
  • 美术(几何绘制)与音频(合成 + TTS)都是「阶段 0 零资源、换资源不改代码」的策略;
  • 历史准确性三条硬约束(出处、定性、存疑标注)与「原文折叠」的措辞修正,是教育产品在孩子视角下的底线。

下一章收尾:把散落在各章的所有踩坑记录集中起来,并回答常见问题。


← 上一章 目录 下一章 →