数学试卷转PPT

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

把小学数学试卷做成课堂讲评 PPT(可直接投影放映)。当用户给出试卷(PDF、拍照、Word、图片,可附参考答案)并说"做成讲评课件/试卷讲评/逐题讲评/把这套卷子做成幻灯片/讲评PPT"时使用。**一次交付、全程不提问、不出样张**:拿着试卷和答案一路做到成品,中途不停下等确认,所有待定项走默认值并记入 decisions.md。内含完整流水线:素材归档 → 逐题独立验算 → 逐页 SVG 制图(一律经 ppt-master 输出 pptx)→ 脚本预检 → PowerPoint 渲染目检 → 交付体检;锁定版式(微软雅黑、≥24pt、无灰字、白底藏蓝朱红、一页不过载);附技术坑表与"通用 vs 单卷"分界(换卷必须重判,不得外推)。

一句话选型结论

按资料字段整理

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

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

安装

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

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

  2. 2
    拿到技能文件

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

  3. 3
    刷新技能列表

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

  4. 4
    验证是否生效

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

技能档案

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

典型使用场景

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

按水平把知识点讲清楚。

出练习题

按章节生成练习与答案。

制定学习计划

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

选择建议

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

值得选的地方

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

先想清楚的地方

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

更适合

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

不太适合

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

同类对比

6 个同类
同分类里挑最接近的几条,字段以各自详情页为准
技能权限级别安装方式累计安装宿主客户端安装命令
数学试卷转PPT当前 未标注权限 未标注 未标注 未标注 有
食谱创建课堂课程 未标注权限 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 全文

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

试卷讲评 PPT

目标不是"排版好看",而是题目一字不错、答案经过独立验算、图形与卷面几何一致、投影上看得清。任何一条不达标,这节课就会在讲台上卡住。

> 本文件是执行主线,读完即可开工。动手前先 python "$MX/scaffold.py" <项目> 铺开 work/gen/——排版库与五类图形在 assets/,不要在项目里重写一遍(脚本见 §8)。references/figure-antipatterns.md(已画错的图案案例)在做风车/月牙/花瓣/音符/树这类图案前必读;references/post-edit.md 只在交付后用户挑页要改时读。

0 一次过清单(动手前读一遍,交付前对一遍)

整套技能记的是"被当面指出过的每一处"。但返工的成因分两类,判据不同:错由 §1 铁律和 §9 闸门兜住,不满意只由下面七条兜住。历史上真正反复的,多数是后者。

# 用户看到的 判据 落在哪
1 题目/答案有没有错 独立验算,不采信任何现成答案 §5.1、S2
2 答案一眼能不能找到 朱红加粗;填空写进括号;计算写等号后 §3「答案版式」
3 简单题有没有废话 一步算式的页不写解析,只留答案+一行易错 §2.2、H3
4 图跟卷面像不像、线全不全 S7.2 十一项+figcmp --make 逐张看+figoverlay 叠合 S7.0–S7.3
5 版面空不空、挤不挤 layout_eye.py(§9 第 12 步);密度按 §3.1 的表定 §3.1
6 话是不是数学老师说的 旋转中心/方向/角度;指代用字母 §2.2
7 门面页有没有被自己加戏 封面照 §3 定稿;删一行字≠要求重设计 §2.2

第 5 条是唯一没有"对错"、只有"好看不好看"的一条,也是过去唯一完全靠人眼发现的——现在由脚本量。其余六条的细则都在对应章节,这里只做索引,不重复。

1 八条铁律(违反即返工)

  1. 必须用 ppt-master 出 pptx。不用 python-pptx 手拼页面,不用 HTML/LibreOffice 转 pptx。本技能只管"写什么、画什么、怎么验",落版一律交给 ppt-master。
  2. 每题答案独立验算:不采信用户给的答案,也不采信试卷自带参考答案;先自己算,再比对,差异单列。
  3. 图形先定图源,再逐项比对(S7.0 三级优先:能裁切就不重画;S7.2 11 项:构成/朝向/标注归属/内部线条/阴影形状/比例/结构拓扑/书写体例/关键点量化/外轮廓凹凸(用量不用眼)/单元手性),不是"算对数就算对";画完按 S7.3 把题设代回,再用 figcmp.py 把原图与成图并排看一遍。
  4. 虚线只能用 stroke-dasharray 的 4 4/6 3/2 2/8 4/8 4 2 4,其余值会生成 custDash,在 WorkBuddy/网页预览里被画成实线。
  5. 一页只讲一个屏:图形面积、填空、选择题一页 2 小题;长题干应用题一页 1 题。
  6. 分清"通用"与"单卷":§6.1 的通用水准不许再犯;§6.2 是单卷结论,换卷必须重判,不得当通用禁令外推。
  7. 一次做完,全程不提问:拿到试卷(+答案)就一路做到交付。不得用提问工具,不得中途停下等确认;所有待定项按 §2 默认值处理,判断记进 work/decisions.md,交付时一并说明。停下来问 = 任务失败。
  8. 满分与附加题是两个数,不许合并:卷面写「总计 110☆」时,110 是得分合计,不等于满分。正卷满分=把各大题分值框相加(示例:27+25+15+21+12=100),余下的(如第六大题 10☆)才是附加题。封面写「满分 100 分 附加题 10 分」,不许写「满分 110」「总计 110☆」。宁可漏写合计,也不许把附加分算进总分——投影上全班都会看到。content_lint.py 的 H4 兜底。

1.1 开工前六问(每个都有命令,答完再动笔)

§7 的坑表是"事后查",这六条是"事前过"。六条里任何一条答不上来就停手去量——这一整套返工,八成出在这六条上。

# 问什么 怎么答 答错的下场
1 每张图的外轮廓是凸还是有凹口、内部分成几块、中心放射几条线 grid_probe.py 页图 --rect … --outline --center cx,cy 得 (solid, fill, 块数, 线数),把原卷数值抄进 figures.json 的 topology 风车画成"正方形+对角线":四个数全对不上(0.72/0.65/8/8 vs 1.00/0.99/4/4),字母位置却全对,于是"答案对、图全错"
2 这道题的对称轴可能有几个方向 竖轴、横轴、两条 45° 对角线逐个试,用题干给的数量当校验器 题干说"再涂 2 格",只试竖轴只差 1 格,于是误判成"题干印错"
3 放射图案的扇区怎么编号 grid_probe.py --polar cx,cy 直出 k(22.5°+45k),别用"上/右上/右"读数 k=3 被读成"左",整套序列题答案偏一格
4 方格纸几行几列、步长多少、哪几格有填充 grid_probe.py --rect …(先看"是否等距") 行列数错一位,整张图平移一格
5 正卷满分是多少、附加题几分 把各大题分值框相加到 100 划界,余下为附加 封面写"总计 110☆",被用户当面指出两次
6 一共多少页、每题占几页 先排 PAGES 再写页面函数,中途拆页要同步三处(design_spec / spec_lock / build.py) 拆页后页数变了,no-answer-pages.txt 的豁免跑到别的页

六问的答案写进 work/decisions.md(数量类写 paper-items.md),交付时一并说明。这条不是走流程——是这六件事各错过一次。

2 自主运行契约:不问,直接做完

输入:试卷(PDF/图片/Word,可多页)+ 参考答案(可选,图片或文字)。
输出:output/《卷名》讲评(全卷N页).pptx + 逐页 PNG + 总览 PNG + work/ 下的核查记录。
过程:一条路走到底。中途只在进度里播报"做到第几页",不征求同意。

待定项 默认值(照用,不要问)
场景 课堂投影讲评,解析要能"站在讲台前念得出来"
幅面配色 16:9/纯白底/藏蓝 #1F3864 + 朱红 #C0392B + 湖蓝 #2E75B6
动画/底色块/教师备注 全部不要
封面/过渡页/页码/右上角板块名 封面默认要(§3 已定稿版式,信息带按 §1 第 8 条写满分+附加题);过渡页、页码、右上角板块名不要
交付形态 pptx + 逐页 PNG(110 DPI)+ 总览 PNG;pptx 另复制一份到桌面
文件名 《卷名》讲评(全卷N页).pptx,N = 实际页数
卷名 从文件名或卷面大标题提取,压成「年级册 + 单元/卷型」,如 五上第三单元、六上期末。去掉「26秋」「扫描件」「最终版」这类噪声
产出根目录 当前工作区根目录(cwd)。所有 projects/ output/ work/ _inbox/ 都在它下面,不要在桌面堆中间文件
答案 自己算一遍;给的答案只作对照,冲突以验算为准,差异单列
满分 正卷一律 100:把各大题分值框相加,凑满 100 的那些大题是正卷,余下的是附加题。封面写「满分 100 分 附加题 N 分」,不许出现「满分 110」「总计 110☆」(§1 第 8 条)
分页 图形面积/填空/选择一页 2 小题;长题干应用题一页 1 题;解析+易错渲染超过约 8 行就拆页(按"题干行数+答案 1 行+解析行数 × 42px ≤ 可用高度"核算)
页数 由分页规则算出来,不为凑整而合并或拆分
样张 不做。照 §3 固定规格直接展开全卷;只有用户当次明说「先出 2 页样张」才做验收版
图形 能确定的自制矢量;实物图裁切;不确定的简化,不猜

唯一允许停下的情形:输入根本读不出来(不是试卷、整页全黑、文件损坏)。只有这时才说明原因并索要文件;其余一律自己解决。

2.1 这些情况一律自决,不要问

情形 处理 记在哪
没给答案 自己全做一遍 answer-audit.md 注明"无参考答案,全部自算"
答案与验算不一致 以验算为准;差异表列出"卷面答案/验算值/判断" answer-audit.md
题目本身有毛病(缺印字母、句式矛盾、条件冲突) 先穷尽常规解法再下这个判断:对称轴把四个方向试完、两种读法都读一遍、单位口径也换着验一次;确认是卷面问题后按原样呈现,不擅自补也不删,解析里一句注明 answer-audit.md
图形看不清 先提 DPI(600–900)→ 找答案照片 → 跑 trace_figure.py;仍不确定就简化到能确定的骨架,去掉装饰线 figure-audit.md 写"简化及理由"
文本溢出 三级:精简措辞 → 拆行 → 拆页。永不缩字号(30px 就破 24pt 底线) 不必记
质检报错 读报错原文 → 改 → 重跑。同一类错误 5 轮不过,降级去掉该元素(去装饰线/拆页)并记录 decisions.md
几何约束互相冲突(格点 vs 比例) 保"顶点在格点",允许微调图形尺寸 figure-audit.md
版式没指定 按 §3 与 S5.1 四种骨架选最接近的 不必记

