goodboy008/labelize/zpl-diff-auto-fix

Claude Code and agent skill by goodboy008/labelize

Trust tier 2
  • community
LLM review pending
Source check pending

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-fix

SKILL.md

ZPL Diff Auto-Fix Skill

Other languages: EPL uses renderer-baseline goldens (no external
reference renderer) — the analyze/fix phases still apply with
parsers/epl/ as the fix surface. TSPL, CPCL and DPL each have their
own 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 the
relevant 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:

  1. The diff report is up to date: cargo test --test e2e_diff_report -- --nocapture
  2. All current tests pass: cargo test
  3. You have reference PNG images in testdata/ for the target label(s)

Procedure

Phase 1: Scan — Identify High-Diff Labels
  1. Read the diff report from label report and unit report
  1. Read the tolerance thresholds from docs/DIFF_THRESHOLDS.md
  1. 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
  1. 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
  1. Read the ZPL source from testdata/labels/<name>.zpl or testdata/unit/<name>.zpl
  1. 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 ``

  1. Inspect the diff image at testdata/diffs/<name>_diff.png — red pixels show where rendering differs from Labelary
  1. 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
  1. 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 diffFull-label bbox diffClassification
Low (< 2%)High (> 2%)PositionDiff — element placed wrong
High (> 2%)AnyContentDiff — 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
  1. 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 / ^XZ wrapper
  • Global state commands (^PW, ^CF, ^BY, ^CI, ^FW, ^PO, ^LR) preserved
  • The specific element's command span (^FO/^FT through ^FS)
  1. 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).

  1. 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.

  1. 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:

  1. Identify the element type, diff classification, and fix category:

Use FixCategory::from_classification(element_type, classification) to select the fix strategy:

ClassificationFix StrategyTarget Source Files
ContentDiff + TextFontMetricssrc/drawers/renderer.rs, src/elements/font.rs
ContentDiff + Barcode128BarcodeEncodingsrc/barcodes/code128.rs, src/drawers/renderer.rs
ContentDiff + BarcodeEan13BarcodeEncodingsrc/barcodes/ean13.rs
ContentDiff + Barcode2of5BarcodeEncodingsrc/barcodes/interleaved2of5.rs
ContentDiff + Barcode39BarcodeEncodingsrc/barcodes/code39.rs
ContentDiff + BarcodePdf417BarcodeEncodingsrc/barcodes/pdf417.rs
ContentDiff + BarcodeAztecBarcodeEncodingsrc/barcodes/aztec.rs
ContentDiff + BarcodeDatamatrixBarcodeEncodingsrc/barcodes/datamatrix.rs
ContentDiff + BarcodeQrBarcodeEncodingsrc/barcodes/qrcode.rs
ContentDiff + MaxicodeBarcodeEncodingsrc/barcodes/maxicode.rs
ContentDiff + GraphicBox/Circle/Line/FieldGraphicRenderingsrc/drawers/renderer.rs
PositionDiff (any element)PositionOffsetsrc/parsers/zpl_parser.rs, src/elements/field_alignment.rs, src/elements/drawer_options.rs
Mixed (any element)PositionOffset first, then ContentDiff fixBoth 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.

  1. Fetch the official Zebra documentation for the suspect ZPL command using the zpl-reference skill:

`` https://docs.zebra.com/us/en/printers/software/zpl-pg/c-zpl-zpl-commands/r-zpl-<slug>.html ``

  1. Compare spec vs implementation using the fix-zpl-render skill's Phase 3 comparison table
  1. Apply the fix to the relevant source file
  1. 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 ```

  1. Measure improvement:

``bash cargo test --test e2e_diff_report -- --nocapture `` Compare the new diff% against the previous value.

  1. If diff improved without regressions: Keep the change and proceed to the next element.
  1. If diff regressed on other labels: Revert the change and try a different approach.
  1. Repeat from step 14 for the next highest-contributing element.
Phase 5: Finalize — Update Thresholds and Report
  1. Update diff thresholds in docs/DIFF_THRESHOLDS.md:
  • Set new diff% values for improved labels
  • Set new tolerance ceilings slightly above the new diff%
  1. Regenerate diff images:

``bash cargo test --test e2e_diff_report -- --nocapture ``

  1. Run full test suite:

``bash cargo test ``

  1. 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%"):

1. Generate diff report
2. Sort labels by diff% descending
3. For each label above 1%:
a. Analyze element contributions
b. For each element (highest contribution first):
i. Extract standalone snippet
ii. Identify fix category
iii. Fetch Zebra spec for the command
iv. Compare spec vs implementation
v. Apply fix
vi. Build & test
vii. If regression: revert, try next element
viii.If improved: keep, re-measure
c. After all elements tried:
- If diff ≤ 1%: SUCCESS, move to next label
- If diff > 1% but improved: PARTIAL, record improvement
- If no improvement possible: SKIP (e.g., font metrics, library limitations)
4. Generate final report

Known Limitations

These labels cannot reach <1% diff due to fundamental limitations:

LabelBlockerReason
ups, ups_surepostMaxiCode encoderProprietary encoding, no compliant open-source encoder
fedexPDF417 encodingrxing encoder uses different compaction modes (valid but visually different)
aztec_ecAztec encodingrxing Aztec encoder differs in symbol sizing
pnldpdMultiple (Aztec + GFA + font)Compound issues from barcode encoding + font metrics
Most text-heavy labelsFont metricsHelvetica 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

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
vskill VERIFIED badge
[![vskill VERIFIED](https://verified-skill.com/api/v1/skills/goodboy008/labelize/zpl-diff-auto-fix/badge)](https://verified-skill.com/skills/goodboy008/labelize/zpl-diff-auto-fix)

Something wrong with this skill or its page? Tell us.