Local-first, deterministic quality assurance for PowerPoint (.pptx) files — built for AI-generated decks and the agents that produce them.
LayoutProof inspects .pptx files on your own machine and flags layout, readability, accessibility and package-integrity problems before a deck is shipped. It is aimed squarely at the happy path failure mode of generative slide pipelines: text that overflows its box, objects parked off-slide, 8 pt body copy, broken media relationships, leftover click to add title placeholders, and simplified-Chinese typography glitches.
One-line value: catch broken AI-generated decks locally, with stable JSON and exit codes an agent can act on — no upload, no subscription, no PowerPoint required.
- AI / LLM agents and slide-generation pipelines that emit
.pptxand need a deterministic quality gate in CI or in an agent loop. - Developers and content teams building decks programmatically (python-pptx, templates, RAG-to-slide) who want low-false-positive linting.
- Chinese-language deck authors who need simplified-Chinese typography checks (kinsoku, CJK–Latin spacing, full/half-width punctuation).
- Fully offline. No network calls, no telemetry, no cloud upload. Pure Python on your machine.
- 12 stable, versioned rules across geometry, typography, accessibility and OOXML package integrity.
- Two profiles.
core(default) ships 7 high-confidence, low-false-positive rules;fullenables all 12. - Agent-friendly contract. A machine-readable JSON report (schema
1.0) plus a four-value exit code that CI and agents can branch on. - Safe by construction. Reads
.pptxas a hardened zip/XML stream, never executes embedded content, and refuses to walk outside the files you point it at. - Bilingual findings. Every rule carries an English and a Chinese title, explanation and recommendation.
Requires Python ≥ 3.11.
# from PyPI (once published)
pip install layoutproof
# or with pipx for an isolated global CLI
pipx install layoutproof
# from a local checkout (development)
pip install -e .[dev]After install, the layoutproof command is available:
layoutproof --version
# LayoutProof 0.1.0a1scan is the default command — a bare path is equivalent to layoutproof scan <path>.
Scan a single deck (human-readable report):
layoutproof scan test_fixtures/corpus/broken_all.pptxLayoutProof 0.1.0a1 - broken_all.pptx
========================================
Slides: 11 | errors 2 warnings 6 info 0
ERROR offslide_object slide 1 [Rectangle 2]
Object outside slide bounds
-> 100% outside slide
fix: Move the object fully inside the slide bounds, or delete it if it is unused.
WARN text_overflow slide 2 [TextBox 2]
Suspected text overflow or clipping
-> estimated 13 line(s) need ~402pt but box is only 55pt tall
fix: Enlarge the text box, reduce the text, or enable auto-fit/shrink text on overflow.
WARN font_too_small ...
A clean deck exits 0:
layoutproof scan test_fixtures/corpus/clean_basic.pptxLayoutProof 0.1.0a1 - clean_basic.pptx
========================================
Slides: 2 | errors 0 warnings 0 info 0
No issues found. Deck passed the selected profile.
Scan a whole directory (add -r to recurse):
layoutproof scan test_fixtures/corpus
layoutproof scan test_fixtures/corpus -rEmit machine-readable JSON (one object for a single file, an array for many):
layoutproof scan deck.pptx --json{
"schema_version": "1.0",
"tool": { "name": "layoutproof", "version": "0.1.0a1" },
"file": { "path": "deck.pptx", "name": "deck.pptx" },
"status": "ok",
"error": null,
"slide_count": 11,
"summary": { "error": 2, "warning": 6, "info": 0, "total": 8 },
"issues": [
{
"rule_id": "offslide_object",
"severity": "error",
"slide_number": 1,
"shape_name": "Rectangle 2",
"detail": "100% outside slide",
"fixable": true
}
]
}Gate strictly on errors (instead of the default warnings):
layoutproof scan deck.pptx --fail-on errorEnable all 12 rules (overlap, blank slides, alt text, CJK typography …):
layoutproof scan deck.pptx --profile fullfix and demo subcommands. The CLI includes fix (safe automatic repairs + re-verify) and demo (generate a broken deck and its fixed counterpart). Both are fully wired in this build. The source is never modified: fixes write a new file (and an optional backup), then re-scan it to confirm the reduction.
$ layoutproof fix deck.pptx
Before: 4 issues -> After: 0 (removed 4)
+ increase_font_size (font_too_small)
+ autofit_text (text_overflow)
+ move_into_slide (offslide_object)
+ clear_placeholder (unfinished_placeholder)
$ layoutproof demo --dir ./demo
Issues that cannot be repaired safely (overlap, blank, media, references, alt text, structure) are reported as skipped with a manual-review note rather than faked.
layoutproof scan writes a JSON document conforming to src/layoutproof/report/schema.json (schema_version: "1.0"). Top-level keys: tool, file, status (ok | error), error, slide_count, summary (error/warning/info/total), issues[], and the effective config. Each issue carries rule_id, severity, slide_index/slide_number, shape_id/shape_name, location/normalized_location (EMU and fraction of slide), detail, confidence, fixable, fix_id and evidence.
| Exit code | Meaning | When |
|---|---|---|
0 |
Clean | No issue at or above the --fail-on threshold. |
1 |
Quality gate failed | At least one issue meets/exceeds the threshold (default: any warning). |
2 |
Usage / input error | Bad arguments, no .pptx found at the target, or a file that cannot be opened as a valid zip/OOXML package. |
3 |
Internal error | Unexpected failure, or a subcommand whose engine is not present in this build. |
Default --fail-on is warning: warnings fail the build, info does not. Set --fail-on error to gate only on deterministic errors, or --fail-on info for the strictest gate.
Pass a TOML or JSON file with --config (a [tool.layoutproof] table is also accepted, e.g. in pyproject.toml):
# layoutproof.toml
min_font_size_pt = 14.0 # body text readability floor
min_contrast_ratio = 4.5 # WCAG AA body text
large_text_pt = 18.0 # large-text threshold
large_text_contrast_ratio = 3.0 # large-text contrast floor
overlap_ratio_threshold = 0.30 # share of the smaller shape that counts as overlap
offslide_fraction_threshold = 0.05
overflow_ratio_threshold = 0.15
max_file_size_mb = 100
fail_on = "warning" # error | warning | info
# enabled_rules = ["offslide_object", "font_too_small"] # whitelist (overrides profile)
# disabled_rules = ["cjk_typography"] # blacklist--profile selects which rules run; explicit enabled_rules / disabled_rules in the config always win over the profile.
| Profile | Rules enabled |
|---|---|
core (default) |
offslide_object, font_too_small, text_overflow, unfinished_placeholder, media_broken, broken_reference, structure_anomaly |
full |
All 12 rules above, plus object_overlap, low_contrast, blank_slide, missing_alt_text, cjk_typography |
See docs/USAGE.md for the full rule catalogue and more config examples.
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: "3.12"
- name: Install
run: pip install layoutproof
- name: Quality gate on generated decks
run: layoutproof scan generated/ --recursive --profile full --fail-on errorThe repository ships a ready-made CI workflow at .github/workflows/ci.yml that installs the package and runs the test suite on Ubuntu and Windows across Python 3.11–3.13.
LayoutProof/
├── src/layoutproof/
│ ├── cli.py # argparse entrypoint (scan/fix/demo)
│ ├── engine.py # scan_file(): parse -> run rules -> attach anomalies
│ ├── models.py # frozen data contract, rule catalogue, exit codes
│ ├── config.py # QualityConfig load (TOML/JSON) and thresholds
│ ├── parsing/ # zip/OOXML package + geometry model
│ ├── rules/ # one module per detection rule
│ ├── fix/ # safe repair engine (new-file output, re-verify)
│ └── report/ # JSON output + schema, self-contained HTML report
├── tests/unit/ # per-rule yin/yang tests
├── test_fixtures/ # generated corpus (.pptx) + manifest
└── docs/USAGE.md # detailed rule & config reference
python -m venv .venv
# Windows: .venv\Scripts\activate | Unix: source .venv/bin/activate
pip install -e .[dev]
pytestEvery detection rule ships with yin (should fire) and yang (should not fire) unit tests under tests/unit/. A defect discovered in production is turned into a regression fixture before it is fixed.
- Rendering is optional: when a local LibreOffice renderer is available (or
LAYOUTPROOF_SOFFICEis set), slides are rendered to real images; otherwise the tool uses a clearly disclosed static fallback and never presents an estimate as a render. - No
.ppt(binary) or.keysupport — only.pptx; Word/.docx is not in scope. - Contrast resolves explicit fills and the master theme background (
bg1/tx1); other theme-derived or gradient-only colors stay conservative. - Linux/macOS runtime behavior is not asserted in CI beyond the static path; geometry assumptions follow the slide dimensions stored in the file.
MIT — see LICENSE.
There is no CI publish step in this repository yet. To cut a release by hand:
- Bump
versioninpyproject.tomland add aCHANGELOG.mdentry. - Ensure
python -m pytestis green on the supported matrix (3.11/3.12/3.13, Ubuntu + Windows). - Build:
python -m build(requirespip install build). - Verify the artifact:
twine check dist/*. - Upload:
twine upload dist/*(you need PyPI maintainer rights). - Tag the commit:
git tag vX.Y.Z && git push origin vX.Y.Z.
LayoutProof 在本机对 PowerPoint(.pptx)文件做确定性质量检查,在演示文稿交付前拦截版式、可读性、可访问性与包完整性问题。它专门面向生成式幻灯片流水线最常见的失败模式:文字溢出文本框、对象落在页面外、8 pt 正文、损坏的媒体关系、残留的 点击添加标题 占位符,以及简体中文排版错误。
一句话价值:在本地拦截坏掉的 AI 生成 PPT,输出 Agent 可直接消费的稳定 JSON 与退出码——不上传、不订阅、无需安装 PowerPoint。
- AI / LLM Agent 与幻灯片生成流水线:需要在 CI 或 Agent 闭环里做确定性质量门禁。
- 程序化生成幻灯片的开发者与内容团队(python-pptx、模板、RAG 转幻灯片):需要低误报的 lint。
- 中文 PPT 作者:需要简体中文排版检查(避头尾、中西文间距、全半角标点)。
- 完全离线:无网络请求、无遥测、无云端上传。
- 12 条稳定且带版本号的规则,覆盖几何、排版、可访问性与 OOXML 包完整性。
- 双 profile:
core(默认)7 条高置信低误报规则;full开启全部 12 条。 - Agent 友好契约:机器可读 JSON 报告(schema
1.0)+ 四值退出码。 - 安全构造:以加固的 zip/XML 流读取
.pptx,绝不执行嵌入内容,绝不遍历你指定范围之外的文件。 - 双语结论:每条规则都带中英文标题、解释与修复建议。
需要 Python ≥ 3.11。
# 从 PyPI(发布后)
pip install layoutproof
# 或用 pipx 安装为隔离的全局命令
pipx install layoutproof
# 本地开发可编辑安装
pip install -e .[dev]scan 是默认子命令,直接跟路径即可。
# 扫描单个文件
layoutproof scan test_fixtures/corpus/broken_all.pptx
# 干净文件退出码为 0
layoutproof scan test_fixtures/corpus/clean_basic.pptx
# 扫描目录(-r 递归)
layoutproof scan test_fixtures/corpus -r
# 输出 JSON(单文件为对象,多文件为数组)
layoutproof scan deck.pptx --json
# 仅以 error 作为门禁
layoutproof scan deck.pptx --fail-on error
# 开启全部 12 条规则
layoutproof scan deck.pptx --profile fullfix(安全自动修复并复跑)与 demo(生成示例坏文件与修复后文件)两个子命令均已在本构建中打通。修复绝不改动源文件:结果写入新文件(可另选备份),随后重新扫描确认问题减少。无法安全修复的问题(重叠、空白、媒体、引用、替代文本、结构)会列入 skipped 并标注需人工,不会伪造。
scan 输出符合 src/layoutproof/report/schema.json(schema_version: "1.0")的 JSON。每条 issue 含 rule_id、severity、slide_number、shape_name、detail、fixable、fix_id 等字段。
| 退出码 | 含义 | 触发条件 |
|---|---|---|
0 |
干净 | 没有达到 --fail-on 阈值的问题。 |
1 |
质量门禁未过 | 存在达到/超过阈值的问题(默认:任一 warning)。 |
2 |
用法/输入错误 | 参数错误、目标下无 .pptx,或文件不是合法的 zip/OOXML 包。 |
3 |
内部错误 | 意外异常,或本构建中未提供对应引擎的子命令。 |
默认 --fail-on warning:warning 即失败,info 不失败。--fail-on error 仅以确定性错误为门禁,--fail-on info 为最严门禁。
用 --config 传入 TOML 或 JSON(也支持 [tool.layoutproof] 表):
min_font_size_pt = 14.0
min_contrast_ratio = 4.5
large_text_pt = 18.0
large_text_contrast_ratio = 3.0
overlap_ratio_threshold = 0.30
offslide_fraction_threshold = 0.05
overflow_ratio_threshold = 0.15
max_file_size_mb = 100
fail_on = "warning"core 默认启用 7 条高置信规则;full 额外开启 object_overlap、low_contrast、blank_slide、missing_alt_text、cjk_typography。配置中显式的 enabled_rules / disabled_rules 优先级高于 profile。完整规则目录见 docs/USAGE.md。
- uses: actions/setup-python@v5
with: { python-version: "3.12" }
- run: pip install layoutproof
- run: layoutproof scan generated/ --recursive --profile full --fail-on error仓库自带 .github/workflows/ci.yml,在 Ubuntu 与 Windows、Python 3.11–3.13 矩阵上安装并运行测试。
python -m venv .venv
pip install -e .[dev]
pytest每条规则在 tests/unit/ 下都有"阴(应触发)/阳(不应触发)"成对测试;生产发现的缺陷先补回归夹具再修复。详见 CONTRIBUTING.md。
- 渲染为可选项:当本机存在 LibreOffice 渲染器(或设置
LAYOUTPROOF_SOFFICE)时输出真实渲染图;否则使用明确披露的静态回退,绝不把估算冒充渲染。 - 仅支持
.pptx,不支持旧版二进制.ppt或 Keynote;Word/.docx 不在范围内。 - 对比度可解析显式填充与母版主题背景(bg1/tx1);其他主题色/渐变场景保守处理。
- CI 除静态路径外不承诺 Linux/macOS 运行时行为;几何判断以文件内幻灯片尺寸为准。
MIT,见 LICENSE。
本仓库暂无自动发布 CI,手动发版流程:
- 升级
pyproject.toml中的version,并在CHANGELOG.md记录变更。 - 在支持矩阵(3.11/3.12/3.13,Ubuntu + Windows)上跑通
pytest。 - 构建:
python -m build(需pip install build)。 - 校验:
twine check dist/*。 - 上传:
twine upload dist/*(需 PyPI 维护者权限)。 - 打标签:
git tag vX.Y.Z && git push origin vX.Y.Z。