goodboy008/labelize/zpl-diff-auto-fix
Claude Code and agent skill by goodboy008/labelize
- community
Checking that the SKILL.md file is still in the repository.
Auto-detect high-diff ZPL labels, extract problematic elements into standalone ZPL files, and iteratively fix rendering logic until diff drops below 1%. Use when: label diff is too high, need to reduce rendering differences, want automated fix cycle, batch fix all labels.
Install
npx vskill@latest install goodboy008/labelize/zpl-diff-auto-fixSKILL.md
ZPL Diff Auto-Fix Skill
Other languages: EPL uses renderer-baseline goldens (no externalreference renderer) — the analyze/fix phases still apply withparsers/epl/as the fix surface. TSPL, CPCL and DPL each have theirown sibling skill — tspl-diff-auto-fix(labelixa/portakal), cpcl-diff-auto-fix(labelixa CPCL endpoint), dpl-diff-auto-fix(Evolabel layout view) — with per-language guardrails; consult therelevant Language Matrix before cross-applying procedures.
Purpose
Automatically detect labels with high rendering diff percentages, isolate the problematic ZPL elements into standalone test files for focused debugging, and iteratively fix the rendering logic until the diff drops below a target threshold (default 1%).
Critical Rule — Fix Rendering Code, Never Tests
DO NOT modify diff tests, golden test infrastructure, reference images, tolerance thresholds (to hide regressions), or test comparison logic to make diffs pass. The goal is to improve rendering accuracy, not to weaken the test harness.
DO fix the root cause in rendering code and logic:
- Parsers:
src/parsers/ - Elements:
src/elements/ - Barcode encoders:
src/barcodes/ - Renderer / drawing:
src/drawers/ - Font handling:
src/assets/
Threshold updates in docs/DIFF_THRESHOLDS.md are only allowed after a rendering fix genuinely lowers the diff percentage — set the new tolerance slightly above the new measured diff, never raise it to paper over a regression.
When to Use
- A label has a diff percentage higher than desired
- You want to systematically reduce rendering differences across all labels
- You need to extract standalone ZPL snippets to isolate a rendering bug
- After implementing a rendering change, you want to verify and fine-tune it
Prerequisites
Before starting, ensure:
- The diff report is up to date:
cargo test --test e2e_diff_report -- --nocapture - All current tests pass:
cargo test - You have reference PNG images in
testdata/for the target label(s)
Procedure
Phase 1: Scan — Identify High-Diff Labels
- Read the diff report from label report and unit report
- Read the tolerance thresholds from docs/DIFF_THRESHOLDS.md
- Identify target labels — either a specific label from the user's request, or all labels with diff > 1%:
- List labels sorted by diff percentage (highest first)
- For each, note the current diff%, tolerance, and primary diff source
- Pick the highest-impact label to fix first (highest diff% that is potentially fixable — skip MaxiCode/PDF417 unless specifically requested)
Phase 2: Analyze — Find Problematic Elements
- Read the ZPL source from
testdata/labels/<name>.zplortestdata/unit/<name>.zpl
- Parse the ZPL to identify all commands and elements:
`` Use src/skill/snippet_extractor.rs → split_zpl_commands() to list all commands Use src/skill/snippet_extractor.rs → group_commands_into_spans() to group into element spans ``
- Inspect the diff image at
testdata/diffs/<name>_diff.png— red pixels show where rendering differs from Labelary
- Correlate diff regions with elements using
src/skill/element_analyzer.rs:
- Parse the ZPL to get
LabelInfo - Compute bounding boxes for each element via
compute_element_bbox() - Load the diff image and count red pixels in each bbox via
correlate_diff_regions() - Report which elements contribute most to the total diff
- Rank elements by diff contribution — focus on the top 3-5 contributors
9b. Classify each element's diff as ContentDiff, PositionDiff, or Mixed using src/skill/diff_classifier.rs → classify_element_diffs():
`` // Full pipeline with classification: Use element_analyzer::analyze_label_with_classification(label, diff_path, zpl, use_labelary) ``
The classifier renders each element in isolation, optionally fetches the Labelary reference for the same snippet, and compares the two renders:
| Isolated snippet diff | Full-label bbox diff | Classification | |
|---|---|---|---|
| Low (< 2%) | High (> 2%) | PositionDiff — element placed wrong | |
| High (> 2%) | Any | ContentDiff — element renders wrong | |
| High (> 2%) | High (> 2%) | Mixed — both | |
| Low (< 2%) | Low (< 2%) | No classification (no meaningful diff) |
For PositionDiff elements, the classifier also attempts to detect the offset vector (dx, dy):
- Shadow detection: two clusters of red pixels → direct offset measurement
- Centroid shift: centroid of diff pixels vs. expected element center
Phase 3: Extract — Create Standalone Snippets
- Extract each high-diff element into a standalone ZPL file:
`` Use src/skill/snippet_extractor.rs → extract_element() ` This creates testdata/unit/<label>_<index>.zpl` with:
^XA/^XZwrapper- Global state commands (
^PW,^CF,^BY,^CI,^FW,^PO,^LR) preserved - The specific element's command span (
^FO/^FTthrough^FS)
- Render each snippet to verify it renders correctly in isolation:
``bash cargo run -- convert testdata/unit/<label>_<index>.zpl ` Both unit tests (testdata/unit/) and carrier labels (testdata/labels/) use the full Labelary canvas (101.625×203.25 mm at 8 dpmm → 813×1626 px). Unit golden PNGs are Labelary references at 812×1624 px` (Labelary rounds by 1 px due to float precision).
- Get Labelary reference for each snippet — post the snippet ZPL to:
`` POST http://api.labelary.com/v1/printers/8dpmm/labels/4.005x8.01/0/ ` Save the reference as testdata/unit/<label>_<index>_ref.png`. Note: Labelary renders at 812×1624 for our canvas size (1 px smaller than the local renderer's 813×1626 due to floating-point rounding of the inch dimensions). This causes a ~0.25% systematic diff; direct pixel comparison is done over the overlapping region.
- Compare snippet renders — this isolates the rendering difference to a single element
Phase 4: Fix — Iterative Rendering Fixes
For each high-diff element, starting with the highest contributor:
- Identify the element type, diff classification, and fix category:
Use FixCategory::from_classification(element_type, classification) to select the fix strategy:
| Classification | Fix Strategy | Target Source Files | |
|---|---|---|---|
| ContentDiff + Text | FontMetrics | src/drawers/renderer.rs, src/elements/font.rs | |
| ContentDiff + Barcode128 | BarcodeEncoding | src/barcodes/code128.rs, src/drawers/renderer.rs | |
| ContentDiff + BarcodeEan13 | BarcodeEncoding | src/barcodes/ean13.rs | |
| ContentDiff + Barcode2of5 | BarcodeEncoding | src/barcodes/interleaved2of5.rs | |
| ContentDiff + Barcode39 | BarcodeEncoding | src/barcodes/code39.rs | |
| ContentDiff + BarcodePdf417 | BarcodeEncoding | src/barcodes/pdf417.rs | |
| ContentDiff + BarcodeAztec | BarcodeEncoding | src/barcodes/aztec.rs | |
| ContentDiff + BarcodeDatamatrix | BarcodeEncoding | src/barcodes/datamatrix.rs | |
| ContentDiff + BarcodeQr | BarcodeEncoding | src/barcodes/qrcode.rs | |
| ContentDiff + Maxicode | BarcodeEncoding | src/barcodes/maxicode.rs | |
| ContentDiff + GraphicBox/Circle/Line/Field | GraphicRendering | src/drawers/renderer.rs | |
| PositionDiff (any element) | PositionOffset | src/parsers/zpl_parser.rs, src/elements/field_alignment.rs, src/elements/drawer_options.rs | |
| Mixed (any element) | PositionOffset first, then ContentDiff fix | Both sets above |
For PositionDiff elements, use the detected offset vector (dx, dy) from PositionOffsetInfo to guide the fix — look for coordinate calculation that differs by that many pixels.
- Fetch the official Zebra documentation for the suspect ZPL command using the
zpl-referenceskill:
`` https://docs.zebra.com/us/en/printers/software/zpl-pg/c-zpl-zpl-commands/r-zpl-<slug>.html ``
- Compare spec vs implementation using the
fix-zpl-renderskill's Phase 3 comparison table
- Apply the fix to the relevant source file
- Verify the fix:
```bash # Quick check — does it compile? cargo build
# Render the snippet cargo run -- convert testdata/unit/<label>_<index>.zpl
# Run the specific golden test cargo test --test e2e_golden -- <label_name> --nocapture
# Check for regressions on ALL labels cargo test --test e2e_golden ```
- Measure improvement:
``bash cargo test --test e2e_diff_report -- --nocapture `` Compare the new diff% against the previous value.
- If diff improved without regressions: Keep the change and proceed to the next element.
- If diff regressed on other labels: Revert the change and try a different approach.
- Repeat from step 14 for the next highest-contributing element.
Phase 5: Finalize — Update Thresholds and Report
- Update diff thresholds in docs/DIFF_THRESHOLDS.md:
- Set new diff% values for improved labels
- Set new tolerance ceilings slightly above the new diff%
- Regenerate diff images:
``bash cargo test --test e2e_diff_report -- --nocapture ``
- Run full test suite:
``bash cargo test ``
- Commit all changes including:
- Source code fixes
- Updated
docs/DIFF_THRESHOLDS.md - Updated diff images in
testdata/diffs/ - New snippet files in
testdata/unit/(if useful for ongoing debugging)
Auto-Fix Loop Strategy
When running in fully automated mode ("fix all labels above 1%"):
Known Limitations
These labels cannot reach <1% diff due to fundamental limitations:
| Label | Blocker | Reason | |
|---|---|---|---|
| ups, ups_surepost | MaxiCode encoder | Proprietary encoding, no compliant open-source encoder | |
| fedex | PDF417 encoding | rxing encoder uses different compaction modes (valid but visually different) | |
| aztec_ec | Aztec encoding | rxing Aztec encoder differs in symbol sizing | |
| pnldpd | Multiple (Aztec + GFA + font) | Compound issues from barcode encoding + font metrics | |
| Most text-heavy labels | Font metrics | Helvetica Bold vs Zebra proprietary fonts |
Utility Code Reference
The skill uses Rust utilities in src/skill/:
This is the start of the file. Read the full SKILL.md on GitHub.
Security
- Security scanPassed, 100 of 100Pattern checks on the skill's files.
- Model reviewNot runA model review is scheduled for the next rescan.
Quality evaluation
- Task evaluationNot runNo evaluation yet. Run one in Skill Studio.
Source
- SKILL.md in the repositoryChecking.github/skills/zpl-diff-auto-fix/SKILL.md
Popularity
- Repository stars
- 52
- Repository forks
- 24
- 7-day trend score
- 20
Stars and forks are for the whole GitHub repository, not this skill alone. Not refreshed yet.
Works with
Any agent vskill installs to: 56 targets in all. These 39 have a page on this site.
- Claude Code
- Cursor
- GitHub Copilot
- Windsurf
- Codex
- Gemini CLI
- Cline
- Amp
- Roo Code
- Goose
- Continue
- Kilo Code
- Junie
- Trae
- OpenHands
- Qwen Code
- AI Agent
- Tabnine Chat
- Sourcegraph Cody
- Amazon Q
- Firebase Genkit
- Sweep
- Devin
- Phind
- Mentat
- Claude Desktop
- Aider
- GPT Pilot
- Plandex
- bolt.new
- v0
- Replit Agent
- Anse
- TypingMind
- BetterChatGPT
- LibreChat
- Warp AI
- Pieces
- Fig AI
Embed badge
[](https://verified-skill.com/skills/goodboy008/labelize/zpl-diff-auto-fix)