How to Troubleshoot Rendering Issues with lint-render.py

lint-render.py is a headless-Chromium based linter that validates HTML examples in the cathrynlavery/diagram-design repository by rendering pages and comparing authored versus released screenshots to detect clipping, overflow, and missing assets.

When diagrams fail visual validation in the cathrynlavery/diagram-design repository, understanding how to troubleshoot rendering issues with lint-render.py requires tracing its three-stage execution pipeline. The script located at scripts/lint-render.py uses Playwright to isolate network dependencies, measure SVG bounding boxes, and perform pixel-perfect diffs to ensure design integrity. Mastering its error signatures and environment requirements allows you to quickly resolve false positives and actual rendering defects.

Understanding the lint-render.py Architecture

The linter operates through a strict sequence of browser isolation, DOM measurement, and visual comparison. Each stage contains specific failure modes that produce distinct error signatures.

Browser Launch and Network Isolation

The script initializes by creating a Playwright Chromium context via launch at lines 10-19. Immediately, the block_network function at lines 22-41 enforces strict network isolation using a resolver_rule at lines 30-36 that blocks all external hostnames. This guarantees only local assets from ASSET_DIR (defined at lines 86-88) are loaded. If Playwright cannot locate the bundled Chromium binary, the script aborts early with error messages at lines 99-106.

Page Rendering and Measurement

For each HTML file processed, the execution follows this exact sequence:

  • page.goto at lines 94-95 loads the target asset
  • SURVEY_JS (lines 16-45) inventories every <svg> element in the DOM
  • RELEASE_JS (lines 84-110) programmatically removes overflow constraints from the SVG and its clipping ancestors
  • shoot at lines 65-69 captures two screenshots: the authored state and the released state
  • DIFF_JS (lines 26-61) performs pixel-by-pixel comparison to detect ink spilling outside the released bounds

Reporting and Self-Verification

Findings are classified into categories such as clipped, page-overflow, svg-collapsed, and unmeasurable within the clipping_findings logic at lines 13-74. The --self-test flag triggers the self_test routine at lines 99-176 to validate the detection logic, DOM restoration, and network isolation integrity before processing actual assets.

Diagnosing Common Rendering Failures

Match the symptom to the specific code path generating the error to troubleshoot rendering issues with lint-render.py effectively.

render-error with traceback: Indicates Playwright crashed or the HTML contains runtime JavaScript errors. Inspect exception handling around check at lines 21-23 to isolate the failure.

page-overflow reported: The document width exceeds the viewport dimensions defined in VIEWPORT at lines 89-90. The detection logic resides in PAGE_OVERFLOW_JS at lines 15-20. Verify your CSS does not force fixed widths exceeding the default 1600×1000 pixel canvas.

clipped findings: Content spills outside the SVG boundaries or a clipping ancestor. Review the diff logic in DIFF_JS (lines 26-61) and the release stages in clipping_findings to identify which ancestor is trapping content.

unmeasurable due to scrolling ancestor: A parent element has scrollable overflow, preventing accurate bounding box calculation. The early exit logic at lines 23-30 of clipping_findings aborts measurement to avoid false positives. Remove scrolling from parent containers or restructure the HTML.

missing-asset errors: Local images or scripts failed to load. Inspect on_request_failed in the watch function at lines 56-60 to identify broken relative paths in skills/diagram-design/assets/.

Self-test failures: Indicates corrupted linting logic or environment misconfiguration. Run python3 scripts/lint-render.py --self-test (entry point at lines 99-106) to determine whether the issue lies in the linter itself or the target assets.

Fixing Environment and Configuration Issues

Many rendering issues originate from environment setup rather than code defects.

Playwright Installation and Chromium Versions

If the script exits with code 2 indicating environment errors, verify Playwright is installed correctly. The script prints installation hints at lines 81-87. Execute:

pip install playwright && playwright install chromium

For consistent results between local and CI environments, align your Playwright version with the pinned version in .github/workflows/ci.yml. Version mismatches between local Chromium and CI Chromium often produce subtle pixel differences in DIFF_JS comparisons.

Font Rendering and Network Isolation

By default, lint-render.py blocks all external hostnames via RESOLVER_RULE at lines 6-7 to prevent network dependencies. If diagrams rely on Google Fonts for accurate typography measurement, enable them with the --fonts flag (argument parsing at lines 64-78). If you encounter unexpected "network-isolation" failures, verify RESOLVER_RULE remains intact and no environment variables override the resolver configuration.

Practical Debugging Commands

Use these specific invocations to isolate different classes of rendering issues:


# Render all examples with default 1600×1000 viewport

python3 scripts/lint-render.py --all

# Test a single file quietly to isolate specific failures

python3 scripts/lint-render.py path/to/example.html --quiet

# Enable web fonts for accurate typography measurement

python3 scripts/lint-render.py --fonts --all

# Verify the linter's own detection logic is functioning

python3 scripts/lint-render.py --self-test

Exit codes indicate result severity: 0 for no findings, 1 for detected issues requiring fixes, and 2 for usage or environment errors (see main return values at lines 95-106).

Summary

  • lint-render.py uses Playwright to render HTML assets and detect visual clipping through pixel comparison in DIFF_JS (lines 26-61)
  • Network isolation via resolver_rule (lines 30-36) and block_network (lines 22-41) ensures reproducible local rendering without external dependencies
  • Common failures include render-error (Playwright crashes), page-overflow (viewport mismatches in VIEWPORT at lines 89-90), and clipped (content spillage)
  • The --self-test flag validates the linter's internal logic through self_test at lines 99-176
  • Environment issues often resolve by matching the CI Playwright version in .github/workflows/ci.yml and ensuring Chromium is installed via playwright install chromium

Frequently Asked Questions

Why does lint-render.py fail with a Playwright installation error even after I installed the Python package?

The script requires both the Python package and the browser binaries. As indicated at lines 81-87 of scripts/lint-render.py, you must run playwright install chromium after pip install playwright to download the bundled Chromium binary that the launch function at lines 10-19 expects to locate in the system path.

How do I fix false positives for page-overflow errors?

Check the VIEWPORT constant at lines 89-90, which defaults to 1600×1000 pixels. If your diagram's natural width exceeds these dimensions, either refactor the CSS or modify the viewport configuration. The detection occurs in PAGE_OVERFLOW_JS at lines 15-20, which flags any content exceeding these bounds.

What causes unmeasurable findings in the lint-render.py output?

This occurs when an ancestor element has overflow: scroll or overflow: auto, preventing the script from calculating accurate bounding boxes. The early exit logic at lines 23-30 of clipping_findings aborts measurement to avoid false positives. Remove scrolling properties from parent containers or adjust the HTML structure to eliminate scrolling ancestors.

Can I allow external resources like Google Fonts during rendering?

Yes. By default, RESOLVER_RULE at lines 6-7 blocks all hostnames, but the --fonts flag (parsed at lines 64-78) explicitly enables Google Font hosts while maintaining isolation for other domains. Use this flag when text metrics affect your visual diff results, but ensure you do not introduce network-dependent assets that would fail in CI environments.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →