Proofing in CI
Hellbox’s headless commands run anywhere macOS runs, including GitHub Actions runners. A font repo can render a fresh proof PDF on every commit, attach it to the pull request, and fail the build when character coverage or layout regresses.
Want to see it working? Fork the example repo: jakefleming/hellbox-ci-example proofs Space Grotesk on every push with the exact workflow below.
The idea
- Author a proof document (
.fontproof) in Hellbox and commit it to your font repo, with your font files next to it (or in afonts/folder beside it). Documents are portable: when Hellbox renders headlessly on another machine, it resolves fonts relative to the document. Requires Hellbox 1.20.2 or later.
The example repo's proof document in Hellbox: spacing strings, reading sizes, and a tracking test, committed beside the fonts.
- In CI, after your fonts build, copy the fresh binaries over the committed ones, then run
--render-checkfor a machine-readable audit and--exportfor the PDF artifact. - Fail the build if the audit reports coverage or overflow issues.
--export and --render-check don’t require a license on the machine running them; the document is authored in the app.
What —render-check reports
{
"ok": true,
"pages": 24,
"pageWidthPts": 612,
"pageHeightPts": 792,
"coverageIssues": [
{ "section": "Diacritics", "font": "MyFont-Regular", "missingCount": 3, "missing": ["ẽ", "ő", "ų"] }
],
"overflowIssues": [
{ "section": "Spacing", "shownPages": 1, "neededPages": 2 }
]
}
coverageIssues lists characters a proofed font has no glyph for, per section and font. overflowIssues flags sections whose content no longer fits their page budget. Both keys are absent when clean.
Example GitHub Actions workflow
name: Proof
on: [push, pull_request]
jobs:
proof:
runs-on: macos-14
steps:
- uses: actions/checkout@v4
# Build your fonts however you already do, then place the
# binaries where the committed .fontproof expects them
# (next to the document, or in fonts/ beside it).
- name: Build fonts
run: |
# e.g. fontmake, or copy prebuilt binaries:
# cp build/*.otf proofs/fonts/
- name: Install Hellbox
run: |
curl -sL -o Hellbox.dmg \
https://jakefleming.github.io/font-proof-swift/downloads/Hellbox-latest.dmg
hdiutil attach Hellbox.dmg -nobrowse -quiet
cp -R /Volumes/Hellbox/Hellbox.app /Applications/
hdiutil detach /Volumes/Hellbox -quiet
- name: Render check
run: |
HELLBOX=/Applications/Hellbox.app/Contents/MacOS/Hellbox
"$HELLBOX" --render-check proofs/family.fontproof > check.json
cat check.json
# Fail on any coverage or overflow regression:
jq -e '(.coverageIssues // []) + (.overflowIssues // []) | length == 0' check.json
- name: Export proof PDF
run: |
/Applications/Hellbox.app/Contents/MacOS/Hellbox \
--export proofs/family.fontproof proof.pdf
- uses: actions/upload-artifact@v4
with:
name: proof
path: proof.pdf
Pin a specific Hellbox version by replacing Hellbox-latest.dmg with a versioned file such as Hellbox-1.20.1.dmg; every release’s DMG URL is permanent.
Tips
- Keep the committed
.fontproofsmall and targeted: a coverage-heavy document (Diacritics, Every glyph) makes the coverage gate meaningful. --render-pngs proofs/family.fontproof out/ 2renders per-page PNGs if you’d rather diff images than read PDFs.- Since proofs render with no font fallback, characters your font lacks appear as its own
.notdefin the PDF, and incoverageIssues, so a shrinking character set is visible in both places.