教学三尺堂

SKILL教育学习
教育学习 未标注权限 许可证不明确
安装这个技能

教学三件套(教案/课件/作业)一键生成:按学科+年级+知识点/教材课节

一句话选型结论

按资料字段整理

教学三尺堂是教育学习类的 Agent Skill,安装方式未标注,权限级别未标注,许可证不明确,有可直接复制的安装命令。技能本质是给模型读的说明书,效果取决于模型与客户端;装完先用一个小任务验证,再放进正式流程。

分类教育学习 安装方式未标注 权限级别未标注权限 许可证许可证不明确
累计安装 未标注 本周 未标注
GitHub 星标 未标注 仓库 未标注
下载量 未标注 技能市场下载数
权限级别 未标注权限 安装前请确认风险范围
许可证 许可证不明确 未说明

安装

未标注
在支持 Skills 的客户端里执行,装完问一句「你有哪些技能」验证
skillhub install user_0ed12131/teaching-trio
  1. 1
    确认客户端支持

    确认你的客户端支持 Skills(Claude、Codex、Cursor 等),并升级到较新的版本。

  2. 2
    拿到技能文件

    执行上面的命令安装;也可以把仓库里的 SKILL.md 手动放进客户端的 skills 目录。

  3. 3
    刷新技能列表

    重新打开客户端,或刷新技能列表,让新放进来的技能被加载。

  4. 4
    验证是否生效

    问一句「你有哪些技能」,确认列表里出现它,再拿一个小任务试跑。

技能档案

教育学习
字段来自技能仓库与公开索引,中文说明由本站标注
作者 / 维护方user_0ed12131仓库 未标注 · 版本 未标注
宿主客户端未标注技能可被这些客户端加载
安装方式未标注安装包 community
权限级别未标注权限安装前请确认风险范围
许可证未说明许可证不明确,商用前请自行确认条款
仓库可用性available技能仓库当前是否可访问
最近核验未标注上游最后核验时间 · 数据更新 1791621666
正文体量56.0 KBSKILL.md 原文大小,越大说明说明书写得越细

典型使用场景

3 类
按分类整理的常见用法,具体以 SKILL.md 为准
讲解知识点

按水平把知识点讲清楚。

出练习题

按章节生成练习与答案。

制定学习计划

按目标和时间排学习节奏。

选择建议

装之前先看这几条
按条目字段给出的判断,不替你决定用不用

值得选的地方

  • 有可直接复制的安装命令,不用自己翻文档找入口。

先想清楚的地方

  • 没有标注权限级别,实际能做什么要装好后确认。
  • 许可证不明确,商用或二次分发前先到仓库确认条款。
  • 没有做站内核验,内容以作者仓库为准。
  • 技能只是说明书,实际效果取决于模型与客户端,装完先用小任务试一遍。

更适合

  • 需要在教育学习场景里给模型补一套做法的人。
  • 愿意先读一遍 SKILL.md、确认它会让模型做什么的人。

不太适合

  • 对许可证要求很严、必须明确可商用的人。
  • 只想装完就自动变强、不打算看说明书的人。

同类对比

6 个同类
同分类里挑最接近的几条,字段以各自详情页为准
技能权限级别安装方式累计安装宿主客户端安装命令
教学三尺堂当前 未标注权限 未标注 未标注 未标注 有
食谱创建课堂课程 未标注权限 GitHub 仓库 25.5 万 Codex、Claude、Cursor 有
语言学习 联网访问 ClawHub 市场 23.6 万 OpenClaw 有
learning 效率 只读 ClawHub 市场 19.2 万 OpenClaw 有
学习习惯 未标注权限 ClawHub 市场 10.2 万 OpenClaw 有
日语家教 只读 ClawHub 市场 8.2 万 OpenClaw 有

SKILL.md 全文

56.0 KB
模型实际读到的说明书原文,来自技能仓库

教学三件套(教案 + 课件 + 作业)

一次对话交付「上课要用的整套材料」。

快速开始(零门槛,一句话即可开工)

用户说 得到
"生成人教版三年级上册《秋天的雨》的课件" 课件 HTML(双击即用)
"做一套初二物理《大气压强》的教案和课件" 教案 DOCX + 课件
"把这份教案转成课件和作业"(附上传的教案) 课件 + 作业(以底稿为蓝本)
"做三年级开学第一课的三科上课材料" 每科一个文件夹,各含独立三件

年级/教材在请求里写明就直接开工;没写且无法推断才问这一个;课件页数、课时划分、主题色等细节自动按教学惯例处理,不追问。本文件是编排层:负责参数收集、输入解析、目录组织、跨件一致性与统一交付;全部实现规范内联于本文档下方章节——单文件自包含,后续修改只改这一个文件:

产物 实现规范
互动课件 HTML 下方『互动课件实现规范』(结构、学科交互组件、绑定坑、jsdom 测试骨架)
防刷题作业 HTML 下方『防刷题作业实现规范』(四机制、确定性乱序算法、提交码、测试清单)
DOCX 流水线排错 下方『Windows 环境修复』(venv 自毁根因与 uv 重建步骤)

产物定义(验收以此为准)

  1. 教案 DOCX:教研标准结构——基本信息、教材分析、学情分析、教学目标(核心素养四维)、重难点、教学准备、教学过程(分环节,每环节含教师活动/学生活动/设计意图)、板书设计、分层作业(基础/提升/拓展)、评价量表、教学反思预设。有图片素材时嵌入正文对应位置。
  2. 课堂互动课件:单文件自包含 HTML。零外部依赖(无 CDN/音频文件/图片外链),双击即用;16:9 统一舞台(锁高下限不缩放);封面页+结束页默认必带;每个教学环节一页,页内嵌教案批注(教师/学生活动、设计意图);学科交互组件按需选配。
  3. 防刷题作业(用户勾选才生成):单文件 HTML。四机制齐上——变式池、选项乱序(确定性可复现乱序)、判据双答(判断+依据各占半分)、提交前零判分;配套行为留痕(用时/切屏/改答/换题)、localStorage 草稿、HW1: 提交码、教师核验区。无后端、无网络请求。

开跑参数(能推断就不问)

默认零门槛:一句话直接开工。 逐项判断,能推断的一律不问:

参数 处理
输入方式 自动判断,永不问——上传了文件=底稿模式;没上传=主题直出
是否生成作业 默认不生成——用户明确提到作业/练习/检测才产出,不追问
年级 + 教材版本 请求或底稿里写得有就直接用;只说"三年级"这类不全信息按主流版本(人教版)补齐;完全无法推断时才用 AskUserQuestion 问这一项

用户未指定的细节(课件页数、课时划分、主题色)按教案内容合理自定,不再追问。主题直出且教材口径拿不准时(单元课文、知识点归属),先 WebSearch 核对教材目录再动笔,禁止凭记忆编造课文名。

流程总览

[0] 参数收集(上方契约) → [1] 输入解析 → [2] 建任务目录
  → [3] 教案(先做,是另两件的蓝本) → [4] 课件 → [5] 作业(可选)
  → [6] 验证(jsdom 全绿)→ [7] present_files 一次性交付

输入解析(上传底稿时)