止损线:同一页连续改到第 3 轮仍未通过,停止微调,换做法(整图重画/拆页/去掉该元素),并在 decisions.md 记一笔。在同一版式上打补丁,第四轮通常还是不对——本次 p27 太阳翼、p31 解析都是第 3 轮换做法才通过。

work/decisions.md 只记两类:改变了卷面事实的决定(简化了哪张图、题目哪里存疑、答案怎么定的)和触发了降级的决定(哪页拆了、哪个元素去掉了)。格式一行一条:页码 | 事项 | 做了什么 | 为什么。

分值口径(最容易被"照抄卷面"带错的一条):正卷满分一律 100。卷面印的「总计 110☆」是得分合计,不是满分;☆ 是分值单位,不是"附加"的意思。算法固定三步:
① 抄下每个大题标题里的分值框(一、数字加油岛(27☆)…);② 按顺序累加,加到 100 为止,这些大题是正卷;③ 剩下的大题就是附加题,分值相加得 N。本卷 27+25+15+21+12=100,第六大题 10☆ 为附加题 → 封面写「满分 100 分 附加题 10 分」。
课件里不写"满分 110",也不按含附加分的总分排序。这条不必跟用户核对,直接照用;用户已当面纠正过两次"把附加题计入总分",content_lint.py 的 H4 会拦。

兜底(别硬凑 100):全部大题相加正好 100 → 本卷没有附加题,封面只写「满分 100 分」+建议时间;相加不足 100(如 95)→ 以 95 为满分,封面写「满分 95 分」,并在 decisions.md 记一笔"卷面标称合计与各大题分值不符";只有相加超过 100 时才拆出附加题。拆不出来又对不上,按卷面写的合计当满分,同样记一笔——不许编一个附加分去凑整。

2.2 全局默认约定(这些问过一次,别再问第二遍)

下面每一条都是已经被用户当面纠正过的,属于"做之前就该定好"的口径。照用,不写进 decisions.md。

