Quiz Quest — 闯关式选择题课件生成器
> 目标:用户给一个主题 → 产出一份可双击打开的单文件 HTML 闯关答题界面。
> 答对有撒花/鼓掌/表扬/得分奖励,答错可重选直至答对,答对后展示解析,支持上一题/下一题,全对进入通关结算。
> 题库、插画、配色、布局、音效、封面、结算、文案、花边全部可定制。
> 需要分享时,可发布成在线链接 + 可下载压缩包直链(合集机制,见「合集归集」)。
铁律:任何要"下载"的交付物,都必须给出直链
> 用户用的是 WorkBuddy 网页版,没有"下载工作区文件"的入口。
> 因此只要用户想拿到某个文件到本地(课件、压缩包、技能包、资料……任何东西),
> 就必须把该文件发布成 HTTP 直链,并把链接给用户,并附一句:
> "把这条直链复制到浏览器地址栏打开,会自动下载"。
> ——这是默认动作,不用等用户开口说"下载不了"。
- 直链形式:
<shareLink>/download/<英文文件名>(放到合集站的decks/download/下即可被公开访问)。 - 文件名用英文(如
zoo.zip、quiz-quest-skill.zip),避免中文名在部分浏览器触发编码/重命名问题。 - 给链接时单独成行、用代码块包住,方便用户一键复制;不要把链接藏在长句子里。
- 交付前自测该直链返回 200,再发给用户。
- 适用范围不限于课件:技能包、题库、说明文档、示例压缩包等一切交付物同理。
When to Use
- 用户想为某个主题生成选择题测验/闯关练习(如"帮我做一个老年高血压的闯关答题课件")
- 用户提供了题库 JSON(或让 AI 生成)并要求渲染成答题界面
- 用户要求"互动测验 / 知识闯关 / 选择题课件"类页面
- 用户要求发布/分享课件("把课件发出去""给我个链接""怎么发给学生")→ 走「合集归集」
- 用户要求下载课件到本地("下载不了""存到电脑上")→ 走「合集归集」下载直链
- 用户要下载任何交付物到本地(插件包、技能包、压缩包、文档…)→ 发布成 HTTP 直链并给出(见上「铁律」)
Not for:问卷、填空/判断混合题型(当前仅单选+多选)、需要服务端计分的场景。
资源清单
| 文件 | 用途 |
|---|---|
templates/quiz-engine.html |
答题引擎模板(占位符由构建脚本替换) |
scripts/build_quiz.py |
打包脚本:校验题库 + 注入内容 → 单文件 HTML |
templates/demo-hypertension.json |
演示题库(老年高血压,5 题) |
templates/example-questions.json |
最小示例题库(3 题) |
references/theme-tokens.md |
换肤指南:全部 CSS 变量速查 + 预设主题 |
references/illustration-guide.md |
插画全链路:SVG 规范 / 图生图还原 IP 角色 / 点赞贴纸真透明 / 去水印 / 压缩内嵌 |
references/layout-recipes.md |
布局配方:16:9 满屏 / 一屏可见 / 左右分栏 / 窄屏堆叠 |
references/decoration-recipes.md |
花边边框配方:蕾丝 / 藤蔓 / 描边三套现成 CSS + SVG 角饰注入(--deco-art) |
references/workflow-checklist.md |
交付前检查清单 + 常见故障速查 |
scripts/verify_quiz.py |
端到端验证脚本:Playwright 全流程断言(插画加载/点赞切换/判题/结算/16:9);--unique-likes 强制每题点赞不重复 |
scripts/process_images.py |
插画后处理:去水印裁剪 / 棋盘格转真透明 / 连通域去残留 / 压缩 + base64 |
scripts/manage_hub.py |
合集管理器母版(发布/收录/删除/恢复/改内容/生成下载包);运行实例在 /root/.codebuddy/artifact/quiz-hub/,见「合集归集」一节 |
需求 → 改哪里(用户提要求时先查这张表)
| 用户说 | 对应做法 | 详见 |
|---|---|---|
| 换主题 / 换颜色 | --theme 传入 CSS 变量片段;成套改 --accent + --glow-* + --stage-* + --title-grad-* |
theme-tokens.md |
| 页面布局 / 比例 / 一屏不滚动 / 左图右题 | --layout split\|screen\|stack(screen 与 full 等价,均为满屏 16:9 一屏可见) |
layout-recipes.md |
| 音效 | 构建加 --sound(默认关闭);Web Audio 实时合成,无外部文件;产物右上角有 🔊/🔇 开关按钮随时可切 |
本文档·交互规则 |
| 答对/答错音效区分 | 引擎内置:答对上行三音阶、答错低沉双音(square+sine 下坠)、通关上行琶音 | 本文档·交互规则 |
| 答对表扬语音(每题不同) | CONFIG.speakOnCorrect 词库按题号轮换朗读(SpeechSynthesis);独立开关 --speak,与音效解耦,产物右上角另有 🗣/🤐 按钮 |
本文档·交互规则 |
| 音效 / 语音分别开关 | 构建 --sound↔--no-sound、--speak↔--no-speak;产物右上角两个独立按钮,互不影响 |
本文档·交互规则 |
| 插画 / 封面 / 结算配图 | 题目 art 字段;封面 --cover;结算 --result-art |
illustration-guide.md |
| 插画不要文字 / 去水印 | 提示词写明"无文字标注";裁剪右下角 9.5%+2% | illustration-guide.md |
| 答题正确时角色点赞 / 点赞形象 | 题目级 likeImg(每题可不同);全局兜底 CONFIG.likeImg;构建 --like-img |
illustration-guide.md·点赞贴纸 |
| 点赞位置不要固定 | 引擎内置随机落点(LIKE_SPOTS 10 个位置轮换,不与上次重复) |
本文档·交互规则 |
| 角色形象要贴合某 IP(电影/动画) | 用官方剧照做图生图参考 + input_fidelity:high;缺参考图先向用户索取 |
illustration-guide.md·形象还原 |
| 每题点赞形象不重复 | 题目对象内逐题写 likeImg,与 art 一一配对 |
本文档·Step 2 |
| 激励话语 | 改 CONFIG.praiseOnCorrect / praiseOnWrong / praiseOnFinale |
本文档·自定义点 |
| 特效(撒花/鼓掌/表扬) | 引擎内置;可在 celebrate() / festa() 调整 |
本文档·交互规则 |
| 边框 / 花边 | --deco 片段.css 注入 #deco-layer(CSS 花边)+ --deco-art 角饰.svg(SVG 角饰);记得给 .nav 留 padding(≥ 花边宽 + 8px) |
decoration-recipes.md |
| 题量 / 难度 / 文案 | --title / --subtitle / --badge / --start-label;题库 JSON |
本文档·Step 2 |
| 把课件发布/分享出去(要链接) | 走合集机制:manage_hub.py 收录 + publish,回在线链接 + .zip 下载直链两条 |
本文档·合集归集 |
| 让用户下载到本地(网页版) | 发 HTTP 直链 <shareLink>/download/<slug>.zip,粘到地址栏即下载 |
本文档·合集归集 |
追问边界:只问会影响成品的决策(布局模式、是否要音效、插画风格),其余用默认值直接开工,不要逐项确认。
快速流程(4 步)
确定主题与题量 → 生成题库 JSON + 插画 → build_quiz.py 打包 → 浏览器验证后交付
Step 1 明确需求
默认值(用户未提及时直接采用):
| 项 | 默认 |
|---|---|
| 题量 | 5 题 |
| 难度 | 中级(面向高职/继续教育) |
| 语言 | 简体中文 |
| 插画 | 每题一幅内联 SVG |
| 布局 | split(左图右题,16:9) |
| 音效 | 关闭 |
| 主题色 | 引擎默认(明亮暖色:奶油底 + 橙红强调) |
Step 2 生成题库 JSON
在 /root/.codebuddy/artifact/ 写 questions.json(不要放 /workspace)。顶层结构两种(A / B),题目字段示例另附(C)。
A. 纯数组(最常用)
[
{
"stem": "题干,支持 <b>加粗</b>",
"hint": "可选,一行提示",
"art": { "type": "svg", "content": "<svg viewBox=\"0 0 200 200\" ...>...</svg>" },
"options": ["选项A", "选项B", "选项C", "选项D"],
"answer": 1,
"explain": "解析:为什么选它,其他选项错在哪。"
}
]
B. 带封面 / 全局点赞(对象)
{
"cover": { "type": "image", "content": "<base64 或 data URI>", "alt": "封面插画" },
"resultArt": { "type": "image", "content": "<base64>" },
"likeImg": "<全局兜底点赞贴纸 data URI,可省略>",
"questions": [ ... ] // 必填,内容同 A 的数组
}
C. 单个题目对象的完整字段(用于"每题专属点赞形象")——这段是上面 questions 数组里的一个元素,不是新的顶层结构:
{
"stem": "...", "options": ["..."], "answer": 0,
"art": { "type": "image", "content": "data:image/jpeg;base64,..." },
"likeImg": "data:image/png;base64,..."
}
> likeImg 写在题目对象内即为该题专属点赞形象;缺省则回退到全局 CONFIG.likeImg,再缺省回退 👍 手势。
> 想要"每题不重复",就给 6 道题配 6 张不同贴纸。
字段规则(脚本强校验):
- stem 必填;options ≥ 2 个
- 单选:answer 为 0 起始索引且落在选项范围内
- 多选:用 "answers": [0, 2, 3](脚本会报错提示)
- art.type:svg(推荐)或 image(URL / base64);art 可省略 → 显示抽象占位图
- art.content 允许写裸 base64(无 data: 前缀)或完整 data URI/外链——构建脚本会自动补前缀(详见 references/illustration-guide.md §3.3)
- 题目级 likeImg 可选,为该题专属点赞贴纸;用于"每题点赞形象不重复"
- 选项默认随机打乱;顺序有意义时加 "shuffle": false
- 题干/选项/解析里仅允许 b/strong/em/br/code 标签(safeRich() 白名单),其余标签会被转义成文字显示
- ⚠️ 不要用 HTML 实体:写 FEV1/FVC < 70% 而不是 &lt; 70%。safeRich() 会二次转义 &,导致页面上直接显示 &lt;。原始 < > 在 JSON 字符串里合法,会正确渲染
- ⚠️ 多选题不用手写"多选"标记:只要该题用 answers 数组,引擎会在题号旁自动显示「多选题」徽标
- ⚠️ JSON 字符串里用「」或中文引号,直接写 ASCII 双引号会破坏 JSON
出题质量要求:
- 干扰项要有真实迷惑性,来自常见误解/易混概念,不凑数
- 解析讲"为什么",点出错项的坑,两三句即可
- 用自然的教学语言,禁止 AI 腔(不堆"首先/其次/总而言之"、"值得注意的是"、空洞套话)
- 单题信息量控制在一屏内,题干最长两行
Step 3 生成插画
- 首选内联 SVG:统一
viewBox="0 0 200 200",颜色用var(--accent)等变量(换肤自动跟随),role="img"+aria-label,文字标注font-size ≥ 14 - 位图插画(写实/3D/手绘):提示词写明"无任何文字标注",生成后裁掉右下角水印、压到 1000px、转 base64
- 要贴合某部电影/动画的角色形象:先向用户索取官方剧照,再用 ImageGen 的图生图(
image1传剧照 +input_fidelity:"high"),提示词里逐条列出角色特征(发型/服饰/标志物/配色),比纯文生图还原度高得多 - 点赞贴纸:
background:"transparent"生成;多数模型返回的是棋盘格/白底假透明,必须二次处理成真透明(见 illustration-guide.md·点赞贴纸) - 专业教学化,不幼稚不游戏化;内容页不留任何文字标签
- 完整规范见
references/illustration-guide.md
Step 4 打包
python3 <skill目录>/scripts/build_quiz.py \
--questions questions.json \
--title "主题 · 闯关测验" \
--subtitle "一句话说明规则" \
--badge "课程/模块标识" \
--start-label "开始闯关" \
--theme theme.css \
--layout screen \
--sound \
--speak \
--cover cover.jpg \
--result-art win.jpg \
--deco lace.css \
--deco-art corner.svg \
--like-img like.png \
--pass-score 5 \
--out /workspace/<主题>.html
只传需要的参数即可。--check 可只校验题库不产出文件。
> --layout 可选 split(默认)/ screen(=full)/ stack。
> --pass-score 决定"过关/星级"门槛,默认等于题量(即要求全部首答答对);想放宽就调小。
> 声音两路可分别控制:--sound/--no-sound 管答题音效,--speak/--no-speak 管英文表扬语音;默认都关,只给 --sound 时语音跟随一起开。
> 花边可拆两层:--deco 传 CSS(线框/底纹),--deco-art 传 SVG 角饰片段(注入 #deco-layer 内部)。
> 点赞形象优先用题库中的题目级 likeImg(可每题不同);--like-img 为全局兜底。
合集归集(用户要求"发布"时)
用户说"发布 XX 课件""把 XX 加到合集"时,走合集机制,而不是单独发一个链接。
为什么:发布通道每次只维护一个应用(一个域名),重复发布会覆盖。所以"多课件并存"只能靠
一个站点、多子路径——每份课件一个子路径 /<slug>/,各自有独立可分享 URL,域名固定不变。
合集管理器:脚本母版在 scripts/manage_hub.py(随技能分发、抗丢失);
运行实例在 /root/.codebuddy/artifact/quiz-hub/manage_hub.py(读写该目录下的 manifest.json 与 decks/,站点根 = decks/)。
> 若运行目录意外丢失:在 /root/.codebuddy/artifact/quiz-hub/ 重建,
> 把 scripts/manage_hub.py 复制过去,放好 decks/<slug>/index.html,再 init --force → publish 即可。
> 改动脚本后记得把母版同步回 scripts/manage_hub.py。
cd /root/.codebuddy/artifact/quiz-hub
python3 manage_hub.py list # 看合集(含已删除项)
python3 manage_hub.py add --file X.html --slug s --title "标题" \
--tag "冠心病 · 宽屏版" --tag-class t-blue --desc "一句话简介"
python3 manage_hub.py replace s --file 新版.html # 换某份内容
python3 manage_hub.py remove s # 软删除(可恢复)
python3 manage_hub.py restore s # 撤回删除
python3 manage_hub.py downloads # 只生成下载包(不发布)
python3 manage_hub.py publish # 生成下载包 + 渲染首页 + 发布
默认行为(用户说"发布 XX"时照做):
- 先
list判断该课件是否已在合集里:
- 已在 →replace <slug> --file <新产物>(内容更新)
- 不在 →add --file <产物> --slug <英文短名> --title <标题> ...(新收录) publish(会自动生成每份课件的下载压缩包)- 给用户回两条链接(重要,别只给一条):
- 在线看:<shareLink>/<slug>/
- 下载到本地:<shareLink>/download/<slug>.zip← 网页版用户靠这条直链下载
- 另附合集首页<shareLink>/与合集总下载包<shareLink>/download/合集-全部课件.zip
关于"下载直链"(网页版用户的刚需):
> WorkBuddy 网页版没有"下载工作区文件到本地"的入口。要让人把课件存到本地,
> 唯一可靠的办法是把文件发布成 HTTP 直链,用户把链接粘到浏览器地址栏就会自动下载。
> 所以每发布一份课件,都要同时给出它的 .zip 下载直链,不要只发在线链接。
- 单课件包:
decks/download/<slug>.zip→https://<域名>/download/<slug>.zip - 文件名用英文 slug(如
zoo.zip),避免中文名在部分浏览器触发编码/重命名问题。 - 合集总包:
decks/download/合集-全部课件.zip(中文名可接受,附在首页按钮上)。 - 两个包都由
publish自动生成;首页每张卡片下也带「⬇ 下载此课件」小按钮。
关键约定:
- slug 用英文短名(如 squirrel/copd/nezha/zoo),一旦定下不要再改(改了就换链接)。
- "删除"是软删除:文件移入 _trash/(站点根之外,不会被公开访问),链接 404、首页移除,可 restore 复原。
- --tag-class 可选 t-red/t-amber/t-green/t-blue,决定首页卡片徽标配色。
- 交付时把该课件的离线副本另存一份到 /workspace/quiz-collection/<课件名>.html。
合集维护常识(实测结论,别踩坑):
- 线上链接是实时反代到沙箱内的静态服务的:沙箱服务一停,链接立刻 504。
发布时已注册平台级自启动(restart:true),沙箱唤醒/恢复时服务会被拉起;但进程被手动杀掉不会自动重启,需重新 publish。
- 链接不要求登录:无 cookie / 陌生 UA 均返回 200(任何人拿到链接即可访问)。
- 课件本身零外部依赖(插画、音效全内嵌),所以下载到本地后断网也能完整使用——
要发给"随时可能没网"的人,优先发 .zip 直链而不是在线链接。
主题变量全集(--theme 文件可覆盖)
/* 基础色 */
--bg-0 --bg-2 --line --line-strong
--text-1 --text-2 --text-3
--accent --accent-2 --correct --wrong --gold
--shadow --radius --radius-sm --font --stage-ratio
/* 背景氛围光斑与舞台渐变(换色请成套改) */
--glow-1 --glow-2 --glow-3 --glow-4 --glow-5
--stage-1 --stage-2 --stage-3
--title-grad-1 --title-grad-2 --title-grad-3
/* 布局 */
--page-pad --stage-max-w --art-col --quiz-col --cover-max-w --result-max-w
只写要改的变量即可,未写的沿用内置默认值。
> 上面是速查索引;每个变量的含义、默认值、预设主题以 references/theme-tokens.md 为唯一权威。
> 其中 --cover-max-w / --result-max-w 未在 :root{} 声明,而是内联兜底(默认/一屏模式各一个值),覆盖它们同样生效。
交互规则(引擎已内置)
- 答错:
- 单选:该选项只显示红色边框/底色 + 轻微抖动,不带 ✕ 也不带任何标记;约 0.4 秒后自动撤销错误态、解除禁用、清空本项选择,回到未作答状态可重新选。答错只显示鼓励语,不展开解析。
- 多选:提交后所有被选中的项统一标红(只要红框,不显示 ✕,不暴露哪一个选错),约 0.42 秒后全部选中项一并清空重置。
- 首次答错会记入错题,且不再计分。 - 答对:绿色高亮 + 撒花 + 鼓掌动效 + 表扬大字 +
+1得分飘字;插画区上方弹出角色点赞贴纸(题目级likeImg优先,每题可不同);首次答对才计分。 - 鼓励语多样性:三类鼓励语池随机取用,
_lastPick保证不与上一条重复。 - 答对后:展开"解析"面板并滚动到可视区,选项锁定。解析头刻意不写"正确答案:X"——正确项由绿色高亮框直接表达,从源头杜绝字母与选项框不一致;解析正文里"答案是B/应选丙/选③"等标识仍会自动改写为当前界面字母(兜底)。
- 导航:未答对当前题时"下一题"禁用;"上一题"随时可用。每题的选项顺序在首次渲染时定格,之后回看字母/位置/解析完全一致;点"再来一次"才重新打乱。
- 结算:全部答对后"查看结算"亮起 → 奖牌 + 星级 + 通关统计 + 全屏礼花;支持"回顾错题"与"再来一次"。星级与标题由通关线(
--pass-score,默认 = 题量)判定:首答全对 = 3 星「完美通关!」;得分达线 = 2 星「过关!」;未达线 = 1 星「再来一轮!」(首次正确率仅作展示)。 - 音效与语音(两个独立开关,默认都关):
- 答对:上行三音阶(587→784→1046Hz triangle),明亮鼓励;若语音开关开启,同时朗读英文表扬词(CONFIG.speakOnCorrect按题号轮换:Great / Excellent / Awesome / Fantastic…每题不同,超出词库长度循环),SpeechSynthesis 合成、优先英文女声,快速连答自动取消上一条。
- 答错:低沉下坠双音(220Hz square + 156Hz sine),与答对明显区分;不朗读。
- 通关:上行琶音(C-E-G-C)。
- 音效开关:舞台右上角 🔊/🔇 按钮,切换CONFIG.soundOn;关闭时所有合成音静默。
- 语音开关:紧随其后的 🗣/🤐 按钮,切换CONFIG.speakOn;关掉时立即speechSynthesis.cancel()并停止后续朗读,但不影响答题音效。两个开关各管一路,图标/文案/aria-pressed各自同步更新。窄屏自动收缩为纯图标。
- Web Audio 实时合成,零外部音频文件。 - 角色点赞:答对时贴纸从随机位置弹出(
LIKE_SPOTS共 10 个落点,分布在插画区上/下两条横带,不与上次重复;靠右时锚点右移避免被圆角裁切)。形象取题目级likeImg→ 全局CONFIG.likeImg→ 👍 三级回退(由currentLikeImg()统一决策)。 - 解析纠偏(含错项引用):解析正文里"答案是B/应选丙/选③"会改写为当前界面真实字母;"所以 D 错误""A、C、D 错误""B 选项是错误的做法"这类错项引用同样按原始索引逐个映射。纠偏顺序:先错项引用、再答案引用(否则"选项X是错误的"会被误替换成正确答案字母)。
- 辅助:键盘 1-6 选择、←→ 翻题;
prefers-reduced-motion时关闭动画。
自定义点速查
| 想改什么 | 怎么改 |
|---|---|
| 配色 / 字体 / 比例 | --theme 传入 CSS 变量,参考 references/theme-tokens.md |
| 布局(满屏/分栏/堆叠) | --layout split\|screen\|stack(full = screen),参考 references/layout-recipes.md |
| 音效 | --sound / --no-sound(或改产物内 CONFIG.soundOn) |
| 表扬语音 | --speak / --no-speak(默认跟随 --sound;或改产物内 CONFIG.speakOn) |
| 花边 / 边框 | --deco 片段.css(CSS)+ --deco-art 角饰.svg(SVG 角饰,注入 #deco-layer),参考 references/decoration-recipes.md |
| 封面 / 结算插画 | --cover / --result-art,或 JSON 的 cover / resultArt |
| 点赞形象(全局) | --like-img,或 JSON 顶层 likeImg,或产物内 CONFIG.likeImg |
| 点赞形象(每题不重复) | 题库中逐题写 likeImg,参考 references/illustration-guide.md |
| 表扬语 / 通关语 / 分值 | 产物 HTML 内 CONFIG(praiseOnCorrect / praiseOnWrong / praiseOnFinale / baseScore) |
| 通关线 / 星级门槛 | --pass-score N(默认 = 题量);HUD 与结算页都会显示该值 |
| 表扬语音词库 | 产物 HTML 内 CONFIG.speakOnCorrect(按题号轮换朗读;由 CONFIG.speakOn 独立控制开关) |
| 标题 / 副标题 / 徽标 / 按钮文案 | --title / --subtitle / --badge / --start-label |
| 题库 | 重新跑 build 脚本即可,单文件无外部依赖 |
| 结算文案 | templates/quiz-engine.html 内 finish() 中的两处 result-sub 文案 |
经验教训(踩过的坑,务必避开)
- 主题只写
:root变量。用独立选择器改#stage(如#stage{width:...})会把舞台宽度压塌(实测退化成 200px)。要调尺寸请用--stage-max-w/--page-pad。 {{占位符}}必须留真实注入点。写在 HTML 注释里不会被替换,构建会报"仍有未替换占位符"。[hidden]会被作者样式覆盖。.btn{display:inline-flex}会导致hidden的"提交答案"按钮照常显示。模板已内置[hidden]{display:none!important}。- 花边会遮挡底部按钮。花边铺满舞台,"上一题/下一题"贴在底部两角。必须给
.nav留padding-left/right——按「≥ 花边宽度 + 8px」取值(例:圆点蕾丝 52px、藤蔓 60px、简洁描边 34px),不要用固定值,详见references/decoration-recipes.md。 - 换主题要成套改颜色。只改
--accent而不管--glow-*/--stage-*/--title-grad-*,会出现"配色换了但标题还是橙色"的割裂感。 - 交付用带时间戳的文件名。用户常因浏览器缓存看到旧版本;配合本地 HTTP 服务(
python3 -m http.server)最稳,不要用file://。 - 批量生成图片要换输出目录。文件名带时间戳时,同一秒内多张会互相覆盖。
- 图像生成按张计费(约 5–10 credit/张)。批量生成前先告知用户。
- 插画上不要留文字。生成时提示词写明"无任何文字标注",角标("插图")也要隐藏。
.quiz__body保持align-items:stretch。改成center会解除题目区高度约束,解析面板展开后会盖住"下一题"按钮(Playwright 会报#explain intercepts pointer events)。只在满屏模式(题目区不滚动)才允许center。<img src>的 base64 必须带data:前缀。裸 base64 会被浏览器当相对路径拼到当前页 URL → 请求串超长返回 HTTP 414,图片永远不显示(控制台只报 "Failed to load resource 414",极易误判)。构建脚本已内置normalize_art()自动补前缀 + 嗅探 mime(≥64 字符、纯[A-Za-z0-9+/=]、无图片扩展名 → 视为 base64)。完整说明与手写示例见references/illustration-guide.md§3.3,此处不再展开。- "透明背景"多半是假的。图像模型返回的是棋盘格贴图/纯白底,直接贴上去会露出方块。必须用边缘起始的 flood-fill BFS 清除"高亮低饱和"像素(
max(r,g,b)>185 且 max-min<20),再用getbbox()裁紧。 - 水印清除用"保留最大连通域"。去水印不能只裁边——水印常浮在角落独立成块。做法:对 alpha 通道做连通域分析,只保留面积 ≥ 最大域 3% 的部分,其余(含孤立水印小岛)置透明。
- 角色点赞要"每题不重复"时,配置落在题目级。全局
CONFIG.likeImg只能存一张;贴纸取值统一走currentLikeImg()(题目likeImg→ 全局CONFIG.likeImg→ 👍)。想换一批点赞形象只需改题库,不必动模板。 - 还原影视 IP 角色必须用图生图。纯文生图会跑偏(实测把哪吒画成普通丸子头女孩、太乙真人画成白胡子老寿星)。正确姿势:先要官方剧照 →
image1传剧照 +input_fidelity:"high"→ 提示词逐条列特征;多张图始终用同一张剧照保一致性。用户说"形象不对"时,先确认是否缺参考图。完整流程与提示词模板见references/illustration-guide.md§3.1b。 - 验证脚本的"故意答错"会拉低结算分。若测试里先点错再看正确率,得分必然 < 满分(首错不计分)。断言要按测试路径的预期值写(如"前两题首错 → 4/6、67%、2星"),不要机械断言 100%。另外
page.evaluate里改了state.index后要显式还原,否则后续断言全跑在错题上。 - 解析纠偏必须"先错项、后答案"。只处理"答案是B"而不处理"所以 D 错误",选项打乱后字母会指向错误的选项(实测 COPD 课件多选第 6 题暴露)。且若先跑答案规则,"选项X是错误的"会被整体替换成正确答案字母——错项引用必须先行,答案规则加"后接错误类词不替换"的负向断言。
- 语音朗读用 SpeechSynthesis,与音效开关解耦。
speechSynthesis.cancel()防止快速连答叠读;关语音开关时也要cancel()掐断在播的一条;voice 列表异步加载(onvoiceschanged时清缓存重取)。注意:Headless Chromium 可能无语音引擎,验证脚本只能断言词库配置与轮换逻辑、以及两个开关的data-on状态互相独立,不能断言真实发声。 --deco-art的角饰是"注入容器内部"的:#deco-layer是position:absolute;inset:0的铺满层,角饰用.cn.tl/.tr/.bl/.br四角定位 +transform:scale翻转。右上角要降透明度(那里常驻音效/语音开关),否则角饰与按钮打架。
交付前检查
build_quiz.py输出OK且无"未替换占位符"报错- 答案一致性自检:脚本会在 stderr 给 ⚠️ 提示——解析里写的字母/序数与
answer不符、解析强调的选项文本不是正确项、选项重复。出现提示必须先修题库再交付 - 浏览器(或 Playwright)过一遍:开始 → 答错一次(确认红框无 ✕、自动重置、答错音效与答对可区分)→ 答对 → 查看角色点赞贴纸(位置随机、语音词随题切换)→ 下一题 → 全对 → 结算;确认无 console error、底部按钮不被遮挡
- 两个声音开关各自独立:点 🔊/🔇 只翻
CONFIG.soundOn,点 🗣/🤐 只翻CONFIG.speakOn;互不干扰,图标/文案/aria 各自同步(关语音时要speechSynthesis.cancel())。解析错项字母一致性:正文里"X 错误"引用的选项必须不是绿色高亮项 - 插画真的加载出来了:断言
<img>的naturalWidth > 0(不是"元素存在"就行——414 时元素在、图为空;裸 base64 未补前缀是最常见原因,见经验教训 11) - 点赞形象每题不重复:读取
QUESTIONS.map(q=>q.likeImg),去重后数量应等于题数 - 多分辨率截图确认(1366×768 / 1440×900 / 1920×1080),舞台保持 16:9 且一屏可见(题干+选项+上一题/下一题都在视口内)
- 交付时把
questions.json一并放进/workspace(便于用户日后改题重打包),文件名带时间戳,并附一句使用说明 - 若走合集发布:
publish后把 在线链接 +.zip下载直链两条都回给用户(网页版用户只能靠直链下载到本地);并自测两条链接返回 200 - 任何"交付到本地"的东西都要给直链(铁律):课件包、技能包、题库、文档…一律发布成
.../download/<英文名>直链,单独成行放代码块,并注明"复制到地址栏即自动下载" - 逐步清单见
references/workflow-checklist.md