受管 Python 环境通常装不上 python-docx/python-pptx,不要尝试安装,直接用标准库:

  • .docx:zipfile + xml.etree.ElementTree 解 word/document.xml(命名空间 http://schemas.openxmlformats.org/wordprocessingml/2006/main);文本按 <w:p> 段落、表格按 <w:tbl> 行列拼;图片从 word/media/ 解出,经 word/_rels/document.xml.rels 映射回正文锚点。
  • .pptx:解 ppt/slides/slideN.xml,逐页提取文本与图;.html 直接读。
  • 提取的图片放任务 tmp/,最终嵌入用 base64 data URI。

任务目录与产物归集(成品一课一夹)

每任务独立子目录 output/<request-id>/,多科/多次任务不混目录。成品一课一夹、三件同放,用户拿到手的就是一个可直接转发的文件夹:

output/<request-id>/
├── 成品/                        ← 唯一交付目录(present_files 只从这里出;模型零回读)
│   ├── 01-教案-《课题》.docx
│   ├── 02-课件-《课题》.html
│   └── 03-作业-《课题》.html     ← 用户勾选了才生成,没有则缺席
├── stage3/ courseware/ homework/ ← 流水线中间件,归集后可弃
├── tmp/                         ← 上传文档解出的临时件
└── working/                     ← 构建脚本、题库 json、页面模板、测试脚本

归集规则:
- 单节课:成品/ 下直接放三件,命名 01-教案-课题.ext / 02-课件-课题.ext / 03-作业-课题.ext——数字前缀保证按 教案→课件→作业 排序,课题与教案课题一致,剔除 Windows 非法字符 \/:*?"<>|。
- 多课次/多学科同批:成品/ 下每课一夹,夹名 学科·课题(如 英语·Unit 1 Making friends),夹内同样 01/02/03 三件。
- 构建脚本直接把最终产物按最终命名写进 成品/;docx 流水线落在 stage3/ 的属中间件,最后一步移动改名进成品——不要让用户去中间目录里自己拼文件。

必须按学科各自成文件——多学科同批交付时绝不做单文件标签页切换。任何情况下都不做"母版再拆分":单科直出;多科同批也只写各科源片段,共享部分抽 working/base.css/base.js 由构建脚本拼装。

源层铁律:模型只编辑 working/ 源层小文件(base.css/base.js/page-*.html/lesson.md/smoke.js),禁止 Read / Edit 成品/、courseware/、homework/ 里的产物——产物含 base64 图片,回读一次就是几十万 token。改任何东西都改源层后重跑构建脚本。

教案规范(先做,是另两件的蓝本)

  • 教案只写一份 working/lesson.md 作为唯一真源:docx 流水线、课件页结构、作业考点池全部从它取材,禁止在流水线各阶段或课件/作业里重写教案内容。
  • 环节划分直接决定课件页结构与作业考点池,动笔前定稳。
  • 分层作业设计写进教案,作业件从此取材,两处口径一致。
  • 歌词/课文等原文转写不可靠时,明确写"以谱面/教材为准"并附原文出处,不硬编。
  • DOCX 走 tencent-docx 流水线生成;venv 报 No module named 'click' 时按下方『Windows 环境修复』章节重建,不绕开流水线手搓 docx。

课件与作业执行要点

按上方表格所列内联章节执行,编排层额外盯跨件一致性:

核对项 要求
封面信息 教材版本/单元/课时逐字段对齐教案表头
环节顺序与时长 与教案"教学过程"一致
结束页要点回顾与作业文案 = 教案重难点与分层作业
知识点表述 教案、课件、作业三处一致(概念定义、术语不允许各写各的)
作业 LS_KEY 每份唯一(如 hw.mus.rye.l25.v1),换学科/换课必换,防串草稿
旧学科残留 构建脚本断言替换次数,最后 grep 旧学科关键词确认无残留(含教师核验区标签)
干扰项质量 瞄准该知识点真实迷思概念,不随手写错项

验收标准(Definition of Done)

  1. 课件、作业各跑 jsdom 冒烟测试全绿(本机浏览器起不来时不要卡在截图验证;要点见下方课件规范的 jsdom 章节)。作业另跑:node --check 抽出的 <script>;grep 题干关键词确认源码无明文。
  2. 教案 docx:图片嵌入完整、表格不破版、文件体积非 0。
  3. present_files 一次性交付 成品/ 全部产物(按课次文件夹逐件列出),附简短清单说明每件是什么、给谁用(教案=教研自留,课件=课堂投影,作业=发学生)。
  4. 收尾询问可选优化(A4 打印版作业等),不自动做。

失败处理与用户沟通

任何环节失败(docx 流水线报错、jsdom 测试不过、教材检索无结果、构建脚本异常),必须向用户交代三件事,不许只甩原始报错:

  1. 出了什么——一句人话,如"文档转换环境损坏,正在重建"
  2. 影响哪件产物——教案/课件/作业;已完成的件不受影响,先交付已完成部分
  3. 怎么办——自动修复中(指明按哪节排错)/ 需要用户做什么;修复后重新验证再交付

环境兼容与排错

  • 主验证环境:Windows + Git Bash + 受管 Node/Python(jsdom 装于受管 node workspace,NODE_PATH 指向其 node_modules)。
  • macOS/Linux 通用,仅路径与 venv 布局差异(POSIX 用 bin/python)。
  • jsdom 测试通用坑:beforeParse(w){ w.scrollTo = function(){}; };作业页 JSDOM 设 url 才有 localStorage;脚本末尾 process.exit(0) 防 setInterval 挂住。
  • 工具调用一律绝对路径。

安全与合规

  • 所有产物本地生成、本地落盘;课件与作业零外链,不采集学生个人数据(作业提交码由学生本机生成、自愿发给老师)。
  • 作业防作弊机制须可关闭(顶栏开关),黄标仅提示教师、不自动扣分,把判断权留给教师。
  • 不生成违反教材审定的内容;涉及价值观表述(寄语、评语)保持中性正向。

反模式清单(禁止)

  • ❌ 多学科塞一个 HTML 用标签页切换
  • ❌ 课件 CDN 引依赖、外链图片/音频
  • ❌ 作业默认附带(用户没勾选就不做)
  • ❌ 题库明文写在 HTML 里(必须 Base64 + 构建脚本注入)
  • ❌ 用 Math.random() 打乱选项后存结果(必须 seed 派生的确定性乱序)
  • ❌ JS 运行时拼接图片占位名("IMG"+n 必裂,复用已有 img.src 或存 data URI)
  • ❌ 能推断的参数还去问(输入方式/是否作业永不问;仅年级教材完全无法推断时问一次)

互动课件实现规范

目标不是把教案贴成幻灯片,而是把教案的每个「环节」变成学生能动手的东西。每个环节保留教案批注(教师活动 / 学生活动 / 设计意图)供老师对照。

> 配套的课后作业页(防刷题 + 可保存提交)见下方『防刷题作业实现规范』章节。两者技术栈同源(单文件 HTML、零依赖、jsdom 冒烟测试),同一份教案可同时产出「课堂课件」与「课后作业」。

输出形态

单文件自包含 HTML,零外部依赖(无 CDN、无音频文件、无图片文件),双击即用、可直接发给任课老师。

必须按学科各自成文件,不要做成一个文件里用标签页切换多科——用户要的是能单独分发给语数外老师的独立课件。

源层与成品分离(铁律,压消耗的根本)

模型只编辑 working/ 下的源层小文件,禁止 Read / Edit courseware/、homework/、成品/ 里的任何产物。 产物含 base64 图片,回读一次就要消耗大量 token。

源层文件 内容 体积
working/base.css / base.js 全套框架(工具函数/render/go/buildJump/键盘/绑定/顶底栏),改一处全局生效 <15KB
working/page-NN.html 页面片段,一页一文件,图片写 src=&quot;IMG1&quot; 占位符,不嵌任何 base64 每页 <4KB
working/smoke.js 参数化测试骨架(传 html 路径 + 期望页数),复用不重写 ~8KB

build.py 是唯一写产物的通道:读源片段 → 图片按 md5 去重(同一图只嵌一次)→ 大图降采样(PNG 线稿转灰度 JPEG q80,75KB 可压到 ~20KB)→ 注入 base64 → 写入 courseware/ 或 成品/。

改版式 = 改源片段 → 重跑 build.py → 重跑 smoke.js。绝不直接改成品——改了下次重跑就被覆盖,且每次 Edit 都吃满 base64。

技术选型(关键决策)

需求 方案 说明
音效(节拍器、倒计时、对错提示) Web Audio API 实时合成 createOscillator 正弦/方波短音。不引入音频文件
雨声/白噪声环境音 Web Audio 白噪声缓冲 + biquadFilter 高低通 + LFO 调幅 2 秒 buffer 循环即可
英语发音 speechSynthesis 单词用 speak();整段连读必须不要在每次调用里 cancel(),否则前一句被掐断
时钟/秒针动画 内联 SVG + setAttribute(&#x27;transform&#x27;,&#x27;rotate(...)&#x27;) 60 刻度用 JS 生成,秒针 requestAnimationFrame 驱动
计时器 performance.now(),不要用 Date.now() 秒表精度要求
移除画布里的灰色占位图 直接写 SVG 矢量插画 教育场景用户明确反感"灰点噪点/无封面"的廉价观感

所有 API 都要做能力探测(window.AudioContext || window.webkitAudioContext、if(!window.speechSynthesis) return),缺失时静默降级,不能抛错。

课件结构

顶栏:学科标识 + 环节跳转下拉 + 教案批注开关 + 全屏放映
进度条
&lt;main id=&quot;deck&quot;&gt;
  &lt;section class=&quot;slide&quot; data-subject=&quot;math&quot; data-title=&quot;环节名&quot;&gt;
    &lt;div class=&quot;s-head&quot;&gt;环节徽章 / 标题 / 时长&lt;/div&gt;
    &lt;div class=&quot;s-body&quot;&gt;…交互组件…&lt;/div&gt;
    &lt;details class=&quot;tip&quot;&gt;教案批注(教师活动/学生活动/设计意图)&lt;/details&gt;
  &lt;/section&gt;
  …
&lt;/main&gt;
底部导航:上一环节 / 页码 / 下一环节
  • 一页 = 教案里一个环节,data-title 用于环节目录下拉。
  • 键盘:← → 空格 翻页,F 全屏,T 切换教案批注。输入框内不劫持按键。
  • 放映模式给 body.present 加 --scale 放大字号并隐藏教案批注;@media print 里全部展开、一页一张。
  • 教学提示必须留在课件里,不是另附文档。

封面页与结束页(默认要加)

课堂打开投影的第一眼是封面,最后一页是收束。默认就带上,别等用户提。

&lt;section class=&quot;slide&quot; data-subject=&quot;X&quot; data-title=&quot;封面 · &lt;课题&gt;&quot;&gt;   ← 第 1 页
  .cover / .cv-hero(accent 渐变 + 顶部 6px 色条)
    .cv-kicker 教材版本  /  .cv-title 大标题  /  .cv-sub 单元·课型  /  .cv-chips 核心素养
  .cv-body  左:.cv-rows 信息表(学科/教材/单元/课型/课时/授课教师·班级·日期留空)  右:学科定制内联 SVG
  .cv-foot  &lt;button class=&quot;btn solid lg&quot; data-goto=&quot;1&quot;&gt;开始上课 →&lt;/button&gt;
&lt;/section&gt;
…
&lt;section class=&quot;slide&quot; data-subject=&quot;X&quot; data-title=&quot;结课 · 谢谢大家&quot;&gt;   ← 最后一页
  .end / .ed-hero(本课结束 / 谢谢大家 / 学科副题)
  .ed-body  h3.sec「本课要点回顾」+ .ed-recall 四张 .ed-card(要点 / 补充)
            + .note 课后作业(呼应教案分层作业)+ .ed-quote 学科寄语
&lt;/section&gt;
  • 翻页跳转统一用 data-goto:$$(&quot;[data-goto]&quot;).forEach(b =&gt; b.addEventListener(&quot;click&quot;, () =&gt; go(+b.dataset.goto)))。合并母版里三科封面共用一个绑定,靠 cur 自动落到当前学科第 2 页,无需按学科写三套。
  • 封面/结束页不加 details.tip(它们不是教学环节)。
  • 封面插在学科分隔注释之后、结束页插在下一个学科注释(或 &lt;/main&gt;)之前——这样按学科切片时自动带上,不必改拆分逻辑。
  • 章节信息全部学科定制:教材版本、单元、课时、核心素养维度、寄语各不同;授课教师/班级/日期留空给老师手填。
  • hero 用 linear-gradient + radial-gradient 叠 color-mix(in srgb, var(--accent) …),随学科自动变色,不用为三科写三套 CSS。

统一页面尺寸(默认要做)

各页内容量天然不等,若不管,翻页时画面会忽高忽低。做法是锁 16:9 作高度下限,短页补满、长页自然高——不要用整体缩放,投影场景字号可读性优先。

.slide.active{display:flex; flex-direction:column; min-height:var(--slide-h,660px)}
.slide.active &gt; .s-head{flex:none}
.slide.active &gt; .s-body{flex:1 1 auto; display:flex; flex-direction:column; justify-content:center}
.slide.active &gt; details.tip{flex:none}
/* 封面/结束页没有 .s-body 这一层,必须单独补,否则撑高后底部留白 */
.slide.active &gt; .cover,.slide.active &gt; .end{flex:1 1 auto; display:flex; flex-direction:column}
.cover &gt; .cv-body{flex:1}
.end &gt; .ed-body{flex:1; display:flex; flex-direction:column; justify-content:center}
@media print{.slide{min-height:0!important} .slide .s-body{display:block!important}}
function fitStage(){
  var deck = $(&quot;#deck&quot;); if(!deck) return;
  var w = deck.clientWidth - 40;               /* 减去 main 左右各 20px 内边距 */
  if(w &lt;= 0) return;
  document.documentElement.style.setProperty(&quot;--slide-h&quot;, Math.round(w*9/16) + &quot;px&quot;);
}
fitStage();
window.addEventListener(&quot;resize&quot;, fitStage);
window.addEventListener(&quot;orientationchange&quot;, fitStage);
/* fullscreenchange 里也要调:body.present 把版心 1240 拉到 1500,必须重算 */
  • .s-body 用 flex:1 1 auto(不是 flex:1),靠 min-height:auto 让长页自然撑开。
  • 打印媒体查询里若忘了复位 min-height,一页一张会错乱。

常用交互组件(按学科选配)

语文
- 生字翻卡:.flip 点击翻面显示拼音/组词;会认字与会写字分开两页
- 总起句揭示:点段落卡揭示该段首句,最后汇总出句式规律
- 比喻/拟人配对:.match 左点右点,data-key 比对
- 色卡:点色块高亮,把「五彩缤纷」变成眼前的颜色
- 换词比较:两个词点选后给出表达效果的评语,不只是对错
- 仿说造句器:&lt;select&gt; 选词拼句 + 朗读;仿写工作台带 textarea 与一键复制
- 背诵提示:逐句揭示,先图后文

数学
- 倒计时:大数字 + 每秒音效,收尾用和弦
- 节拍器:setInterval 不行,要用 AudioContext.currentTime 前瞻调度(while(next &lt; ctx.currentTime + 0.2) + requestAnimationFrame)才能不漂移
- 估时挑战:开始后隐藏读数(否则学生偷看),按停后显示实际用时与误差,并给评价与记录表
- 秒针走一圈:提供「6 秒演示」与「真实 60 秒」两档;分针同步走一小格,让学生自己推出 1 分=60 秒
- 秒表:启动/停止/归零
- 单位选择:情境化选择题,每题给「为什么」的解析
- 概念可视化组件库(v1.0.7 沪教数学三上实战沉淀,其他学科可类比):
- 递等式逐步揭晓 .eqbox/.eqline:每行一行等式 + .why 理由标签(乘除步标「份总关系」、加减步标「部总关系」),点击走一行(bindEq:step 从 −1 起,beep(520+step*110) 音阶上行,末行双音庆祝)。把「先算哪一步」从讲解变成逐步揭幕
- 运算顺序点选 .pickrow .tok:算式整体做成可点 token,data-want=&quot;1&quot; 是该先算的部分;点对变绿弹礼花、点错抖红 0.9s 并追问「求出的是什么」。比选择题好——学生点的是算式本身而非答案
- 双算法对比 .dualgrid/.dualbox:三列(正确算法 / 从左往右陷阱 / 意义不清变体),data-ok + data-why,点击即判并在 .dualnote 显示说理。「冲突辨析」环节标配
- 关系模型卡 .relgrid/.relcard:两卡双色(份总/部总),data-rule 点击朗读,.hot 高亮当前分析到的一步
- 情境购物图 .scenebox/.good:emoji 商品卡(价格 .pr + 数量 .qt)+ 题目文本 .scenetxt,替代 AI 生图——纯 CSS 零成本且文字精确
- 分层闯关 .lvlgrid/.lvl:三关并排(⭐/⭐⭐/⭐⭐⭐),每关 .lvq 题面 + .lvp 选项 + .lvn 计数器,答对过一关
- 提示卡 .hintcard:虚线橙框口诀卡,闯关卡底部放「卡住就看这里」
- 计数圆点 .dotgrid:份总关系的可视化(几个几就点几组点)

英语
- 节奏拆句:beatbox 逐拍高亮 + 逐拍发音,先慢后快
- 角色对话:两个 &lt;select&gt; 换人名,动态生成台词 + 朗读
- 找朋友:随机名字卡 + 60 秒倒计时 + 控场提醒
- 造句器:输入自己的名字生成台词
- 星星贴纸:给同伴加星

低龄卡通化组件库(低龄版优先用,v2 实战验证)
- 贴纸卡 .sticker:大 emoji(58px)+ 大字(26px),一点即发音,hover 抬起旋转。把「听一听」按钮换成它,互动感立刻上来
- 集星正反馈:.flip.read 贴星 → #starBar 进度更新 → 集满自动 confetti(46) 礼花。跟读任务从"老师要求读"变成"我要集齐星星"
- 随机抽朋友 pairUp():点击随机抽 2 个角色高亮(.role.pair),抽中者上台对话。比"老师点名"参与感强得多
- 描红动画 .trace:SVG path + stroke-dasharray:var(--len) + drawit 动画,点卡片重播笔顺。书写顺序从"看不见"变成"可反复看"
- 卡通化三要素:贴纸白描边(border:4px solid #fff; outline:3px solid #ffd9a8)+ 底部实体阴影(box-shadow:0 8px 0 rgba(...),不要模糊阴影)+ 幼圆字体栈。模糊阴影是"精致中透露简陋"的主因
- 英文必须用独立儿童体且放字体栈首位:中文栈里的英文字形会被中文字体抢先渲染——幼圆自带的拉丁字母又瘦又呆(用户会嫌"英文字体不好看")。正确做法:font-family:&quot;Comic Sans MS&quot;,&quot;幼圆&quot;,&quot;YouYuan&quot;,...——Comic Sans 无中文字形,英文走它、汉字自动落幼圆,一处改动全局生效。Windows 自带候选:Comic Sans MS(圆润胖乎乎,首选)、Century Gothic(几何圆体,a/g 单层结构与手写一致)、Segoe Print(手写印刷体)、Ink Free(钢笔手写,太瘦不推荐)。可用 ls C:/Windows/Fonts/ 探测(Add-Type 与 reg.exe 常被安全策略拦截,别走那两条路);fontTools 可核对字体是否真含中文字形(ord(&#x27;你&#x27;) in cmap)
- 文字密度红线:低龄版每页可见文字 ≤ 150 字(正文,不含折叠的教案批注);教案内容全部移进 &lt;details class=&quot;tip&quot;&gt; 折叠抽屉,投影时只见画面不见说教

物理
- 缩放舞台(模型建构):&lt;input type=&quot;range&quot;&gt; 驱动 SVG group 的 transform=&quot;translate(x,y) scale(s)&quot;,把「贴近看细节」连续过渡到「只剩一个点」。用于质点、点电荷等从具体到抽象的建模环节——比直接给定义有说服力得多。收尾叠一个色点标记 + 概念文字标签(切 opacity),下方解说文案分 3 档同步切换(别一档到底)
- 参考系切换:同一运动的两种描述。&lt;svg data-ref=&quot;car|ground&quot;&gt; + CSS svg[data-ref=&quot;ground&quot;] .traj-p{opacity:1} 控制两条轨迹(竖直直线/抛物线)显隐;车厢位移用 @keyframes 做往返。切换时同步替换说明文案
- 参数对比判断:刻意选同一对象、不同问题、结论相反的组合(地球公转可/自转不可;排球判断明显出界可/压线不可;小车过杆不可/绕圈可)。这是打破「大小决定论」这类前概念最有效的一组题,比正面讲解管用
- 音效沿用 Web Audio;物理课不需要语音合成,别为了「和语文英语对称」硬加 speechSynthesis

交互绑定的坑(踩过的)

  1. 选择题必须按 .q-opts 分组绑定,不要按 .q-row。卡片里直接写 .q-opts 的题目不在 .q-row 内,按行绑定会漏掉,点了没反应。
  2. 翻卡/纯发音卡要拆开判断:if(f.dataset.say) speak(...); if(!f.dataset.nof) f.classList.toggle(&#x27;on&#x27;)。写成 if(f &amp;&amp; !f.dataset.nof){...} 会把发音也一起挡掉。
  3. buildJump(); render(); 是首屏渲染的唯一入口。拆分/搬运脚本时极易把它丢掉,症状是打开即白屏(没有 .slide.active)。
  4. 单科文件的初始学科状态要从 document.body.dataset.subject 读,不要硬编码 &quot;chinese&quot;,否则数学/英语文件的页码显示成 1 / 0、环节目录为空。
  5. 加配对时给初始选中做 clearSel() 干净切换;.m-stat 要 grid-column:1/-1 才不会挤进第二列。
  6. 动态生成的按钮(如换角色后重绘的 🔊)依赖事件委托(document 上监听 [data-speak]),不能逐个 addEventListener。
  7. 封面/结束页的存在会改变页码与目录长度:加完必须同步更新断言里的期望页数,并新增「首页有 .cover、末页有 .end、封面页 #prev 禁用、点 data-goto 后落在 .s-head 页且 #pg=2 / N、目录首项含「封面」末项含「结课」」这几条,否则漏渲染不会暴露。
  8. 选择题答错后再答对,要清掉残留的 .wrong:if(ok){ opts.forEach(o =&gt; o.classList.remove(&quot;wrong&quot;)); btn.classList.add(&quot;right&quot;); … }。否则同一张卡片会同时挂着红绿两种状态,投影上看很乱。
  9. buildJump() 若依赖页面列表,必须自取 SLIDES=$$(&quot;.slide&quot;),不要依赖 render() 先行填充——启动行 buildJump(); render(); 里 buildJump 先执行,此时 SLIDES 还是空数组,症状是环节目录下拉为 0 项、跳转失效(jsdom 断言 #jump.options.length 可拦住)。
  10. AI 生图(ImageGen)多张并行调用会同秒撞名互相覆盖——返回同一个 localPath,目录里只剩最后一张。多张插图必须逐张串行生成,每张落盘后立即改名归档再生成下一张;不放心时 Read 图片确认内容与用途一致。
  11. 页面片段里的内联 &lt;script&gt; 先于框架执行:build.py 把 base.js 注入在 body 之后,片段内的 script 排在前面,直接调 confetti() 等框架函数会 ReferenceError。正确姿势:片段里只做标记(如 b.setAttribute(&quot;data-bye&quot;,&quot;1&quot;)),在 base.js 的 bindAll() 里统一绑定。
  12. 节拍器歌词数组相邻项不能重复:[&quot;Hello!&quot;,&quot;Hello!&quot;,...] 前两拍文案相同,屏幕上看起来像卡住不动。滚动歌词必须保证相邻项不同(测试断言:连点 6 拍收集歌词,相邻两拍不重复 且去重数 ≥ 4)。
  13. SAPI TTS 输出格式必须实读验证,不能声明什么信什么:设置 SAFT22K16BITMONO 后 SAPI 可能仍输出 8bit 立体声 12kHz(wave 模块读出 sampwidth=1/ch=2)。若按声明的 16bit mono 拼接字节,波形会被错误重组放大 256 倍、整体削平(Flat factor 74、削平点 3.6 万处),听感"炸"。正确流程:合成后用 wave.open 实读 nchannels/sampwidth/framerate,按实际格式解码(8bit 无符号以 128 为中心,减 128 去直流,×256 升 16bit)再拼接。验收硬指标:Flat factor = 0、Peak ≤ −3 dBFS。
  14. 配音 + BGM 混音配方(ffmpeg 滤镜链):旁白链 highpass=f=110 → acompressor(threshold=-18dB:ratio=3) → alimiter(limit=0.90) → volume=-2dB;BGM 链 lowpass=f=9000 → volume 微调 → afade 入/出;侧链闪避 [vox]asplit=2[voxout][voxkey]; [bgmin][voxkey]sidechaincompress=threshold=0.02:ratio=4:attack=10:release=260[bgduck];amix=weights=1 0.75:normalize=0;最后 loudnorm=I=-16:TP=-1.5:LRA=9 统一响度。BGM 电平要比旁白低约 18dB 才是"轻量伴奏"感;验收分段测音量(说话段 vs 间歇段差 ≥ 15dB 说明闪避生效)。
  15. BGM 无版权做法:不引用外部音乐文件,用 Python 程序化合成(正弦叠加 + ADSR 包络模拟钟琴/八音盒,C 大调 I-vi-IV-V 和弦进行 + 主旋律,120BPM),峰值规范化到 −20dBFS。零依赖零版权,音色贴合低龄课件。
  16. 动画视频帧高度必须是偶数:libx264 + -pix_fmt yuv420p 要求宽高都能被 2 整除,1200×675 直接报 height not divisible by 2。用 1200×676(或加 scale=trunc(iw/2)*2:trunc(ih/2)*2 滤镜兜底)。
  17. SAPI 中文旁白两个坑:① SpMemoryStream.GetData() 返回的是裸 PCM 字节(无 RIFF 头),wave.open 直接报 "file does not start with RIFF id"——必须用 SpFileStream.Open(path, SSFMCREATEFORWRITE) 让 SAPI 自己写 WAV 文件;② 中文旁白要显式选声音:遍历 v.GetVoices() 按 Huihui/Yaoyao/Kangkang 匹配,否则默认英文声音念中文是拼音怪调。
  18. 提交码前缀长度与 slice 偏移必须同步:前缀从 HW1:(4 字符)改成 MHW1:(5 字符)时,verify() 里的 slice(0,6)/slice(6) 若没同步改成 slice(0,5)/slice(5),核验永远报"要以 MHW1: 开头"。改前缀就 grep 一次所有 slice。
  19. 视频时长对齐旁白:时间轴 JSON 中转:先合成旁白并实测各段时长,写 timeline.json({total, starts, durs});视频脚本与 BGM 脚本读同一份 JSON 决定总长与幕次边界(T1=starts[1]-0.25)。顺序千万别反——先定视频时长再配音必然对不上。
  20. 冒烟测试的时序陷阱:测试脚本自己先点的组件会改变页面状态——eqbox 点过 3 次后断言"初始未点亮"必然失败;[data-goto] 点击会跳页,键盘导航断言前必须先用目录 #jump 归位到已知页。断言测的是"当前状态"不是"初始状态"。

交付前必做:jsdom 冒烟测试

浏览器守护进程在某些机器上起不来,不要卡在截图验证上。用 jsdom 把每个可点元素点一遍,比手动点更彻底。

测试骨架沉淀在 working/smoke.js,参数化复用(node smoke.js &lt;html路径&gt; &lt;期望页数&gt;),换课件只传参不重写。每换学科新增的交互元素才往骨架里补断言,补完骨架本身也归档复用。

> 真实浏览器截图验证在本机不可用(agent-browser 起不来、chrome --headless 直接崩溃),不要反复尝试,直接用 jsdom 做行为验证。

# 一次性准备(隔离工作区,勿污染用户环境)
cd &quot;C:/Users/&lt;u&gt;/.workbuddy/binaries/node/workspace&quot;
node &quot;C:/Program Files/nodejs/node_modules/npm/bin/npm-cli.js&quot; install jsdom

测试要点:
- beforeParse(w =&gt; { w.scrollTo = () =&gt; {}; }) —— jsdom 未实现 scrollTo,否则首屏渲染就报错
- 加载:new JSDOM(html, { runScripts:&quot;dangerously&quot;, pretendToBeVisual:true, virtualConsole, beforeParse })
- 断言首屏状态:.slide.active 恰好 1 个、#pg 等于 1 / N、#jump.options.length 等于 N。这三条正好能抓住上面第 3、4 条坑
- 逐个切换页面并点击 .flip, .opt, .star, .sw, .beatbox, .m-item, [data-speak], .btn,每个点两次覆盖双态分支
- 跳过 #btnFull(全屏 API 在 jsdom 中不存在)
- 涉及布局的代码要单独断言:jsdom 里 clientWidth 恒为 0,布局函数会提前 return。用 Object.defineProperty(deck,&quot;clientWidth&quot;,{value:1240,configurable:true}) 注入真实宽度,再 window.dispatchEvent(new Event(&quot;resize&quot;)),然后断言 documentElement.style.getPropertyValue(&quot;--slide-h&quot;)。这验证的是算式与写回位置,不是像素级还原,但足以拦住"函数没被调用/算错分母"这类错
- &lt;script&gt; 被外部编辑器注入 data-page-node-id 属性时,构建前用 re.sub(r&#x27;\s+data-page-node-id=&quot;[^&quot;]*&quot;&#x27;, &#x27;&#x27;, html) 清掉;产物若再冒出此属性是文件预览面板回写的,重跑构建脚本即可,属无害属性

NODE_PATH=&quot;C:/Users/&lt;u&gt;/.workbuddy/binaries/node/workspace/node_modules&quot; node smoke_test.js *.html

复用已有源层做框架(换学科最快路径)

新学科课件不必从零写:从上一任务的 working/ 里直接搬源层——base.css(&lt;style&gt; 块全量)、base.js(工具函数/render/go/buildJump/键盘/.q-opts 绑定)、尾段(data-goto/底栏/全屏/resize/buildJump();render();)、顶栏底栏骨架。不要从成品 HTML 里抽——那是含 base64 的大文件,读它本身就烧 token。注意:

  • 抽出来先 re.sub(r&#x27;\s+data-page-node-id=&quot;[^&quot;]*&quot;&#x27;, &#x27;&#x27;, …) 清编辑器属性
  • 谱例/插图用占位符(src=&quot;IMG1&quot;)写在页面片段里,构建脚本统一替换成 base64 data URI;JS 里绝不能运行时拼占位名(img.src = &quot;IMG&quot;+n 替换不到,图片必裂)——要么用隐藏 &lt;img&gt; 复用其 .src,要么把 data URI 存进 JS 对象
  • 学科主题色只需在新 CSS 段覆盖 --accent/--accent-2/--accent-soft/--accent-ink 四个变量
  • 冒烟断言里的「16:9 舞台高度」期望值 = (版心宽 − 40) × 9/16(1240 版心 → 653px),别按 1200 直接乘

防刷题作业实现规范

交付形态是单文件自包含 HTML:学生双击打开就能做题,做完点提交会生成一段「提交码」,复制发给老师即可;老师把提交码粘回同一页面的「教师核验区」就能看到全部作答与过程记录。全程不需要任何后端。

配套的互动课件见上方『互动课件实现规范』章节,两者技术栈相同,可同一份教案产出两件。

一、先想清楚防的是什么

刷题的四种路径,以及对应的机制。四条要一起上,缺一条就有明显缺口:

学生的路径 对应机制 为什么有效
反复做同一份卷,记住「第 3 题选 B」 变式池:同一考点准备多个情境,每次随机抽取 题面每次都变,背的答案对不上
记住字母位置 选项乱序:正确项在 A/B/C/D 各位置均匀分布 记字母无效
只记结论不记理由 判据双答:每题要答「判断」+「判断依据」两处,各占一半分 只选对结论只得 5/10,蒙不出来
一遍遍试错直到全对 提交前不判分:作答过程中不给任何对错反馈 没有反馈就无法逼近答案
拿到卷子先翻答案/搜题 题库 Base64 编码存放 + 禁选中禁复制 提高成本,非密码学防线,配合前三条足够
事后改答案、换个卷重刷 过程留痕:改答次数、切屏次数、换题次数、总用时随成绩单一并上报 老师看得见,且「换卷无收益」——各变式难度等价

关键设计前提:变式之间必须难度等价(同一考点的不同情境,判据结构相同)。否则学生靠换题挑软柿子,机制就废了。

二、题目结构:判据双答

客观题不要做成「单选一题一答」,做成两问:

【情境】研究地球绕太阳公转一周所用的时间 —— 能否把地球看成质点?
  ① 你的判断(5 分)    A 可以看成质点   B 不能看成质点
  ② 你这样判断的依据(5 分)
     [正确] 地球的直径远小于公转轨道半径,各部分运动差异对所研究问题的影响可以忽略
     [干扰] 地球的体积那么小,小物体才可以看成质点          ← 针对「大小决定论」迷思
     [干扰] 因为地球在做圆周运动,做曲线运动的物体都能看成质点
     [干扰] 质点就是数学里的一个点,任何物体都可以直接看成一个点  ← 针对「质点=几何点」迷思

干扰项必须瞄准真实迷思概念,不要随手写错的。设计时先列出这个知识点学生最容易犯的 3 个错,每条干扰项对应一个。这样这份作业同时也是诊断工具——看错选项就知道是哪种误解。

主观题要点:
- 设字数下限(实时显示「已 N 字 / 至少 M 字」,未达标变色)
- 设举例禁用名单(banWords):要求"举一个本节课没出现过的例子",题干里用过的情境都列入名单,检测到就标给老师看
- 主观题不自动判分,只报完成度,写清「20 分由老师评阅」

三、技术架构

作业页(单文件)
├─ 题库:const POOL_ENC = &quot;&lt;Base64&gt;&quot;      ← 明文 5KB → 编码后 ~14KB
├─ 解码:自写 b64→bytes→utf8             ← 不依赖 atob / TextDecoder
├─ 出卷:paper = { seed, A:[sid...], B:[sid...], C:sid }
│        · 抽题与选项顺序全部由 seed 派生
│        · paper 只存「种子 + 选中的 sid」,不存答案
├─ 渲染:从题库 + seed 现算选项顺序
├─ 判分:同样的算法再算一遍 → 比对
├─ 状态:localStorage 存 { paper, ans, behavior, history }
└─ 提交码:HW1: + Base64(JSON)

3.1 确定性乱序(核心算法)

必须用可复现的伪随机,不能用 Math.random() 打乱后把结果存下来——那样只能存明文答案,或者存了顺序却还原不出正确项。

function hashSeed(s){ let h=2166136261; for(let i=0;i&lt;s.length;i++){ h^=s.charCodeAt(i); h=Math.imul(h,16777619);} return h&gt;&gt;&gt;0; }
function makeRng(seed){ let a=seed&gt;&gt;&gt;0; return function(){ a=(a+0x6D2B79F5)|0;
  let t=Math.imul(a^(a&gt;&gt;&gt;15),1|a); t=(t+Math.imul(t^(t&gt;&gt;&gt;7),61|t))^t; return ((t^(t&gt;&gt;&gt;14))&gt;&gt;&gt;0)/4294967296; }; }
function shuffled(arr, seedStr){ const r=makeRng(hashSeed(seedStr)), a=arr.slice();
  for(let i=a.length-1;i&gt;0;i--){ const j=Math.floor(r()*(i+1)); const t=a[i]; a[i]=a[j]; a[j]=t; } return a; }

选项顺序 = shuffled([正确项, ...干扰项], paper.seed + &quot;|&quot; + 题号 + &quot;|&quot; + sid),
正确位置 = shuffled(...).indexOf(正确项)。渲染算一次、判分再算一次,两次必然一致。

好处:localStorage 里只有种子和 sid,没有任何答案信息;刷新后题目和选项顺序完全不变。

3.2 utf8 安全的 Base64

浏览器 btoa 不支持中文,atob 在 jsdom 里也可能缺失。自己写,30 行,无处不兼容:

var B64C = &quot;ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/&quot;;
// b64ToBytes / bytesToUtf8 / utf8ToBytes / bytesToB64 / encodeText / decodeText
// 注意 4 字节 UTF-8 分支要正确合成代理对,否则 emoji 会炸

3.3 提交码

&quot;HW1:&quot; + encodeText(JSON.stringify({
  v:1, hw:题库ID, bv:版本, n:姓名, c:班级, s:学号,
  t:时间戳, at:第几次提交, ob:客观得分, ot:客观满分,
  d:[[题号, 部分, 判断对否, 依据对否, 得分], ...],
  sub:[{k:题号, dv:判断, big:&quot;&quot;, small:&quot;&quot;, tx:&quot;主观原文&quot;}, ...],
  bh:{ sec:用时秒, blur:切屏次数, blk:拦截次数, ed:改答次数, rd:换题次数 },
  seed:卷种子, p:卷面
}))
  • 一段包含全部信息(含主观题原文)约 2000 字符,微信里能发
  • 键名用短名压缩长度
  • 教师核验区粘贴 → 解码 → 渲染完整档案;解析失败要给友好报错,不能崩

3.4 必做:把「保存」做扎实

  • localStorage 每次作答后 debounce 700ms 自动保存,顶栏显示「已保存 HH:MM:SS」
  • 页面 beforeunload 再存一次
  • 刷新后必须完全还原:同一份卷(seed 不变)、每道题的选项选中态、主观题原文、学生信息
  • 没存储时要能降级到内存对象(try/catch 包住 localStorage),别让隐私模式下整页崩掉
  • 保存 ≠ 提交:提交是显式动作,提交后锁定全部控件、显示成绩单、生成提交码;刷新后仍能看到上次成绩单

四、行为留痕清单

记录项 实现 成绩单上如何呈现
总用时 Date.now() - startedAt 秒表;< 5 分钟标黄
切屏 visibilitychange + document.hidden 计数 次数;≥3 次标黄
复制/快捷键拦截 contextmenu/copy/cut/keydown(Ctrl+C/X/P/S/U、F12),preventDefault() 并计数 次数;>0 标黄
改答 同字段值变化时 edits++ 次数;≥6 次标黄
首次作答时间 记录 firstAt,与渲染时间比对 可用于识别「秒答」
换题 「换一套题」按钮计数 次数;>0 标黄

黄标项在成绩单里写一句「提示(供老师参考,不作为扣分依据)」,把判断权留给老师,不要自动扣分。

防作弊要可关闭(顶栏开关,老师演示时关掉),关闭后 body.noguard 放开 user-select。

五、标签与组件样式

  • 选中态 .opt.sel(靛蓝实底白字);提交后 .sel-ok(绿)/ .sel-bad(红)/ .miss(绿框,标出漏掉的正确项)
  • 下拉答错要在旁补一行「正确答案:xxx」——下拉框本身没法染色标正确项
  • 纯 CSS、不依赖任何图片;打印样式里隐藏顶栏/工具/教师区

六、交付前必做:jsdom 冒烟测试

测试骨架沉淀在 working/smoke_homework.js,参数化复用(传 html 路径 + 题库 json 路径),换学科只传参不重写;只有新增题型时才往骨架补断言。

浏览器守护进程在部分机器上起不来,不要卡在截图验证上。 用 jsdom 把整条链路跑通:

const dom = new JSDOM(html, { runScripts:&quot;dangerously&quot;, pretendToBeVisual:true,
  url:&quot;http://localhost/hw&quot;,                     // 不设 url 则 localStorage 不可用
  virtualConsole: vc,                            // 捕获 jsdomError 与 console.error
  beforeParse(w){ w.scrollTo=function(){}; } }); // scrollIntoView/scrollTo 在 jsdom 不存在

断言清单(本项目实测 66 条,可作骨架):

  1. 纯逻辑(不开 DOM):同 seed 可复现;不同 seed 结果不同;抽题覆盖池内全部变式;正确项在 4 个位置的分布均匀(这条直接证明乱序生效)
  2. 首屏:题量、进度 0、成绩单隐藏、无任何得分标记、无任何对错高亮、源码里搜不到题干明文
  3. 作答:点击选中态、进度更新、草稿落盘、改答计数、首次时间
  4. 行为:右键/复制被 preventDefault(用 cancelable:true 的事件查 defaultPrevented);切屏计数
  5. 校验:信息未填拦截、未答完二次确认并报剩余数量
  6. 判分:全对得满分、全错得 0 分(这两条一起才能证明判分与乱序映射一致)
  7. 提交码:生成 → 教师核验区解析 → 身份/得分/主观原文一致;非法码友好报错
  8. 刷新恢复:把 localStorage 内容塞进新 JSDOM 实例的 beforeParse,验证选项/下拉/标签/文本全部还原
  9. 换题:卷面变化、计数 +1、提交状态复位

测试脚本必须自己复制一遍 hashSeed/makeRng/shuffled,用它从 paper.seed 反推每道题的正确答案位置——页面内部变量在闭包里,外部拿不到。

测试脚手架的两个坑

  • 自动保存有 700ms 防抖:断言 localStorage 前先点一下「保存草稿」按钮强制落盘,否则读到的是上一次状态
  • 脚本末尾必须 process.exit(0) + 关掉所有 JSDOM 实例(window.close()):页面里的 setInterval 计时器会让 Node 进程永不退出,被外部超时 SIGTERM 杀掉时块缓冲的 stdout 会整段丢失,表现为"测试跑到一半就没输出了"

七、构建流程

题库不要直接写在 HTML 里(手写 1200 行 HTML 容易出引号错误),用三步:

working/hw_bank.json      题库明文(便于人工核对)
working/hw_template.html  页面模板,题库位置写 __POOL__ 占位
working/build_homework.py 读 JSON → Base64 → 替换占位 → 输出到 homework/

同课件铁律:模型只编辑 working/ 源层,禁止 Read / Edit homework/、成品/ 里的产物;改任何内容都改 json/模板后重跑构建脚本。

生成后立刻做两件事:node --check 抽出的 &lt;script&gt;(能抓住引号不配对这类致命错误),以及 grep 题干关键字确认源码里搜不到。

八、踩过的坑

  1. 引号开双闭单:&#x27;...&#x27; + x + &quot;]&#x27;) 这种拼接,第三个字符串写成 &quot;]&#x27;(开双引号闭单引号),解析器会把后续整段吞进字符串,报错位置却在很远的地方(missing ) after argument list)。排查方法:逐行统计单/双引号出现次数,奇数的那行就是嫌疑,比读二分法快得多。
  2. 复杂属性选择器拼接(&#x27;.opt[data-&#x27; + f + &#x27;&quot;]&#x27;)极易写错,且 else 分支往往根本不会执行 —— 优先用 closest(&quot;.grp&quot;) 这类结构定位,少拼选择器。
  3. 用 d.body.textContent 做文案断言会把 &lt;script&gt; 里的代码也匹配进去(模板字符串里常有同样的中文),要限定到具体容器(如 #paper)。
  4. 加「正确项提示」这类只在提交后出现的 DOM,要确认对应容器存在锚点元素(下拉框要 append 到 .sel-q),否则静默失败。
  5. 每新加一种题型(下拉、标签),记得同步 paintPaper 的标记逻辑和 qmark 锚点,否则那一部分永远没有得分标记。

九、跨学科复用模板的替换清单

模板带一批学科硬编码文案,换学科时逐条替换并在构建脚本里断言替换次数 == 1,最后 grep 断言无旧学科词残留:

  • &lt;title&gt;、顶栏 brand、页脚来源行
  • A 部分标题/导语/题干拼串(物理是 能否把X看成质点?,含 it.sc.object 字段)/ data-v 两个按钮文案 / 成绩单 myV、okV / 错题归纳与全对文案(x.part === &#x27;A&#x27; ? … 三元)
  • B/C/E 部分标题与导语、E 的 textarea placeholder(句式模板)
  • 教师核验区主观题标签:所选模型、大物体举例、小物体举例、模型迁移 —— 这四处藏在 verify() 里最容易被漏掉
  • LS_KEY 必须换(物理是 hw.phy.*),否则同一台机器做过多学科作业的学生会互相串草稿
  • 表单占位(年级/班级示例)

注意:核验表是紧凑格式([key, part, vOk, rOk, score]),只显示 ✓/✗ 和得分,不含作答原文——断言别去找答案文本,找主观题标签即可。


Windows 环境修复(tencent-docx venv)

症状

在 Windows 上跑 tencent-docx 插件流水线的 Stage 3(doc-converter → html-to-docx)时:

  1. 直接调用转换报错:ModuleNotFoundError: No module named &#x27;click&#x27;
  2. bash &lt;plugin_root&gt;/scripts/wb/local/setup-html-to-docx.sh 看起来跑通了(打印 ✓ venv ready),但跑完 ~/.venv-html-to-docx 目录凭空消失
  3. 手动 uv venv 时输出 Activate with: C:\c\Users\&lt;user&gt;\.venv-html-to-docx\Scripts\activate —— 这是误建路径的信号

根因

setup-html-to-docx.sh 是按 POSIX venv 布局写的(判断和调用都用 $VENV_DIR/bin/python),但 Windows 上 uv venv 产出的是 Scripts/python.exe。于是:

# 脚本第 86 行:Windows 上永远判定为&quot;venv 不存在&quot;
if [ ! -x &quot;$VENV_DIR/bin/python&quot; ] || ...
    rm -rf &quot;$VENV_DIR&quot;          # ← 把之前建好的 venv 删掉
    uv venv --python 3.12 &quot;$VENV_DIR&quot;
fi
# 第 94 行:PY=&quot;$VENV_DIR/bin/python&quot; 仍指向不存在的路径
# → import 探测全部失败 → uv pip install --python &lt;不存在&gt; 失败

结果:venv 被删、依赖没装、脚本却因为 | tail 吃掉退出码而"看起来成功"。

另外,在 Git Bash 里把 /c/Users/... 这类 MSYS 路径传给 Windows 版 uv.exe,uv 会当成相对路径处理,落到 C:\c\Users\...——所以传路径必须用 C:/Users/... 形式。

修复步骤(PowerShell / Git Bash 通用)

1. 确认 uv 位置

uv.exe 通常已在 C:\Users\&lt;user&gt;\.local\bin\uv.exe(插件自带的 SessionStart hook 装过),不要再 curl 装一遍。

export PATH=&quot;$HOME/.local/bin:$PATH&quot;
uv --version

2. 用 Windows 风格路径重建 venv(关键)

# 注意:必须写成 C:/Users/... ,不能写成 /c/Users/...
uv venv --python 3.12 &quot;C:/Users/&lt;user&gt;/.venv-html-to-docx&quot;

若提示 A virtual environment already exists,加 UV_VENV_CLEAR=1。

3. 安装依赖

cd &quot;&lt;plugin_root&gt;/skills/html-to-docx/scripts&quot;
uv pip install --python &quot;C:/Users/&lt;user&gt;/.venv-html-to-docx/Scripts/python.exe&quot; \
  --only-binary=:all: -r requirements.txt

依赖清单:python-docx html-for-docx beautifulsoup4 lxml httpx Pillow click pytest(20 个包,约 3 秒装完)。

4. 验证

&quot;C:/Users/&lt;user&gt;/.venv-html-to-docx/Scripts/python.exe&quot; -c &quot;import click, docx, bs4, lxml, html4docx; print(&#x27;deps OK&#x27;)&quot;

> 注意:html-for-docx&gt;=1.2 的实际模块名是 html4docx(不是 html_for_docx),转换器源码 from html4docx import HtmlToDocx 也是这个名字。若照旧命令 import 报 No module named &#x27;html_for_docx&#x27;,先查 site-packages 里的真实目录名再判定,不要盲目重装。

5. 执行转换

cd &quot;&lt;plugin_root&gt;/skills/html-to-docx/scripts&quot;
&quot;C:/Users/&lt;user&gt;/.venv-html-to-docx/Scripts/python.exe&quot; -m html_to_docx convert \
  &quot;&lt;input.html&gt;&quot; -o &quot;&lt;output.docx&gt;&quot; --page-size A4 --orientation portrait

成功输出:{&quot;success&quot;: true, &quot;docx_path&quot;: &quot;...&quot;, &quot;warnings&quot;: [], &quot;fields&quot;: []}

> 转换时 stderr 会打印 MarkupResemblesLocatorWarning(bs4 对 URL 样文本的误报),属正常噪声,可忽略。

6. 清理误建目录

若见过 C:\c\Users\...,删掉它:

rm -rf &quot;/c/c&quot;

判定成功的标准

  • Scripts/python.exe -c &quot;import html_to_docx&quot; 无报错
  • 转换 JSON 的 success 为 true
  • 目标 .docx 落盘且体积非 0(三份教案的文档约 70 KB)

备注

  • setup-html-to-docx.sh 是上游插件的幂等脚本,在修好的机器上不要再重复跑——每次跑都会把 venv 删掉(见根因)。跨会话如果转换报 No module named &#x27;click&#x27;,按上面步骤 2–4 重来一遍即可。

版本记录

v1.0.7(2026-09-16)

  • 数学学科首战(沪教版2024三上《两步四则运算》)全套落地:教案 DOCX(doc-converter 流水线,45KB 零警告)+ 11 页互动课件(748KB 含 13.6s 带旁白 BGM 动画)+ 防刷题作业(MHW1 提交码)。
  • 新增数学概念可视化组件库(递等式揭晓 / 顺序点选 / 双算法对比 / 关系模型卡 / 情境购物图 / 分层闯关 / 提示卡 / 计数圆点),核心设计思想:把「运算顺序」从讲解变成点击与揭幕。
  • 新增坑位 16-20:视频高度偶数、SAPI 中文声音 + SpFileStream(GetData 无 RIFF 头)、提交码前缀 slice 同步、时间轴 JSON 驱动视频时长、冒烟测试时序陷阱。
  • 程序化动画代替 AI 视频:PIL 逐帧绘制三幕动画(概念讲解类视频不需要 AI 生成——数字、算式、高亮卡必须精确无误,程序化绘制 100% 可控且 182KB 超小体积);封面仍用 ImageGen。
  • 教材版本歧义须确认:沪教版数学存在 2024 新教材与旧教材两套目录结构(「两步四则运算」vs「复习与提高」),首次生成某学科某版本前先 WebSearch 核对,歧义时 AskUserQuestion。

v1.0.6(2026-09-16)

  • 修复重大音频削波 Bug(坑位 13):SAPI 声明 16bit mono 但实际输出 8bit stereo,按声明格式拼字节导致波形放大 256 倍削平(用户反馈"声音炸了")。修复后 Flat factor 74.4→0、Peak 0dB→−3dBFS。
  • 新增 BGM 配方(坑位 14、15):ffmpeg 侧链闪避混音链 + Python 程序化合成无版权童谣 BGM;响度统一 −16 LUFS。
  • 混音平衡方法论:BGM 比旁白低约 18dB 才有"轻量伴奏"感;分段测音量验证闪避(说话段与间歇段差 ≥ 15dB)。

v1.0.5(2026-09-15)

  • 新增「低龄卡通化组件库」:贴纸卡 .sticker、翻卡集星 + 集满礼花、随机抽朋友、SVG 描红动画四件套及卡通化三要素(贴纸白描边 / 实体阴影 / 幼圆字体),源自 Unit1 Hello 低龄英语课件 v2 实战。
  • 新增两个坑:① 页面片段内联 &lt;script&gt; 先于 base.js 执行,不能直接调框架函数,须 data 属性标记 + bindAll() 统一绑定;② 节拍器歌词数组相邻项重复会让节拍"看起来卡住",滚动歌词必须相邻不重复。
  • 文字密度红线:低龄版每页可见正文 ≤ 150 字,教案内容全部折叠进 &lt;details class=&quot;tip&quot;&gt;。

v1.0.4(2026-09-15)

  • 修正过时验证命令:html-for-docx&gt;=1.2 的模块名为 html4docx(原 html_for_docx 已失效),Windows 环境修复章节同步更新。
  • 新增两个实战坑:① buildJump() 必须自取页面列表(依赖 render() 先填 SLIDES 会导致目录为空);② ImageGen 多张并行同秒撞名互相覆盖,AI 插图必须逐张串行生成并立即改名归档。
  • 低龄版裁剪先例:经用户要求可裁剪「判据双答」(低龄点选式作业无依据可答),但变式池、确定性乱序、提交前零判分、提交码与教师核验区必须保留;干扰项按 3 选 1 设计并在测试中按 3 位置断言分布。

v1.0.3(2026-09-15)

  • 零门槛开工:参数全部可缺省——输入方式自动判断、作业默认不生成、仅年级教材无法推断时才询问,一句话即可出全套材料。
  • 失败沟通规范:任何环节失败须说明「出了什么 / 影响哪件 / 怎么办」,不再甩原始报错。
  • 快速开始示例前置,补齐普通用户视角的使用案例。
  • 清理无效内容:删除与现行规则矛盾的「母版拆分」旧流程章节及历史叙事性论据,精简 description。

v1.0.2(2026-09-14)

  • 源层/成品分离铁律:模型只编辑 working/ 源层小文件(base.css / base.js / page-*.html / lesson.md / smoke.js),禁止 Read/Edit 产物——产物含 base64,回读一次就是几十万 token。
  • 构建脚本图片治理:md5 去重(实测同图重复嵌入曾占文件 26.2%)+ 大图降采样(PNG 线稿 → 灰度 JPEG q80)。
  • 禁止"母版+拆分"双份输出:多科同批也只写各科源片段 + 共享 base.* 拼装(历史母版 255KB 内容 100% 重复进单科)。
  • 教案单一真源 working/lesson.md:docx 流水线、课件、作业三处共用,禁止流水线内重复读写。
  • 测试骨架参数化沉淀:working/smoke.js / smoke_homework.js 传参复用,不每次重写。

v1.0.1(2026-09-10)

  • 产物归集优化:新增「成品/」唯一交付目录——单节课的教案、课件、作业三件同放一个文件夹;多课次/多学科同批时每课一夹(夹名 学科·课题)。
  • 成品统一命名 01-教案 / 02-课件 / 03-作业 + 课题,数字前缀保证排序;stage3/courseware/homework 降级为流水线中间件,交付只从成品目录出。
  • 交付清单明确用途指向(教案=教研自留,课件=课堂投影,作业=发学生)。

v1.0.0(2026-09-10)

首个公开发布版本。

能力

  • 三件套编排:教案 DOCX + 课堂互动课件(单文件 HTML)+ 可选防刷题作业(单文件 HTML),一次对话全链路交付。
  • 双输入模式:主题直出(学科+年级+知识点/教材课节,教材口径自动检索核对)与上传底稿(docx/pptx/html 解析,标准库零依赖,含图片提取与正文锚点映射)。
  • 可选参数:年级与教材版本开跑前选择确认;是否生成作业可选。
  • 课件:零依赖单文件、16:9 统一舞台、封面/结束页、教案批注内嵌、学科交互组件库(翻卡/配对/倒计时/节拍器/语音合成/Web Audio 音效/参数化 SVG 演示)、环节跳转、放映模式、打印样式。
  • 防刷题作业:变式池随机抽题、seed 派生确定性选项乱序、判据双答、提交前零判分、行为留痕(用时/切屏/改答/换题)、localStorage 草稿自动保存、HW1 提交码 + 教师核验区、防作弊可关闭开关。
  • 多学科同批交付:按学科独立成文件;跨件一致性核对表(封面信息/环节/要点/LS_KEY/无旧学科残留)。
  • 质量门禁:jsdom 冒烟测试骨架(课件 33 断言级 / 作业 66 断言级)、node --check、明文泄漏 grep、DOCX 完整性检查。
  • 自包含分发:全部实现规范内联于单一 SKILL.md,单文件可用,不依赖外部技能。

常见问题

5 问
答案由本站依据条目字段整理
教学三尺堂怎么安装?

在支持 Skills 的客户端里执行:skillhub install user_0ed12131/teaching-trio。安装方式为未标注。装完刷新技能列表或重开客户端。

教学三尺堂支持哪些客户端?

资料没有标注宿主客户端,但只要客户端支持 Skills(Claude、Codex、Cursor 等),一般都能加载。

教学三尺堂权限高吗,安全吗?

权限级别为未标注权限。安装前先看它会读取或写入哪些内容。

教学三尺堂收费吗?

本站不代收费用,也没有标注具体价格。是否收费取决于技能本身和所用的模型或客户端,正式使用前按作者说明确认。

教学三尺堂用什么许可证?

许可证标注为 未说明(许可证不明确)。商用或二次分发前请到仓库确认条款原文。

热门专题

按场景挑技能
全部专题 →

技能内容以作者仓库为准;分类、权限级别与许可证状态的中文说明为中文整理,最近核验 未标注。