事项 默认做法 教训来源
分值口径 满分 ≠ 卷面合计。把各大题分值框累加到 100,凑满的是正卷,余下的是附加题;封面只写「满分 100 分 附加题 N 分」。照抄卷面「总计 110☆」就是错——110 是得分合计 用户两次纠正"怎么总是把附加题计入总分";其中一次是我自检时拿卷面字面覆盖了本来写对的封面
页眉文字 只留编号,不加短标题 用户要求删掉「二、3 比大小」的后半截
纯计算题的解析 口算(直接写出得数)、竖式计算这类「一步就算完」的题,不写解析——答案就在等号后面,解析只是把算式再念一遍;要提醒只写一行「易错」。简算、脱式不在此列,它们的解析讲的是运算律,照写。content_lint.py 的 H3 只认一步算式 用户要求删掉第 3、4 页下方的解析,并补一句「太简单的才不用写」
数学术语 用教材规范说法,不用口语描述:旋转中心/旋转方向(顺时针・逆时针)/旋转角度、对应点/对应边/旋转角。方法条也照此写,写"盯住一条边,看它绕旋转中心转过多少度、与哪条边重合",不写"绕哪个点、往哪个方向、转多少度" 第 8 页方法条被要求"数学化一点"
虚实线 先发生的状态用虚线,最终状态用实线;原图实线加粗。旋转/平移/翻折都按"步骤顺序"定,不按"哪个是答案"定 p22 第一版把旋转画实线、平移画虚线,被要求对调
拼摆/切割/移补图的画法 横排优先,右侧(或下侧)剩余区域再竖排;画法与解析算式的顺序必须一一对应 p20 先画成整块示意,被要求把 14 个小三角形全画出来
图形配色 照卷面:卷面空白就画空白(#FFFFFF),卷面有浅填充才填,卷面用斜线阴影就用斜线。不为了"好看"自行加深或改色。解析需要靠颜色区分时,只给"新增/待求"那一块加浅填充(#DCE8F5),其余保持卷面原样 p27 横梁被画成深色,用户要求改回空白
简化尺度 只减装饰细节(阴影线密度、纹理),不减结构:几个构件、谁连着谁、朝哪个方向,一个都不能走样 p27 把水平横梁画成了竖向缝隙
指代图形要素 用字母(AB、CD、△ADE),不用"底边""上边""左边"这类方位词——换一张图就有歧义 p31 写"到底边的距离",用户回问"底边是哪条边"
图形图源 卷面有图就不许凭印象重画:优先高 DPI 裁切,其次描点重画,最后才按题面补画;每张图登记进 work/figures.json,出图后用 figcmp.py --make 并排看 p27 太阳翼凭印象画成 2×2、p21 线段方向画反、p22 旋转顶点画反,都是"没对着原图"
一题多解 只留一条主路径,取教材通法;不并列"解法二" §3
门面页改动 用户删掉某一行字,是在做减法,不等于要求重设计。 封面/结构页先按"最小改动"走(删掉、挪位置、调间距),确要动结构(加数据卡、换版式、新增副标题或页脚)就一次只上一项,并在交付时说明可退回 用户删了封面两行文字,我改出三卡数据版,被判"改的不满意,撤销",四次来回才回到原样

这张表是防返工的第一道闸:交付后用户若又纠正了某条"本来就该定好"的口径(不是内容错、也不是技术错,而是约定没对齐),回来补一行,写清做法与教训来源。表里的每一条都是这么攒出来的。

3 固定规格(= 已交付课件的实际样式,换卷照样式、不换页数)

templates/spec_lock.example.md、templates/design_spec.example.md 就是从这套规格抽出来的,颜色/字号/版式键值不要改;换卷只改卷名、页数、页清单。

项 要求
字体 全篇 Microsoft YaHei(含数字、单位、字母)。在 SVG 根节点写 font-family,不要逐元素写
字号 任何文字 ≥ 24pt。32px = 24pt、36px = 27pt、48px = 36pt(1px = 0.75pt)。只用四档:32 正文/36 强调/40 答案/48 页眉(封面 64 单列),不要 34 这类夹在中间的档位——差 2px 分不出层级,只显乱。图形内标注同样 ≥24pt,放不下就外移,不许缩
颜色 不允许灰色文字。正文 #1A1A1A,次要信息藏蓝,强调朱红。朱红只给三类:「答案:」后的结论、「易错:」前缀、图形里表示新增量的结论性标注
图形内文字 一律藏蓝,不得标红——标红会被当成重点
版式 纯白底;不加卡片、底色块、阴影、边框;页眉仅一条 2px 结构线(#9FB6CE,投影/打印不糊)
页眉 题干页只写编号:五、2。一题占两页写 一、3(1)(2)/一、3(3)(括号数=该页画的第几幅图);两题共用一页写 二、3 二、4。不加任何文字标题(原因见 §2.2)。无过渡页、无右上角板块名、无页码
前置页 默认只放 1 页封面。结构/难度/用时这三页仅在用户明确要求、或跨册综合卷确实需要导航时再加——用户删过封面上的说明性文字,说明他不喜欢多余的门面页。放的话:封面(考试时间/满分+附加题:按 §2 三步算出来,不许照抄卷面的「总计 110☆」/页数)、试卷结构(题型·题量·分值·占比)、难度层次(分档+题号+卡点)、用时分配。根节点写 data-deck-front="1",页眉写板块名或整页不设页眉;content_lint.py 凭这个属性跳过 H1,其余检查照跑(H4 专门查封面分值)
续页 同一小题跨页时,续页标题与首页完全相同,不加「(续)」
与 design_spec 的分工 design_spec 的 #### Slide NN - … 是文档目录,可以带描述(一、1 平行四边形的面积);- **Title**: 是页面上真正显示的字,只能写编号。两者别混
每页结构 题干 → 图形 → 答案(朱红加粗,前置"答案:")→ 解析(2–5 步)→ 易错(≤20 字)
答案版式 判断/选择/问答用独立「答案:」行;填空、简便计算不必单起一行——填空把答案朱红加粗写进括号((平方千米)),计算把结果写在算式末尾(= 405),视觉上要能一眼找到
解析 只给一条主路径。不要并列"解法二",五年级学生会在两种方法之间卡住
图上装饰 不加对勾 ✓、不加与解题无关的"验算"标记

封面版式(已定稿,换卷照抄):学年 32 号 #1A1A1A → 标题 64 号藏蓝加粗 → 结构线
(左段 4px 藏蓝、右端落在标题末字中心,右段 1.5px #9FB6CE 拉到底)→ 浅蓝信息带
1168×100,内文 40 号藏蓝加粗居中,写三件事:「满分 100 分 附加题 N 分 建议 90 分钟」。
信息带里不许出现「总计 110☆」(§1 第 8 条);本卷实测 40 号下这段文案宽 809px,1168 内居中富余 180px。
不设副标题、不设页脚——用户明确删过「全卷讲评」与「5 大题 46 小题|逐题讲评…」两行,别再自动加回去。
结构线长度不要写死坐标,按 56 + tw(标题, 64) - tw(末字, 64)/2 算,改标题才不会错位。
plain(x, y, fs, lh, text) 里第 3 个参数才是字号、第 4 个是行高——把行高当字号改(写成 plain(640, 534, F3, 52, …))不报错但会乱行距。

3.1 版面密度:这一页有多少内容,就用哪一档

字号不是"挑一个看着合适",是由这一页的字数算出来的。同一档字号,六行字和十三行字投影出来的观感差一倍:前者空,后者挤。所以先数行数,再对表:

每页内容量(题干行+答案 1+解析行) 典型页 题干 答案 解析 qa() 怎么传
≤ 6 行、且无图 短应用题、判断题、单问填空 36 40 32 stem_fs=36, fill_to=660
7–10 行 一题一问、两问小题 32 40 32 fill_to=660
11–13 行 长题干、解析三到四步 32 40 32 不传 fill_to(本来就满)
纯计算(口算/竖式) 一、1、一、2 40–48 — 不写解析 见 §2.2,整页铺开

三条硬规则:

  1. 先数行数再排版。nlines() 给的数就是行数,别用"看着差不多"估;估错的代价是整页重排。
  2. fill_to=660 只解决"重心偏上",不解决"整页没东西"。它把多余空白均摊到"题干→答案""答案→解析"和解析段间,且逐项封顶(40/32/24),所以行距不会被拉散。若加完仍偏空,只能升字号或补图。
  3. 一页只有六行字、又确实没有图可补时,走"升一档+fill_to"这一档就够,不要为了填满去加装饰线、色块、方框——那是把空页换成乱页。

> 判据来源:拿 33 页已交付课件标定,layout_eye.py 的阈值与上面这张表同源。改表之前先跑一次 layout_eye.py,别凭印象调。

4 流水线

路径约定(下文 $PM / $MX / $TK / $PY 分别指四处,不要混用):

PM="$HOME/.workbuddy/skills/ppt-master/skills/ppt-master/scripts"     # ppt-master(出 pptx)
MX="$HOME/.workbuddy/skills/ppt-mathexam/scripts"                     # 本技能(校验/预览)
TK="$HOME/.workbuddy/skills/ppt-mathexam/templates"                   # 本技能(规格模板)
PY="$HOME/.workbuddy/binaries/python/envs/default/Scripts/python.exe" # 受管解释器

用 $HOME 而不是写死 C:/Users/<用户名>:换机器只要 .workbuddy 在用户目录下就能跑。若在 PowerShell 里执行,把 $HOME 换成 $env:USERPROFILE。

S1 之前必跑依赖自检(新机器首次使用必跑;本机环境没变过可跳):

"$PY" "$MX/dep_check.py"

dep_check.py 核对 ppt-master 四个入口脚本、与 env_lock.json 的版本锁定、以及关键 Python 包(pymupdf / Pillow / python-pptx),缺什么当场给安装指引。铁律 1 依赖 ppt-master——没装就装好再进 S1,不要做到交付链末端才发现。ship.py 首步的环境核对是第二道闸,两处判据一致。

S1 素材归档与页码映射

  • 先解决页码错位:用户给的 PDF 常带封面、导读、答案页,正文第 1 页往往不是 PDF 第 1 页。做法:把 PDF 每页渲染成 150 DPI 缩略图(page.get_pixmap(dpi=150)),肉眼找到"试卷正文第 1 页",记下 PDF页 = 正文页 + 偏移,写进 work/paper-items.md 抬头。偏移每卷不同,必须重数;某卷实测是 PDF 9–12 页 = 正文 1–4 页,那只是那一卷的偏移 +8,不要照抄。
  • 正文页按 300–1100 DPI 重渲染到 work/pages/;扫描版每页是位图,get_drawings() 返回 0,拿不到矢量坐标,一切靠看图 + 图像分析。
  • 先判扫描版还是矢量版:len(page.get_drawings()) 为 0 就是位图。若给的是 Word 导出的原生 PDF,get_drawings() 能直接拿到每条线段的端点坐标——那种情况照坐标画图,精度最高,不要退回"看图猜"。
  • 要裁某道题的图,先盖坐标网再读坐标,不要凭感觉试 Rect(曾经为一张图试了五轮):
    bash python "$MX/page_grid.py" 试卷.pdf 11 -o work/grid11.png --dpi 120 # 1 基页码
    图四周有 pt 刻度,直接读出 x0,y0,x1,y1,再交给 crop_figure.py --rect。
  • 桌面散落的 Markdown/页面图文件夹(PDF 转换残留)统一收进 _inbox/,不要留在桌面。

S2 事实核查(独立子代理,不可省)

派 general-purpose 子代理,任务是"把试卷转成结构化题目清单 + 独立验算",产出:

  • work/paper-items.md:逐题结构化。几何图必须记录图形种类、每条边的标注值及其所在位置、角度、方格行列数;抬头写 PDF 页码映射,以及分值账——各大题分值框逐个抄下、累加到 100 划出正卷、余下的大题标为附加题(§2 三步)。这份账是封面信息的唯一来源,别到做封面时再凭印象填。
  • work/answer-audit.md:与参考答案的差异、题目本身存疑处(标注冲突、漏印字母、句式矛盾)。

不采信任何现成答案,自己算完再比对。

S3 核查结论落文件(播报一句就往下走,不停)

把三件事写进 work/answer-audit.md:总题数、答案差异(题号/卷面答案/验算值)、题目本身存疑处。同时在进度里一句话带过,然后直接进 S4,不征求同意、不等回复。这些内容在交付回复里再完整讲一遍。

若发现答案错了,不要为了对齐答案去改自己的验算——以验算为准,差异留在 answer-audit.md,交付时说明。

S4 规格锁定(用模板,别手填 [fill])

python "$PM/project_manager.py" init <卷名> --format ppt169 --dir projects --quick-generate
D=projects/<卷名>_ppt169_<YYYYMMDD>
python "$PM/project_manager.py" scaffold-spec "$D"
python "$PM/project_manager.py" scaffold-lock "$D"
cp "$TK/design_spec.example.md" "$D/design_spec.md"   # 覆盖骨架
cp "$TK/spec_lock.example.md"   "$D/spec_lock.md"
python "$PM/project_manager.py" validate "$D"                      # rc=0

为什么用模板:scaffold 出来的骨架有 30 多个 [fill],逐个填既慢又容易写错枚举(Status、Crop Policy、页面字段都会报错)。templates/ 下两份是已经通过 validate + checker 的成品,全套版式(白底藏蓝、字号、禁止项)都预置好了。

覆盖后只需改三处:
1. design_spec §I 的 Project Name/Page Count/Created Date——Page Count 必须等于 §IX 的 #### Slide 块数,检查器是逐块数的,多一块少一块都报 §I Page Count is N but the content outline has M Slide block(s) 并 blocking(示例是"2 页 2 块"的自洽占位,改页数时同步增删块);
2. design_spec §IX:照示例的五个字段(Audience move/Relationships/Title/Content/Answer)一页一块,替换掉示例的两块;
3. spec_lock 的 ## page_rhythm:- P01: dense 一直排到 P<NN>,与页数一致。

  • init 会自动补后缀:目录名 = <项目名>_ppt169_<YYYYMMDD>;--quick-generate 才建 svg_output/。
  • 有裁切图就在 spec_lock 的 ## images 加 - p<页码>: images/x.png | source=slice | crop=no-crop,并在 design_spec §VIII 补一行。
  • spec_lock.md 的 page_rhythm 只接受 anchor / dense / breathing(逐页一行 - P01: dense)。写成 medium 这类"看着合理"的词,validate 会报 illegal value 'medium' 并退 1。讲评课件每页信息量接近,全填 dense 即可,不用编节奏。
  • spec_lock.md 的 ## typography 必须声明实际用到的每个字号(如 36/27/24),否则检查器报 undeclared font-size。
  • design_spec.md 的 ## IX. Content Outline 每页一块。字段照模板示例的五项写:Audience move/Relationships/Title/Content/Answer(已验证通过)。scaffold 骨架给的是另一套六字段(Composition/Core message/Mathematical content),checker 也接受,但一份文件里只用一套,别混着写。
  • 图片资源行:Crop Policy 只能 adaptive/no-crop;Acquire Via 只能 ai/web/user/placeholder/slice;Status 的枚举以 $PM/../references/svg-image-embedding.md(ppt-master 的,不在本技能里) 为准(slice → generated,user → existing),写错报 invalid Status 'xxx'。design_spec 的 ## VIII 与 spec_lock 的 ## images 两处都要登。

S5 逐页制图(SVG 1280×720)

  • 画布 viewBox="0 0 1280 720",内容区 x 56–1224、y 108–712,页眉分隔线 y=100。
  • 一个 SVG 一页,文件名 01_短名.svg … NN_短名.svg,序号即页序。
  • 每个逻辑块一个 <g id="..." data-pptx-bounds="x y w h">,bounds 必须覆盖块内所有元素的真实范围(含文字下沿);模块 bounds 之间不得重叠(容差 1px)。
  • 左右分栏时,左栏 bounds 右边界要收窄到文字实际右边界,不要横跨整页压住右图。
  • 多行文字每行一个 <text>(lib.flow() 就是这么出的,两套卷 54 页已通过全部检查器);同一行内要混排颜色时才用 <tspan>。
    > 旧版本这里写的是"不要每行一个 <text>",与现在的检查器不符——实测每行一个 <text> 不报错,反而便于逐行定位越界。
  • <line> 带 data-pptx-role="decoration" 时必须同时有 id。

先铺骨架,再从第 1 分钟开始画(排版库和五类图形已随技能提供,不要再重写一遍):

python "$MX/scaffold.py" <项目>        # 铺 work/gen/{lib,figures,pages,build}.py
python <项目>/work/gen/build.py        # 出 svg + work/page-index.md

assets/lib.py 是冻结件:宽度模型、换行禁则、block() 的 bounds、qa() 的纵向推进都已验证过两套卷 54 页。
不要改它的内部实现——改一次 _flow 的换行规则,全册都会重排,必须整册复检。要加能力,写在 figures.py 或本项目的 pages_*.py。

assets/figures.py 的五类图形(顶点一律用图形自身单位给,不写像素):

类 适用 关键参数 固化的教训
GridPaper(x,y,cols,rows,cell) 方格纸、旋转/平移、数格题 .P(c,r) .poly([(c,r)…]) .rot(pts,center,k,cw) .text(c,r,s) 线段画反、顶点不在格点
VerticalMul(x,y,fs,ncol) 竖式(逐位分写) .put(row,{col:字}) .rule(row) .arrow(row,to_col) 连写、数位错位、4 对不上 1
Tiling(x,y,sx) 长方形里拼摆小图形 .outer(w,h) .piece(x0,y0,w,h) 只画横排不穷尽、旁条高算错
StairPath(x,y,w,h,path_w,scale) 等宽阶梯小路 + 平移拼接 .original(steps,…) .translated(y,…) 白路无边糊在浅底上
BarChart(x,y,w,h,ymax,ystep) 复式条形统计图 .svg([(标签1,标签2,值1,值2)…]) 缺刻度、柱顶无值、读数靠猜

生成器结构约定(决定返工时的定位成本):

  • 一页一个函数,函数名与 SVG 文件名对应(p22() → 22_caozuo_2_xuanzhuan.svg)。
  • 题干/答案/解析就写在页面函数里(qa(...) 的第一个参数),图形调用紧随其后。文字与图形放在同一页的代码里,改一页只翻一处;不要把文字抽到全局表——qa() 的换行位置依赖 maxw,抽出去还得再传一遍参数。
  • build.py 自动输出 work/page-index.md:页码 | 标题 | SVG 文件 | 函数名。改某页先读这张表,不要 grep 全项目。

S5.1 四种版式骨架(实测坐标,直接套改)

版式 适用 骨架(x y w h)
A 全宽四题 简便计算、比大小等纯文字块;题型对应:计算题(口算/竖式/脱式) 四块同宽:56 140 1168 118,y 每 +128 → 268 / 396 / 524
B 上文下图 方格纸、需要大图的题;题型对应:操作题(作图/画对称/平移旋转)、统计图题 stem 56 112 1168 56 → fig 50 172 1146 292 → options 56 468 1168 44 → answer 56 518 1168 56 → explain 56 578 1168 134
C 左文右图 有图的选择/填空(最常见) stem 全宽 56 112 1168 190;图 720 310 490 320(或 745 295 465 330);左栏 answer 56 320 660 60 + explain 56 390 660 326
D 上下两题 图形面积,每题自带图;题型对应:解决问题(应用题)里带图的两小问 两块各 56 118 1168 282 与 56 404 1168 296,题干在左、图在该块内右侧

排版冲突时优先保"图不压字、字不出界",宁可把解析拆到下一页,也不要把 24pt 压成 20pt。

S6 文本宽度预检(省 80% 返工)

估算规则(按当前字号):

全角(汉字、中文标点):font-size × 1.06
半角(数字、字母、运算符):font-size × 0.62
空格:font-size × 0.35

32px 正文一行超过 1168px 必溢出正文区;超出所属模块 bounds 会被判错。先跑脚本再导出:

python "$MX/textfit.py" svg_output/*.svg      # 退出码 1 = 有溢出

超了先精简排版(去运算符两侧空格、(  )→( )),仍超就拆行;不要缩字号,30px 就破了 24pt 底线。

S7 图形制作

  • 几何图自制矢量:先定"1 单位 = n px",所有点按比例落位,画完反查关键边像素长度是否等于标注值。
  • 实物图(树叶、光伏板、器材)从卷面裁切,<image href="../images/x.png">,登记进 ## VIII 与 spec_lock。裁切命令(--rect 的坐标由 page_grid.py 读出):
    bash python "$MX/crop_figure.py" 试卷.pdf 11 --rect 365,192,532,292 -o images/fig6.png --dpi 600
    实物图 300 DPI 够;线条图看结构用 600–900 DPI。裁完 ViewImage 确认区域,别把相邻题裁进来。
  • 标注放图形外侧;放不下就引线外移,别让文字压线。
  • 直角符号画在真正的直角处,符号边长 16px。
  • 辅助线用 <line stroke-dasharray="6 3" stroke="#2E75B6">:分割线、作高、延长线都要画出来,让"底和高是哪条"直接可见。
  • 阴影用 45° 平行细线或 #DCE8F5 浅填充,全篇统一。
  • 不要用 AI 生图代替画图:几何图必须自己落点,AI 生成的图边长、角度都不可控,对不上标注。只有"卷面实物图裁不出、又被涂改"时,才作为最后手段,且必须在 design_spec 里登 Acquire Via: ai。
  • 阴影线用等值线 x + y = k 生成,两端点必须同 k,算完 assert 一次;参数化写反会变成交叉扇形,这是最难看出来的错。

S7.0 先定图源(返工最多的一环)

图形出错的根因不是"不会画",而是凭印象重画、画完没跟原图并排对。所以先按优先级定图源:

级 做法 适用 代价
1 裁切 crop_figure.py 高 DPI 裁原图直接贴(<image href>) 实物照、统计图、七巧板、复杂组合图形;以及风车/月牙/花瓣/音符/树这类装饰图案——凡"重画必走形"的都走这级 与矢量线风格有别;可按亮度重着色成藏蓝(见 §7 坑表)
2 描点重画 逐点量出坐标再落笔(S7.1 四步法) 方格纸上的图形、需要在图上标答案的 慢,但可控
3 按题面补画 卷面本无图,按数字关系补 "花车队""电池板"这类纯文字描述题 无原图可比,只能靠 S7.3 验条件

每张有图的页登记一条 work/figures.json,跑 --scan 自动铺骨架,别手抄模板(templates/figures.example.json 只是字段说明)。这是硬性项:ship.py 检测到图形页却没有登记表会直接失败(只给旧项目留了 --allow-no-figures 这个口子)。字段就是在逼自己回答:原图在哪、画的是哪一级、图上有几个闭合图形、谁连着谁、标了哪些值。

"22": {
  "svg": "22_xuanze_8_cai.svg",
  "mode": "crop",
  "src": "work/png/sheet_04.png",
  "rect": [120, 300, 480, 620],
  "view": [640, 120, 620, 470],
  "labels": ["3 格", "8 4"],
  "shapes": 5,
  "topology": "外框含 4 个小矩形,横梁贯通左右",
  "note": "裁切自卷面左上,未重画"
}

填 rect 之前先出内嵌图清单:scan_figures.py 把每页位图连坐标 dump 成竖排拼图+index.md。rect 只能照这张表抄,不许凭"第几个图"记——错一格就会把「笑脸」配给「平行四边形」,而 --check 照样打 OK(它只验证据链,看不出左右不是同一题):

python "$MX/scan_figures.py" <卷面.pdf> --out work/figscan   # → work/figscan/sheet_pN.png + index.md

登记表不手抄——手抄就会想"最后一起弄",最后就没弄:

python "$MX/figcmp.py" <项目> --scan     # 检出图形页 → 写 figures.json 骨架(字段留空待填)
python "$MX/figcmp.py" <项目> --make     # → work/fig/cmp_NN.png(「原图|成图」并排)
python "$MX/figcmp.py" <项目> --check    # 缺字段、标注值找不到、对照图比 SVG 旧 → 逐条报

--scan 建完,把 src / rect / shapes / topology / labels 填上;--check 会把没填的逐条列出来,不填过不去。只登记一半也算失败(检出 14 页只登记 3 页,--check 直接报出漏了哪 11 页)——半份登记比没有更危险,因为它会打印 OK。

取景要能比出大小:view/rect 不只是裁掉多余空白,它决定两栏各自框住多大范围。带坐标系的图(方格纸、统计图、数轴)两侧一律按整张坐标纸取景——只框图形本身,两边各自缩放到等高后格子一大一小,"花占 4 格还是 5 格""柱子离轴多远"就比不出来,只剩形状可看。四瓣花那次的尺寸错正是这样漏过去的。

--make 之后必须 ViewImage 逐张看过,再说"对过了"。--check 只验证据链(原图出处、对照图是否比 SVG 新、labels 每个值是否真在 SVG 里),判不了像不像,但它能挡住"根本没看"。ship.py 在 preview 之后自动跑这一步;建了登记表就不许带病交付。

并排之后再做一次叠合。并排是"两个画面在脑子里对齐",人眼对形状敏感、对尺寸和整体偏移几乎无感——四瓣花 4 格画成 5 格,就是这样连过两轮没人看出来。figoverlay.py 把重绘按同一把尺叠回原图:格纸页按格宽比缩放(1 格对 1 格),尺寸差会变成整圈偏色;无格纸页按外框缩放,只能比形状。

python "$MX/figoverlay.py" <项目>                 # → work/fig/ov_NN.png(原卷红 / 重绘青)
python "$MX/figoverlay.py" <项目> --svg-dir 旧稿  # 同一页比新旧两版画法

判读方法:重合处发暗;一侧红、一侧青,就是那一边画偏了、画小了或少了东西。只看图形轮廓与线段——标注文字(3、6、9、12)两侧位置本来就不同,讲评页把标注摆得更开是为了投影看得清,那不是错,别拿它当证据。

它刻意不给分数——给分就要设阈值,阈值一设就得替示意图、不按比例图开例外,最后只剩一堆还得人再判一次的数字。这条路上试过两版(轮廓相关、填充 IoU),在扫描件与渲染件之间都没能稳定下来,误报远多于命中;叠合不设阈值,也就不制造假警报。

还有一层是任何检查都抓不到的:把原图读错(把四个圆的并集当成原卷的构造、把阴影边界看错)。错的不是画法而是"读图时的假设",而比对的两端——我声明要画的、我实际画出来的——同源,怎么比都自洽。治它只有一条:先在原图上量出数据,再让代码只做"把数据变成点",量出来的数写进注释(S7.1 第 3、4 步)。一、1 的花就是这么定稿的。

S7.1 还原原图的复杂图形(按序做,别凭印象重画)

  1. page.get_pixmap(dpi=600~900, clip=Rect) 重渲染目标区域。
  2. 先用文字写结构,再落笔:按"五问"写一段——外轮廓有没有凹口/几个单元/单元之间怎么接/手性朝哪/标记在哪。写不出这段话就是还没看懂,不许开始画。写完用 grid_probe.py --outline --rect … 量 solid(轮廓/凸包)和 fill(轮廓/外接矩形)自检:凸形 ≥0.95,八角星 0.7–0.85,风车 0.5–0.7,对不上就说明文字写错了。这段文字还是画完复核的对照物——看图容易"看着像"就放过,文字对不上会立刻露馅。
  3. 阴影用像素剖面定,不靠眼睛:先 np.unique 取灰度峰值,认准"填充"那一档(本案 A/B 位图是 201、四、2 是 163,不是固定的 170–230 区间),再把图形降采样成 16×16/32×32 的明暗字符图(# 线/o 填充/. 空白)。阈值猜错会得出相反结论:二、3 的 D 就因阈值选错,把 5/8 读成"接近一半",答案差点翻车。字符图还能顺手量出每条斜线的两个端点落在哪个格点,比"看着像"可靠。
  4. 方格纸/放射图案先量再画:grid_probe.py --rect … 出格线坐标与逐格灰度表,--polar cx,cy 出每个标记的扇区号 k。这张表就是后面画图的输入——格线坐标抄错一位,整张图就整体错位;扇区号读偏一格,序列题的答案会全线偏移(本案就这么错过一次)。
  5. python "$MX/trace_figure.py" <页图> x0 y0 x1 y1 提长线段:同一角度密集重复的是阴影线,角度各异的那几条才是轮廓。
  6. 用户上传的答案照片往往比扫描件清楚,优先级最高。

S7.2 逐项比对表(数值对 ≠ 图对了)

比对项 要问的问题
图形构成 原图画了几个图形?有没有第二个被漏掉("长方形 + 平行四边形叠放"只画成一个)?
朝向 斜边朝哪边倾?左右是否镜像?外框正放还是斜放?
标注归属 每个数字标在哪条边、哪个角?原图在右侧竖边的不能标到左侧
内部线条 对角线/分割线/直角符号/阴影的位置和数量对不对
阴影形状 是三角形、长方形还是平行四边形?四个角是不是直角、对边是否等长?
阴影归属与裁切 阴影夹在哪两条线之间?两条线是不是都从同一个顶点出发?外轮廓有没有把阴影裁掉一块(四、2 的右上角就不该有阴影)?按"看着像什么"直接算面积,误差能到半倍(本案 50 vs 37.5)
比例 用像素长度 ÷ 比例尺反查标注值
结构拓扑 几个构件之间谁连着谁?梁/杆是横的还是竖的?贯穿到底还是中途断开?只数"几个图形"不够,还要数"怎么接"
书写体例 竖式/脱式是逐位分写还是连写?横线伸出多长?进位、退位、箭头怎么标?这类图的"对不对"由体例决定,不由得数决定
关键点量化 把卷面上能辨认的端点量出来:起止方向、长度比例、与格线的关系。目测"大概朝右上"不算数,要量
外轮廓凹凸(图案类必查,用量不用眼) 外轮廓是凸的还是带凹口?跑 grid_probe.py --outline --center cx,cy 得四个数:solid=轮廓/凸包、fill=轮廓/外接矩形、内部封闭区域几块、放射线条数。参照值:正方形+对角线=(1.00, 0.99, 4, 4);八角星+连 8 顶点=(0.46, 0.46, 8, 8);扫描件上的风车=(0.72, 0.65, 8, 8)。原卷与成图各跑一次,四个数有一个对不上就是结构画错
单元手性(图案类必查) 直角/尖角朝外还是朝内?月牙的凹面朝哪?单元之间是分开、共边、还是只共一点?顶点数在细线图形上不可靠(同一张图能数出 8 也能数出 13),要答的是"接不接、朝哪边",不是"几个点"

S7.3 画完把题设代回去(图对了 ≠ 条件成立)

图形画好后,把题目给的每个条件逐条代回图上验算,不成立就重取点,不许改条件去迁就图:

  • 面积/周长相等的条件:把两条边代进去算,必须真的相等。
  • 点落在哪条边/哪个区域:写死坐标后回头确认没有越界。
  • 标注的数字与题设一致:图上标的每一段,都能在题干里找到出处。
  • 答案要用"画出来的图形"重算一遍:图定稿后按图上的边界重新算,与先前按题意"想当然"的结果对一遍;不一致时以图形为准,并在 work/answer-audit.md 记一条(本案四、2:想当然 50,按图 37.5)。

反面教材:某题设"△ADE 与 △CDF 面积相等",图上随手取了 F 点,算下来两个面积一个 10、一个 40,图看着像、条件全错;另一题把"三排共占 18 cm"当成了旁侧余条的高,导致摆放个数多算了一个。共同点是只验证了"图形长得像",没验证"条件真成立"。

S8 导出

改一页时按最便宜的那一档来,不要一上来就跑全链:

想确认什么 命令 上一卷 33 页实测 覆盖到哪
版面/图形看着对不对 peek.py <项目> --latest 2 0.5–1 s 只出图,不判合规
SVG 侧有没有破(宽度/文案/页眉) ship.py <项目> --svg-only 7 s 前 4 道闸门
能交了,只重出改动页预览 ship.py <项目> --pages 22,25 25 s 全 14 步
全量交付 ship.py <项目> --name "《卷名》讲评(全卷N页).pptx" 27 s 全 14 步 + 全量预览
python "$MX/peek.py" <项目> --latest 2      # 改一个像素也 0.5 秒看见,不碰 pptx
python "$MX/ship.py" <项目> --svg-only      # 改措辞时用
python "$MX/ship.py" <项目> --pages 22      # 只重出第 22 页预览,其余 PNG 不动
python "$MX/ship.py" <项目> --name "《卷名》讲评(全卷N页).pptx"   # 交付前最后一遍(已交付过的项目可省 --name)

> peek.py 用 resvg 直接把 SVG 渲成 PNG(与 PowerPoint 的差异只在字体抗锯齿,整册均差约 8/255),
> 是"自己看"的工具,不是交付证据:字号不足、标注压线、形状出界只认 ship.py 的结论。
>
> 为什么不再手敲全链:改一页也要走十三步,手敲既慢又容易漏(曾出现过"PDF 是改前的、check_labels 等于没检")。
> ship.py 把顺序与判据固化,失败停在那一步并打印具体条目,退出码 1。

只在排查单步时手敲:

python "$PM/svg_quality_checker.py" <项目> --canonical-authoring --stage final --json
python "$PM/finalize_svg.py" <项目>
python "$PM/svg_to_pptx.py" <项目> --no-notes
python "$MX/deck_check.py" "output/《卷名》讲评(全卷N页).pptx"
python "$MX/fix_dash.py" "output/《卷名》讲评(全卷N页).pptx"   # 仅当上一步报 custDash
  • 改过 SVG 就必须重跑质检再导出:svg_to_pptx 会校验 validation/svg_quality_report.json 里记的 svg_output sha256 指纹,SVG 变了而报告没重出会报 found stale 并拒绝导出(2026-10-31 升级后的 ppt-master 行为)。手工排查时别跳步;ship.py 的顺序已按此排好。
  • pptx_pdf.ps1 用 PowerPoint COM 导出。必须用 SaveAs($out, 32):ExportAsFixedFormat 在本机会静默失败。脚本只 Quit 自己创建的实例,不会关掉用户已打开的 PowerPoint。
  • 没装 PowerPoint 时(New-Object -ComObject PowerPoint.Application 报错):退到 LibreOffice soffice --headless --convert-to pdf <pptx> --outdir output;两者都没有就跳过 check_labels,在交付里写明"未做压线检测",不要卡在这里等指示。
  • LibreOffice 转出的 PDF 只能用于 check_labels(几何相交检测),不能用来出预览图。 它在个别汉字上会画错字形——实测某页行首"旋"字被渲染成两个字叠印,而 PDF 文本层的字符原点坐标完全正确,放大对比才能确认是渲染问题而非排版问题,极容易误判成"文字重叠"去改版式。预览图必须由 PowerPoint 出:要么让 make_preview.py 吃 PowerPoint 导的 PDF,要么直接用 COM 逐页 Slide.Export(path, "PNG", 1467, 825),再用 PIL 回写 dpi=(110,110)。
  • make_preview.py 同时产出逐页 PNG 与总览拼图,列数按页数自动排布(页数变了不用改代码,总览尺寸也随之变化)。
  • _check.pdf 是中间产物,交付前删掉。
  • --json 不打印到 stdout:报告落在 validation/svg_quality_report.json。stdout 末尾有一行 blocking: N hard findings; gate also requires exit 0,判据就是 blocking: 0 且退出码 0(等价于 JSON 的 summary.errors == 0);warnings 放行。
  • svg_to_pptx 的产物在 exports/,文件名带时间戳。交付要复制成正式名:output/《卷名》讲评(全卷N页).pptx。
  • 重建过一次之后,exports/ 里就有多个 pptx,此时 cp exports/*.pptx 目标 会报 target is not a directory——一律用 cp "$(ls -t ... | head -1)"。
  • POSTFLIGHT 回执形如 [POSTFLIGHT] status=passed-with-warnings quality_gate=passed slides=21 warning_categories=2。放行判据:status 是 passed 或 passed-with-warnings,且 quality_gate=passed。[POSTFLIGHT][WARNING] 那几行是提示,逐条看一眼是否合理即可;只有 status=failed 才必须改。
  • 产物是原生形状与文本框(不是整页图片),WPS/PowerPoint 里可以直接改字改色。
  • 重建会覆盖 PPTX 里的手工改动。凡在 PPTX 里改过的字,先同步回 SVG,再重建;否则下次一重建就退回旧版。

5 逐页自检(内容级,交付前逐页写结论到 work/selfcheck-full.md)

5.1 题干与答案

  1. 题干:与卷面逐字比对,数字、单位、括号、问句、标点都不能动。唯一可删的是纯过渡语("按要求做一做""请完成下面各题"这类既不带条件、也不带问句的话);删了记进 decisions.md,交付时提一句。除此之外一律照抄,觉得"读起来啰嗦"不是删的理由。
  2. 答案:重算一遍,检查单位与"约等于/精确值"。判断题(对的打√、错的打×)只写符号或卷面的「对/错」,不要写整句;解析必须点出错在哪一步——只给一个×,学生还是不知道为什么错,这页就白讲了。

5.2 图形

  1. 按 S7.2 11 项逐个比对(图形构成/朝向/标注归属/内部线条/阴影形状/比例/结构拓扑/书写体例/关键点量化/外轮廓凹凸/单元手性)。
  2. 按 S7.3 把题设代回图上,条件必须真的成立,不成立就重取点。
  3. 并排看原卷,不是看课件单图:figcmp.py --make 出「原图裁切|成图」并排图后逐张 ViewImage,--check 退 0 才算数。"只翻课件看像不像"等于没验——三处图案错误(风车、月牙、音符)都是这么漏过去的。每画完 3–5 张图就 --make 一次,别攒到最后:攒到 20 张时,人会滑着看、看完也记不住哪张没看。图案类另跑 grid_probe.py --outline 比 solid/fill——眼睛会骗人,面积比不会。

5.3 解析(返工最多的一类,逐条过)

先判断这一页要不要解析。 口算(直接写出得数)、竖式计算这类纯计算题不写解析:答案就在等号后面,解析等于把算式再念一遍,投影时还白占半页。这类页只留答案,加一行「易错」;省下的纵向空间给题目本身(字号放大一档、行距拉开)。判据:整页以一步算式为主(≥4 行、每行只有一个运算符号,且中文行 ≤3)却出现「解析:」,content_lint.py 的 H3 直接判失败;脱式(3.6×2.5+6.4×2.5=…)不算,它的解析讲的是运算律,该留。其余题型照下面四条走(第 6–9 条)。

  1. 逐步可验证:一步一行。算式脱式((35+75)×36÷2=110×36÷2=1980)是同类化简,可以连写;跨推理步骤的等式链(F 到 AB 的距离=边长-AE=BE=8)必须展开,每一步都要说出用了什么(面积相等?平行线间距离?E 在那条边上?)。判据:链上相邻两个量之间如果需要"想一想为什么相等",就不许连写。
  2. 不跨题引用:一页两题时,解析只讲本题;写进别的题的条件就是错。
  3. 指代用字母(AB、CD、△ADE),不用"底边/上边"这类方位词(§2.2)。
  4. 每步都有出处:数字只能来自题干、来自前一步、或来自图上标注,三者之外不许出现。

> content_lint.py 的 A1 会把疑似跨步的连等列出来(只列候选、不下判断,脱式会自动跳过)。

5.4 易错(三重门槛,缺一条就换一条)

  1. 真会错:学生按常规做法会不会踩这个坑?只是"与答案不同"不算。
  2. 只对该空成立:一题多空时,这句话必须对每个空都成立;只对一个空成立的,要点明是哪个空。
  3. 不引向错答:这句话读完,学生会不会反而去做错?会,就删。

> 反面教材(全是实际被指出的):「9.9 公顷正好是 99000 平方米,应填=」只是复述答案;「积缩小 100 倍,一个因数不变」只对第一空成立,第二空缩 1000 倍;「8 是斜着那条边的高,不能算 10×8」会把学生引去算 8×8。

5.5 机器项与全卷通读

  1. 文字:textfit.py 无溢出;content_lint.py HARD 0(页眉 H1/「(续)」H2/纯计算题写了解析 H3/封面分值 H4;ADVICE 项为连等 A1、方位词 A2);check_labels.py 检出 0 处压线。
  2. 合规:最小字号 ≥24pt、无灰字、无越界、无灰底卡片。
  3. 通读全卷(逐页过了还要横着看一遍):同一类图的方格/配色/标注位置是否一致;每道题该有的标注是否都在(长、宽、高、路宽、单位);题干给的、图上标的、解析算的三处数值是否一致;页眉编号是否连续、与题号对得上。
  4. 封面分值自洽(有封面就必查):把各大题分值框重新加一遍,确认「满分 100 + 附加 N = 卷面合计」。content_lint.py 的 H4 只能拦住"写错"(满分≠100、直接写合计),拦不住"算错"——加错的账只有人能发现。自检时不许拿卷面字面去覆盖已经算对的口径:卷面写「总计 110☆」是原文,不是标准答案。
  5. 版面(layout_eye.py,或看 work/layout-eye.md):HARD 必须为 0;报出的失衡页逐页处理,确有理由(整页一张大图、封面)就写进 decisions.md 一句。这一项不能靠翻总览图替代——总览缩到八列之后,"下半页空"只剩一小撮白,看着都差不多。

6 通用准则 vs 单卷特例

先分清性质,再决定要不要写进技能。 被当面指出过的问题里,只有一部分是技术缺陷(换任何卷都会犯),其余多是内容取舍,其中一些只对某一套卷子成立。把单卷结论当通用禁令写死,下一套卷子就会被带偏——这比犯错更糟。

6.1 通用水准(换任何卷都成立,违反即返工)

# 现象 根因 正确做法
1 预览里虚线变实线 dasharray 写了预设外的值(7 5、8 6)→ 生成 <a:custDash>;PowerPoint 认,网页渲染器(pptx-preview)只认 <a:prstDash> 只用 5 种合法值;deck_check.py 查 custDash,有就跑 fix_dash.py
2 填空题答案读不通 没看空后紧跟的字。"( )四边形"里塞"菱形",读成"菱形四边形" 定答案前先看空前后的字,答案要能填进去读成完整句子。方法通用,答案不通用
3 只给结论不给来路 "面积是一半""积都是 16"一笔带过,学生一问就卡住 关键结论给可复述的来路(如:四个角各剪掉底高减半的小三角形,各占 1/4,合起来正是半个梯形)。判据见 §5.3:一步一行,A=B=C 连着写必拆
4 图上多余符号 把草稿里的验算记号带进成品(解析行尾的 ✓) 交付前扫一遍装饰符(✓√★→),除题干原有外一律不留
5 图形内文字标红 想强调重点 图形内文字一律藏蓝;朱红只留三处(答案结论、易错前缀、新增量标注)
6 图形被"美化" 卷面空白处填了色、装饰线被省略、构件位置被"调正" 图形只对卷面负责:构成、朝向、拓扑、配色一律照搬。"好看"不是目标,S7.2 11 项才是判据

6.2 单卷特例(示例卷:《小数报》五上第三单元;换卷必须重判)

下面两条来自另一套卷子,留在这里是为了示范"什么样的话只能对单卷说",不是本卷结论。换卷时先问:这条是技术缺陷,还是这道题的特例?

本例做法 为什么只能这样 换卷要重判什么
四、2 第一空答"平行四边形",且不展开菱形 题干"它是( )四边形"——空后紧跟"四边形",填"菱形"读成"菱形四边形",不通。注意:本例是等腰梯形,对角线相等,其中点四边形在几何上确实是菱形,"菱形"不算错,只是这个空写不进去 若空是"它是( )"或问"为什么",菱形就是正解,必须讲;判据是空前后有没有限定词,不是"菱形不能提"
图 6 阴影画成长方形 本例长方形的一条对角线正好与平行四边形的底边重合,所以恒为"一半在内、一半在外",面积与平行四边形相等(340×130 = 308×143 = 44200) 不代表阴影都是长方形。换卷按 S7.2「阴影形状」判据重判

7 技术坑表(按踩坑频率排,越靠前越常犯)

坑 表现 处理
轮廓按"想的构造"重绘 看到花就当成四个圆的并集,画完是四瓣,原卷是八瓣 先在原图上量极径剖面(每 5° 取边界点、四象限旋转平均),能对上某个构造再用构造;对不上就按实测点重建
解析引用了图上没有的标签 写"① 的 A 点在 O 上方 4 格",可 A/B/C 属于图② 讲评文字里出现的每个字母,都要能在同一页的图上指出来;跨图形的标签一律改成"左上顶点""竖边"这类描述
对照图只框住图形本身 两边各自缩放,"占几格/离轴多远"看不出对错,只剩形状可比 方格纸、统计图按整张坐标纸取景,让两侧格子同宽
对照图左右不是同一题 笑脸配平行四边形——rect 填串了,--check 还照样打 OK 填 rect 前跑 scan_figures.py 出内嵌图清单照抄;--make 后每张先确认左右是同一道题再看像不像
阴影画错归属 阴影本该夹在两条线之间、还被轮廓裁掉一角,却画成整块填满 按 S7.1 第 3 步做像素剖面,先定"哪几块是阴影"再落笔
圆弧画反方向 想画凹弧却凸出来,两段弧一凹一凸不对称 SVG A r r 0 0 <sweep> 的 sweep 决定圆心落在哪侧:以底角为圆心、向上收的凹弧,两段都要 sweep=1;画完看字符图左右是否对称
原卷有尺寸线,重绘只写数字 数字对得上,但看不出量的是哪一段 原卷画箭头就画箭头(dim());只写裸数字等于换了标法
连线穿过文字被判压线 check_labels 报数字压线,放大看白底已经盖住 它按线段几何判、不看图层遮挡;连线一律按目标框的内边截断(取"半宽 ÷ cosθ"与"半高 ÷ sinθ"的较小值),别画到框心
标注压线 24pt 数字横跨线段 引线外移或换到线的另一侧;check_labels.py 兜底
上底与 45° 冲突 直角梯形画成上底 = 高 由 45° 反推上底 = 下底 − 高,再落点
组合图形少画分割线 学生看不出上部是三角形 补虚线,并在解析里点名"沿虚线分成上下两块"
多解法并列 学生不知道跟哪个 只留一条主路径
左栏 bounds 跨页 检查器报 module overlaps 左栏 bounds 右边界 = 文字实际右边界
相邻模块差几像素相交 svg_quality 一次报十几条 blocking,逐块挪坐标调不干净(文字高度会随字体度量浮动) 在 build.py 里把整页各块合成一个 <g id="page-body" data-pptx-bounds="48 108 1180 600">:保留块内容、只丢外层 <g>。一页一块必过,页边距也统一了。别为了"结构清晰"留着几十个互相咬的块
textfit 报 OVER-BOUNDS-YTOP 文字块顶边描到 y<110,压住页眉线 bounds 顶边取 max(110, y0 - 30);y0 是首行基线,直接减行高会越界
弧线上的角度标注压字 check_labels 报"90°"与弧相交,逐次收窄弧角也躲不开 角度标注沿半径外推到弧外(离圆心 1.15R 处),不要骑在弧上;弧本身只画到 78°–12° 这种留白区间
标题字号超声明 undeclared font-size 54 spec_lock typography 补声明,或统一到已声明字号
spec_lock 节奏值写错 validate 报 section &#x27;page_rhythm&#x27; has illegal value &#x27;medium&#x27;,退 1 只填 anchor/dense/breathing;讲评课件全 dense
图片状态值写错 invalid Status &#x27;ready&#x27; 按 $PM/../references/svg-image-embedding.md(ppt-master 的,不在本技能里) 的枚举填
表格/图片缺 §VIII 行 svg_image_missing_spec design_spec 与 spec_lock 两处都登记
质量报告指纹过期 svg_to_pptx 报 default release export requires a passing final SVG quality report,末尾 found stale 改过任何 SVG 就必须重跑 svg_quality_checker.py:新版按 svg_output 的 sha256 指纹校验报告新鲜度。ship.py 的顺序已满足,别绕过它单独导出
解析塞满整页 24pt 下挤成一团、贴到底边 先算版面预算:可用高度约 550px,每行 42px;题干行数+1(答案)+解析行数 ≤ 13 行。超了先精简措辞,再拆页,不缩字号
页边距被标注突破 标注跑到 x<56 图形整体右移或移到另一侧
方格纸格子不是方形 横竖间距不等(68×34),学生数不了格 先定 cell,横竖同用;make_grid.py --cell
顶点不在格点 与解析的"5×6=30 格"对不上 顶点写成 整格 × cell,画完反查每边格数
方格纸贴边 顶边贴纸顶,像被裁掉 上下左右各留 1 格空白
标签压在格线上 字母落在方格纸内部 标签基线放到纸外 36px 以上
两个图形叠放只画一个 只画成平行四边形 数清闭合图形个数,缺一个整张重画
旋转类图形朝向反了 赵爽弦图外框斜放、小正方形正放,画反 先定"哪个正放"再摆另一个;a、b 要贴住具体直角边
标注左右颠倒 10cm 原图在右竖边,画到左边 逐个核对"在哪条边、哪个角"
等腰梯形画歪 上下底中心不齐 上底、下底的中点 x 坐标必须相同
文件被预览占用无法覆盖 PermissionError / WinError 32;PowerPoint 只读打开也会锁文件 先用临时名 _vN.pptx 跑完全套检测,再循环 copyfile 覆盖(10 次 × 2 秒);覆盖后用 md5 核对项目内与桌面副本一致。始终失败就保留临时名并在交付里说明
页眉带了短标题 用户要求"只留编号" 页眉只写 五、2;要补充信息放题干,别放标题
构件方向画错 水平横梁画成竖向缝隙 数结构:几个构件、谁连谁、朝哪个方向;S7.2「结构拓扑」
竖式体例与卷面不符 卷面逐位分写,课件连写;数位错位 照卷面体例重画,横线伸出长度、箭头一起还原
图形配色擅自加深 卷面空白处被填成深色 照卷面;空白就画空白,靠边线界定(§2.2)
解析一步跨两个结论 F 到 AB 的距离=边长-AE=BE=8 拆成"两段距离和=边长""AE=边长-8"两步(§5.3)
改一两个字后字号变小 editor_sdk slide_set_text 后整行变 18pt 黑色 见 §11:改完必须补 slide_set_text_property
一题分两页,页眉按页序编 第 2 页写「一、3(2)」,内容其实是第 3 幅图 页眉括号写该页画了哪几幅:一、3(1)(2)/一、3(3);content_lint.py 会校验
字号用出夹心档 34 与 32 差 2px,同页并存分不出层级,只显乱 只用 32/36/40/48(封面 64 单列);qa()/Stack() 默认已是 32
红色既标答案又标错因 「易错:」用红、答案也用红,扫页时找不到答案 「易错:」与「解析:」同为藏蓝加粗,RED 只给答案值
灰度位图与矢量线不搭 卷面裁切图是黑线,和藏蓝矢量图并排显脏 别重绘几何(易走形):按亮度映射成藏蓝 alpha,alpha=clip((235-v)/155,0,1),存 RGBA PNG;首版用 (255-v)/255 会因中间灰占三成而发虚。旧图保留可回溯
图凭印象重画 太阳翼画成 2×2 带竖缝、方格线段方向反了、旋转顶点绕错方向——都由"看文字描述就想当然"引起 卷面有图先裁切;必须画就按 S7.1 量点,并按 S7.0 登记 figures.json 后出并排图逐张看
改完图没重拼对照 图改了,cmp_NN.png 还是旧的,等于拿旧证据签字 --check 会比对 mtime,对照图旧于 SVG 直接判失败;改图后重跑 --make 再看
拿 peek 的图当交付证据 peek 用 resvg 渲 SVG,字体抗锯齿与 PowerPoint 不同(均差约 8/255),且它不读 pptx,看不出字号被写死、custDash 被降级这类只在导出后出现的问题 peek 只回答"看着对不对";字号/压线/出界/虚线一律以 ship.py 的结论为准
改了判据脚本,脚本照跑但不报错 比较写反、rc 漏判、异常被 except 吞掉——这是最贵的一类缺陷,因为它让整条交付链变成装饰 改完任何脚本跑 selftest.py:它对每个闸门正反各测一遍(合法页放行 + 故意造错必须拦住)
答案豁免清单过期 页数改过,work/no-answer-pages.txt 里的旧页号豁免到了别的页 deck_check.py 会打印"超出总页数"点名;每次改页数顺手核对这份清单
换了个 python 就跑不起来 系统 python 没装 pymupdf / python-pptx / lxml 一律用受管环境 $PY;selftest.py 开头会打印实际解释器路径
封面把附加分算进总分 封面写「满分 110」「总计 110☆」——卷面的 110 是得分合计,不是满分 按 §2 三步累加:27+25+15+21+12=100,余下的第六大题 10☆ 才是附加;写「满分 100 分 附加题 10 分」。content_lint.py H4 兜底,但自检时别拿卷面字面去覆盖算对的口径——这条是被用户当面指出两次的
把行高当字号改 plain(640, 534, F3, 52, …) 改了没报错,其实第 3 参才是字号、第 4 参是行高 改封面文案只动第 5 参(文字);要调大小改第 3 参并把第 4 参按 ×1.35 同步
finalize_svg 偶发 rc=1 前一步 svg_quality 刚 OK,finalize_svg 却退 1;单独跑一次又正常 先单独跑 finalize_svg.py &lt;项目&gt; 确认(它幂等),能过就重跑 ship.py;连续两次失败才当真错
临时文件放 /tmp 检查脚本报 failed to load external entity:Git Bash 的 /tmp 是 %TEMP%,Windows 版 Python 写 /tmp/x 却落到 C:\tmp\x 临时目录一律建在项目 work/ 下(如 work/h4test/),用完删;跨脚本传路径写绝对路径

8 脚本

日常只用三条:ship.py(交付/复检)、peek.py(改完立刻看效果)、selftest.py(改过脚本才跑)。其余是按阶段调用的专项工具(如 S7 的 figcmp/figoverlay、S1 的 page_grid),何时用由 §4 决定;交付判定只认 ship.py,别把专项工具当成额外闸门挨个手跑一遍。

脚本 用途 用法
ship.py 一键交付:按固定顺序跑完十三道闸门+桌面同步(§9,共十四步),任一不过即停;--pages 22 只重出该页预览,--svg-only 只到 SVG 质检,--strict-env 让版本漂移直接失败 python &quot;$MX/ship.py&quot; &lt;项目&gt; --name &quot;《卷名》讲评(全卷N页).pptx&quot; [--pages 22] [--svg-only] [--no-desktop] [--allow-no-figures] [--strict-env](output/ 里已有成品时可省 --name,沿用那一个名字)
scan_figures.py 内嵌图清单:把 PDF 每页位图按页 dump 成竖排拼图,每张标注 rect,并写 index.md。填 figures.json 的 rect 只照它抄 python &quot;$MX/scan_figures.py&quot; &lt;卷面.pdf&gt; [--pages 1,4] [--dpi 200] [--out work/figscan]
figoverlay.py 叠合证据:把重绘按同一把尺(格纸页按格宽、其余按外框)叠回原图裁切,原卷进红、重绘进青。尺寸差会变成整圈偏色,比并排好判 python &quot;$MX/figoverlay.py&quot; &lt;项目&gt; [--page N] → work/fig/ov_NN.png;不给分数,不设阈值
peek.py 秒级速览:SVG 直接渲 PNG(0.5 s/页),完全不碰 pptx;--diff 与 output/ 里同页交付图并排并报差异,用来判断"这页到底改了没有"。只用于看效果,不是交付证据 python &quot;$MX/peek.py&quot; &lt;项目&gt; --page 9 [--diff]/--latest 3/--all
layout_eye.py 版面体检:量每页的墨量、深墨、重心、上/中/下三段分布、最长空带,判"空白页/过载/头重脚轻/下半页空",并按命中项给改法。--from-output 量已成片的预览图(ship 用这条),不带则渲 SVG。封面(data-deck-front)不判失衡 python &quot;$MX/layout_eye.py&quot; &lt;项目&gt; [--from-output] [--pages 25,32] [--strict] [--md]
selftest.py 技能自检:脚本齐不齐、--help 通不通、闸门拦不拦得住(合法页放行 + 故意造错各测一遍)、peek 与交付图是否仍一致。改过任何脚本先跑它 python &quot;$MX/selftest.py&quot; [--quick] [--project &lt;项目&gt;]
scaffold.py 新项目铺骨架:把 assets/ 的 lib.py/figures.py/pages.py/build.py 复制到 work/gen/(已存在则跳过,--force 覆盖) python &quot;$MX/scaffold.py&quot; &lt;项目&gt; [--force]
textfit.py 文本是否超页/超模块 bounds;退出码 1 = 有溢出 python &quot;$MX/textfit.py&quot; svg_output/*.svg
content_lint.py 内容级自检(不需要 PDF):页眉是否纯编号(data-deck-front=&quot;1&quot; 的前置页豁免)、有无「(续)」、纯计算题页有没有多写解析、连等是否跨步、有无方位词指代、有无装饰符、封面分值口径(H4:满分必须 100;>100 的合计未拆附加题就报错)。HARD 退 1,ADVICE 只提示(--strict 才计入) python &quot;$MX/content_lint.py&quot; svg_output/*.svg
check_labels.py PowerPoint 渲染 PDF 后检测"文字 × 图形线段"相交;页数不匹配退 2;有压线退 1。覆盖 line/polygon/polyline/path/有描边的 rect;按字符框判(line bbox 含行高留白,会把"贴着没压"判成压线) python &quot;$MX/check_labels.py&quot; out.pdf svg_output/*.svg
deck_check.py pptx 交付体检:最小字号、灰字、custDash、形状出界、缺答案页;退出码 1 = 不通过。--allow-no-answer 豁免声明过的页(ship.py 会自动读 work/no-answer-pages.txt 传进来) python &quot;$MX/deck_check.py&quot; x.pptx [--min-pt 24] [--allow-no-answer 1,2]
fix_dash.py 把 &lt;a:custDash&gt; 降级为 &lt;a:prstDash val=&quot;dash&quot;&gt;;--check 只查不改 python &quot;$MX/fix_dash.py&quot; x.pptx [-o out.pptx]
pptdiff.py 对比 pptx 与 svg_output 的文字,把用户在 PowerPoint 上的手改捞回源;退 0 = 一致、退 1 = 有差异并指名到页 python &quot;$MX/pptdiff.py&quot; &lt;项目&gt; [--pptx 文件]
pptx_pdf.ps1 备用:单独导 PDF(PowerPoint COM)。功能与 ship.py 第 8 步 pptx_pdf 等价,日常不用手敲——只有在"不跑全链、只要一份 PDF 给 check_labels"时才用它 powershell -File &quot;$MX/pptx_pdf.ps1&quot; -In x.pptx -Out y.pdf
make_preview.py PDF → 逐页 PNG + 总览拼图,列数自动 python &quot;$MX/make_preview.py&quot; y.pdf --outdir output [--cols 3]
page_grid.py 给试卷页盖 pt 坐标网,用来读出裁切矩形,不再靠猜 python &quot;$MX/page_grid.py&quot; 试卷.pdf 11 -o g.png [--step 50]
crop_figure.py 按 pt 矩形高分辨率裁图,落到 images/ python &quot;$MX/crop_figure.py&quot; 试卷.pdf 11 --rect x0,y0,x1,y1 --dpi 600
make_grid.py 生成方格纸 SVG 片段(含外框) python &quot;$MX/make_grid.py&quot; --cols 15 --rows 9 --cell 30 --x 56 --y 220
trace_figure.py 还原扫描图结构:提长线段 + 像素密度字符图(需 opencv) python &quot;$MX/trace_figure.py&quot; 页图.png x0 y0 x1 y1
grid_probe.py 量方格纸/放射图案(画之前先量):给定区域自动找等距格线,报行列数、格宽高、是否等距,出逐格平均灰度与逐格字符图(~=浅填充格、#=格内有图形、空白=纯白格;判据是"高于边框基线 5 个点",不是绝对阈值);--polar cx,cy 把浅填充块按极角归到 8 个扇区(k=22.5°+45k,附带"左上偏左"这类不歧义方位名);--outline 出四个可比的数:fill(轮廓/外接矩形)、solid(轮廓/凸包)、内部封闭区域几块、加 --center 再出放射线条数。图案题画前量原卷、画完量成图,四个数逐一对照——眼睛会骗人,面积比不会。方格题、八角形题、图案题一律先跑它,别目测数格。扫描白底偏灰、满屏都是 ~ 时用 --fill 150,235 收窄(--polar / --outline 需 opencv) python &quot;$MX/grid_probe.py&quot; 页图.png --rect x0,y0,x1,y1 [--polar cx,cy] [--outline --center cx,cy] [--line-frac 0.35] [--fill 150,225]
figcmp.py 图形对照:--scan 检出图形页并写 figures.json 骨架(字段留空);--make 拼"原图|成图"并排图;--check 验原图出处、标注值、对照图新旧,漏登记的页也直接算失败(ignore 列表可显式排除粗筛误判页);--list 列疑似图形页。退出码 0 通过/1 有缺项/2 未建登记 python &quot;$MX/figcmp.py&quot; &lt;项目&gt; --scan / --make / --check / --list

全部用受管环境跑:$PY(含 pymupdf / python-pptx / opencv / lxml / Pillow / resvg-py)。除纯生成脚本(make_grid / crop_figure / page_grid / trace_figure)外都带退出码,可以直接串进 &amp;&amp;;content_lint 最便宜(不依赖 PDF),每改完一批 SVG 就先跑它,整链交给 ship.py。

两处环境事实,踩过就别再踩:

  • peek.py 额外依赖 resvg-py(一次性:&quot;$PY&quot; -m pip install resvg-py,预编译轮子,不需要 cairo)。缺了它会打印安装命令并退出,不会静默降级。
  • env_lock.json 记着验证通过的 ppt-master 版本与 commit,以该文件为准(升级后先跑 selftest.py,通过再写入新 commit)。ship.py 每次启动核对并打印一行,不一致只 WARN——上游更新不该让课件交不出去,但得知道;--strict-env 才升级为失败。ppt-master 装在非默认位置时用 PPT_MASTER_SCRIPTS 指过去(指向 skills/ppt-master/scripts),别去改脚本里的常量。

9 交付闸门(一条命令,跑完再回话)

python &quot;$MX/ship.py&quot; &lt;项目&gt; --name &quot;《卷名》讲评(全卷N页).pptx&quot;   # 通过即可交付
# --name 省略时:沿用 output/ 里已有那份成品名;一个都没有 → 立刻失败(0.4s)并提示补 --name,
#              不会白跑一遍;所以首次交付必须带 --name

跑第一步之前先做环境核对:PPT_MASTER_SCRIPTS 指向的目录里四个入口脚本必须齐(缺了直接失败),
env_lock.json 记的 commit 与实际 HEAD 不一致则打 WARN 并在开头那行写明——这不拦交付,但见到它就该先跑一次 selftest.py。

它按顺序跑十三道闸门+桌面同步=十四步(--no-desktop 时十三步),判据写死在脚本里:

# 步骤 放行判据
1 validate rc=0
2 textfit 0 issues
3 content_lint HARD 0
4 svg_quality blocking 0 且 rc=0
5 finalize_svg rc=0
6 svg_to_pptx 产物存在
7 覆盖正式名 带锁重试 12×2s,md5 核对。重试失败不再中断:8–14 步改用 output/_build.pptx 照常跑完,桌面同步也用这一份,末尾单列「正式名没落地」并退 3——内容有没有问题是两件事,不该因为它停在一半
8 pptx_pdf 页数 = SVG 数
9 deck_check 结论 = 通过;work/no-answer-pages.txt 里声明的页不计入"缺答案"
10 check_labels 0 处压线
11 preview 预览页数 = SVG 页数(--pages 增量时允许旧图)
12 layout layout_eye.py 退 0(HARD 0)。"版面失衡"不拦交付,但页号会打出来并写进 work/layout-eye.md——交付回复里那句"版面无异常"必须以它为依据;报出来的页要么改,要么在 decisions.md 说明理由
13 figures figcmp.py --check 退 0。未建 work/figures.json 且检测到图形页 → 直接失败(--allow-no-figures 只给旧项目迁移用,交付时要写明"N 页图形未并排比对")。图形没并排比过就等于没验——2026-11 三张图案全画错,就是这一步被当"可跳过"
14 desktop 桌面副本存在且 md5 与 output/ 那份一致(--no-desktop 跳过;桌面不可写会在前面就报错)

顺序有讲究:第 8 步吃的是第 7 步的产物。先导 PDF 再改 pptx,check_labels 检的就是旧版,等于没检。把顺序写进脚本,就是为了不再靠人记。

第 12、13 步放在预览之后是有意的:它们比对的是成图,不是 SVG 声明。版面量的是渲染出来的像素;图形对照比的是 cmp_NN.png 与 SVG 的新旧——图改了却没重拼(cmp 比 SVG 旧)一律判失败,防止拿旧证据签字。

  • [ ] ship.py 跑到「结论:通过」(失败会停在具体那一步并打印条目)
  • [ ] 先看 output/全卷N页总览.png 扫一遍异常(某页大片空白、文字贴底、图形缺失、页与页疏密悬殊),再对可疑页逐页 ViewImage;图形按 S7.2 比对过。总览能一眼看出"哪页不对",逐页看则容易漏掉"整体不齐"
  • [ ] work/layout-eye.md 里列出的失衡页逐页处理过(改法就写在报告里),或在 decisions.md 写了理由。没看过它,交付回复里不许写"版面无异常"
  • [ ] work/figures.json 已建,figcmp.py --make 的「原图|成图」逐张 ViewImage 看过(不是翻课件单图),--check 退 0。第 12 步出现 ⚠ 时,交付回复第 2 段必须写"N 页图形未并排比对",不许写"图形已核对"
  • [ ] 图案页(风车/月牙/花瓣/音符/树)原卷与成图各跑过 grid_probe.py --outline,solid、fill、封闭区域数三项对得上;只比"看着像"不算
  • [ ] 答案复算过,单位对;填空/计算类的答案能一眼找到
  • [ ] 页数与题数对得上,续页无「(续)」
  • [ ] 有封面时:满分 100 + 附加 N = 卷面合计,信息带里没有「总计 110☆」这类合计数(§1 第 8 条)
  • [ ] 无灰字、无装饰符(✓ 等)、图形内文字全藏蓝
  • [ ] output/ 下有:pptx、逐页 PNG(110 DPI,1467×825)、总览 PNG(make_preview.py 按页数自动排布,列数与画布高度随页数变化,不要照抄某一次的尺寸)
  • [ ] §2.2 的默认约定逐条对过:分值口径(满分+附加题,不写合计)、页眉纯编号、虚实线按步骤顺序、拼摆横排优先、配色照卷面、简化不减结构、指代用字母、单一路径
  • [ ] pptx 已复制一份到桌面(桌面不可写则跳过,在交付里说明)
  • [ ] SVG 源与 pptx 一致(改过 pptx 的,已同步回 SVG)
  • [ ] work/answer-audit.md、figure-audit.md、decisions.md、selfcheck-full.md 四份都在

10 交付回复写什么(写完就结束,不要反问"要不要继续")

按这五段写,一段不能少:

  1. 成品:output/ 与桌面的完整路径、页数、文件大小。
  2. 核查结论:总题数、答案差异(题号/卷面/验算值)、题目本身存疑处。封面口径若与卷面字面不同(课件写"满分 100 + 附加 10",卷面印"总计 110☆"),在这一段解释一句"110 是得分合计、100 是正卷满分"——不解释,用户会以为你算错了。
  3. 我替你定的:decisions.md 里的关键几条(简化了哪张图、哪页拆了、答案怎么定的),一条一句。
  4. 遗留:仍未确定的(如图形局部做了简化、某处按卷面原样保留)。没有就写"无"。
  5. 收尾一句:\"哪一页要改,指出来我直接改。\"——只此一句,不要附带问题清单。

不得在交付时反问"配色可以吗""要不要加封面""需不需要调整"——这些 §2 已经定了。

11 交付后的微调(用户指着某一页说要改)

第一步:确认 pptx 还是不是你上次交的那份。 用户常在 PowerPoint 上自己改几处再交回来,
这时直接重建会整页覆盖,改动全丢。先对一遍源与产物(ship.py 已在覆盖前自动把旧正式名
存进 backup/&lt;时间戳&gt;_formal/,但走 editor_sdk 就地改的那条路没有这层保护):

python &quot;$MX/pptdiff.py&quot; &lt;项目&gt;          # 逐页列出「svg 有、pptx 没有」与「pptx 有、svg 没有」的段落

退 0 = 两边一致,放心重建;退 1 = 命令行已指名到页,把每条落回 work/gen/pages_*.py
(用户删掉的就把那段代码删掉,改过措辞的就照抄),再重建。字号不在四档也会一并列出来。

再选路径,别一律上手改 pptx:

改动性质 走哪条路
纯文字(错字、措辞、去个符号) editor_sdk 就地改,改完同步 SVG
图形、增删行、版式、涉及重算 改 SVG → 重跑 S8 全线(checker → finalize → svg_to_pptx),不要在 pptx 上补画

原因:pptx 上的手改没有源,下次重建就丢;而图形改动用 editor_sdk 拼不出原生形状。

改 1–3 页时的加速路径(三档由小到大,按需停在哪一档):

# ① 0.5 秒:改完立刻看效果,只看图、不判合规
python &quot;$MX/peek.py&quot; &lt;项目&gt; --latest 1
# ② 7 秒:SVG 侧没破(宽度溢出 / 页眉 / 续页 / 装饰符)
python &quot;$MX/ship.py&quot; &lt;项目&gt; --svg-only
# ③ 24 秒:全链,但预览只重出改动页
python &quot;$MX/ship.py&quot; &lt;项目&gt; --pages 22,25

> 不要为了快只检改动页:lib.py 这类共用件一改会波及全册(本次改 NB 集合就让 31 页全部重新排版),
> 只检一页会漏掉连带效应。ship.py 的文本/质检始终跑全册,只把"渲染预览"限制在指定页,这是有意的取舍。
> peek.py 的定位是省掉"为一个像素重建一次 pptx",不是省掉检测——它连 SVG 之外的东西都不看。

→ 具体命令、page_index 0 基、字号用 pt、save_file 后实例失效、文件锁重试、改完复检清单:读 references/post-edit.md。

12 目录约定

projects/&lt;卷名&gt;_ppt169_&lt;YYYYMMDD&gt;/
  design_spec.md  spec_lock.md
  README.md                                # 空壳即可:validate 缺它会报一条无效 WARN
  svg_output/01_xxx.svg … NN_xxx.svg      # 一页一个,序号 = 页序
  images/                                  # 裁切图、logo
  exports/&lt;项目名&gt;_&lt;时间戳&gt;.pptx            # ppt-master 产出(带时间戳)
  validation/                              # 检查报告
  work/paper-items.md  answer-audit.md  figure-audit.md  selfcheck-full.md  decisions.md
  work/page-index.md                       # build.py 自动生成:页 → 标题 → SVG → 函数
  work/gen/{lib,figures,pages,build}.py    # 由 scaffold.py 铺开;lib/figures 是冻结件
  work/no-answer-pages.txt                 # 允许没有「答案:」的页(前置页/填空内嵌/纯图形)
  work/layout-eye.md                       # layout_eye.py 的逐页版面指标与改法(ship 第 12 步自动写)
  work/peek/                               # peek.py 的速览图,随时可删,不是交付物
output/                                    # 交付:pptx(正式名)+ 逐页 PNG + 总览 PNG
_inbox/                                    # 用户桌面收来的转换残留(md/页面图)

> 一页一文件、序号即页序,是为了让 check_labels.py 能按文件名排序对齐 PDF 页码。

常见问题

5 问
答案由本站依据条目字段整理
数学试卷转PPT怎么安装?

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

数学试卷转PPT支持哪些客户端?

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

数学试卷转PPT权限高吗,安全吗?

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

数学试卷转PPT收费吗?

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

数学试卷转PPT用什么许可证?

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

热门专题

按场景挑技能
全部专题 →

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