npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

kicadiff

v0.2.0

Published

Visual diff tool for KiCad PCB and schematic files

Readme

kicadiff

Visual diff tool for KiCad projects — see what changed between two states of a .kicad_pcb / .kicad_sch / .kicad_sym / .kicad_mod file in your browser, or as a markdown report you can paste into a PR.

日本語版 README

kicadiff demo

What you get

  • HTML viewer with side-by-side / overlay / swipe modes, layer toggles for PCBs, page navigation for hierarchical schematics, wheel-to-zoom and right-click-drag-to-pan, and an amber tab marker on files / pages whose rendered output actually changed.

  • Markdown report (--md) with side-by-side image tables and a structural component diff (added / removed / changed by reference designator), plus — for PCBs — a Nets subsection that lists added / removed nets and pads that were rewired (R1.2: GND → /VCC). Pad transitions to or from the unconnected net are surfaced too (R7.1: (unconnected) → +3V3). Both legacy ((net id "name")) and KiCad 10 ((net "name"), no top-level net table) shapes are supported. Good for PR descriptions and commit messages.

  • Text-only structural diff (--text-only) — fast, no image rendering, prints to stdout. Includes the same Nets subsection for PCBs so routing changes show up in CI logs and grep:

    blink.kicad_pcb (pcb): +0 -0 ~1 =3
      ~ R1  value: 330 → 470
      Nets: +1 -0 ~2
        + /LED_OUT
        ~ R1.2: GND → /LED_OUT
        ~ R7.1: (unconnected) → +3V3
  • DRC / ERC violation diff (kicadiff check) — runs design-rule and electrical-rule checks on both sides and reports the delta as +N new / -M fixed / =K unchanged. Exits 1 when the target side introduces NEW violations (non-zero on operational failures too — missing kicad-cli, git errors, JSON parse errors), so it makes a good PR gate that fails on regressions while ignoring pre-existing findings.

Requirements

  • kicad-cli 9.x or later (rendering engine).
  • Bun — runs the TypeScript CLI directly via shebang. Bun also compiles the standalone binary, so no separate Node install is needed for any workflow. Standalone binary users skip this.

The render pipeline (SVG → PNG, tri-colour pixel diff highlight) used to need rsvg-convert and ImageMagick; both are now in-process (@resvg/resvg-js for rasterisation, a small custom classifier on top of pngjs for the diff overlay).

Install

Three ways depending on what's already on your machine:

# 1. One-shot via Bun's package runner (no install)
bunx kicadiff [args...]

# 2. Global install (puts `kicadiff` on PATH)
pnpm add -g kicadiff
# or with `bun add -g kicadiff` / `npm install -g kicadiff`

# 3. Standalone binary — single file, no Bun runtime needed.
#    Drops `kicadiff` into ~/.local/bin (override with KICADIFF_INSTALL_DIR).
curl -fsSL https://raw.githubusercontent.com/sksat/kicadiff/main/install.sh | sh

kicad-cli (and rsvg-convert / magick) are not bundled — install KiCad 9+ first, then pick whichever kicadiff distribution form fits your workflow.

Usage

kicadiff works on the same positional argument shape as git diff, plus a few subcommands when you want to scope to one file type.

# Project-level diff (cwd, both PCB and schematic, default = index vs working
# tree — same as `git diff`)
kicadiff

# Pass a project root, a .kicad_pro, or any single KiCad file
kicadiff path/to/project/
kicadiff project.kicad_pro
kicadiff project.kicad_pcb

# Staged changes only (same as `git diff --cached` / `git diff --staged`)
kicadiff --cached project/
kicadiff --staged project/             # alias

# Compare arbitrary refs
kicadiff HEAD path/to/project/         # working tree vs HEAD (includes staged)
kicadiff main path/to/project/         # working tree vs main
kicadiff v1.0 v2.0 board.kicad_pcb     # v1.0 vs v2.0
kicadiff main..feat foo.kicad_pcb      # range syntax
kicadiff main -- foo.kicad_pcb         # explicit `--` separator
kicadiff :0 project/                   # explicit index ref (alias: index / staged)

# Subcommands scope to one file type (skip sibling auto-detect)
kicadiff pcb foo.kicad_pcb
kicadiff sch foo.kicad_sch       # alias: schematic
kicadiff sym lib.kicad_sym       # alias: symbol
kicadiff fp foo.kicad_mod        # alias: footprint
kicadiff fp lib.pretty           # whole .pretty/ library

# Output formats
kicadiff project/                       # default: HTML viewer + images
kicadiff project/ --md                  # markdown report + images, no HTML
kicadiff project/ --md --output report.md
kicadiff project/ --md --output -       # markdown to stdout, logs to stderr
kicadiff project/ --text                # also print structural text diff
kicadiff project/ --text-only           # text only, skip rendering (fast)
kicadiff project/ --images-only         # PNGs only, no HTML / markdown

# Custom markdown templates (Mustache subset: {{var}}, {{#section}}…{{/section}},
# {{^inverted}}…{{/inverted}}). Project template sees from_label / to_label /
# file_count / has_changes / files / file_sections. File template sees path /
# type / before_image / after_image / has_both / after_only / before_only /
# added_count / removed_count / changed_count / unchanged_count /
# nets_added / nets_removed / nets_changed (pcb only) /
# has_structural_diff (real component OR net changes) / has_visual_diff (PNGs
# differ) / has_changes (any of the above) / structural_diff (formatted body). Either
# flag is optional; the default template ships built-in.
kicadiff project/ --md --md-template my-report.md.tpl
kicadiff project/ --md --md-file-template my-file.md.tpl

# Auto-open the HTML in VSCode (Live Preview), a browser, etc.
kicadiff project/ --open vscode
kicadiff project/ --open firefox
kicadiff project/ --open=/usr/bin/open  # arbitrary command

# Watch mode — re-render every time an input file changes. Hot reload comes
# from the viewer: VSCode Live Preview / live-server / similar will refresh
# the page automatically once kicadiff overwrites the images. For plain
# file:// browsers, kicadiff injects a tiny image-polling script so the
# rendered images update in place without needing F5.
kicadiff project/ --watch
kicadiff project/ --watch --open vscode

# Other
kicadiff project/ -v                    # verbose summary (full PNG paths)
kicadiff project/ -q                    # suppress summary
kicadiff project/ --no-cache            # bypass the render cache
kicadiff project/ --exit-code           # exit 1 if any change (mirrors `git diff --exit-code`)

# Claude Code PostToolUse hook integration. Reads the hook JSON from
# stdin, renders only when the edited file is .kicad_pcb / .kicad_sch.
# Default: --open vscode (override with --open <target> as usual).
kicadiff hook

# DRC / ERC violation diff — third fast-path mode alongside --text-only.
# Runs `kicad-cli pcb drc` (PCB) / `kicad-cli sch erc` (schematic) on both
# sides and reports the delta as +N new / -M fixed / =K unchanged. Exits 1
# when NEW violations are introduced on the target side; pre-existing
# violations that persist do not fail the gate. Operational failures
# (missing kicad-cli, git errors, JSON parse errors) also produce a
# non-zero exit. Useful as a PR gate that fails only on regressions,
# independent of any visual diff.
kicadiff check                          # PCB+sch in cwd, index vs working
kicadiff check HEAD project/            # working tree vs HEAD
kicadiff check main..feat foo.kicad_pcb # main vs feat, PCB only

Output

By default kicadiff writes to <repo>/.claude/preview/ (next to the git root) so the directory is easy to find from the project. Override with --output-dir <dir> for the image directory, and --output <path> to relocate the HTML / markdown file specifically (image paths in the file get rewritten to be relative to it, so the file stays portable).

The HTML viewer is a single file with the manifest + image references inline; you can email it, host it as a static asset, or open it locally with VSCode's Live Preview extension.

Render cache

Every per-side render is content-addressed and cached under $XDG_CACHE_HOME/kicadiff (or ~/.cache/kicadiff). Repeat runs against unchanged content return in ~1 s vs ~5 s cold. Bypass with --no-cache or override the location with KICADIFF_CACHE_DIR.

The cache grows monotonically — every kicad-cli version bump and every content edit adds a new entry, and nothing is evicted automatically. Inspect and reclaim space with the cache subcommand:

# Show cache directory, entry count, total size, and oldest / newest age
kicadiff cache stats

# Delete entries older than a cutoff (units: s/m/h/d, unit required)
kicadiff cache prune --older-than 30d
kicadiff cache prune --older-than 30d --dry-run    # preview, change nothing

# Wipe the whole cache (recursive rm of the cache root — any stray files
# at the root go too, not just registered entries). `--yes` skips the
# confirmation prompt and is required in non-TTY (CI) environments so
# the prompt can never hang a build. As a safety net, `--all` refuses
# to run unless the cache root contains a `.kicadiff-cache` marker
# (auto-dropped on first cache write and on any `cache stats` /
# read) — that way a misconfigured `KICADIFF_CACHE_DIR` can't silently
# wipe an unrelated directory. For a pre-existing cache from before
# this marker was introduced, run `kicadiff cache stats` once to
# install the marker, then retry `--all`. Use `rm -rf` manually if
# you really mean to delete such a directory.
#
# Note: `cache stats` does NOT recurse into foreign top-level
# directories (anything whose name doesn't match the cache layout's
# 2-char hex bucket pattern). Their bytes are excluded from "Total
# size" — a misconfigured `KICADIFF_CACHE_DIR` (e.g. `$HOME`) won't
# make `stats` walk a huge unrelated tree. `--all` will still wipe
# the entire cache root, so it may reclaim more than `stats` reports.
kicadiff cache prune --all --yes

GitHub Actions

Drop the action into a workflow to render a visual diff for every PR that touches a KiCad file. The action handles KiCad install, runs kicadiff, and (opt-in) uploads the rendered images as a build artifact, writes a job summary with inline before/after images, upserts a sticky PR comment, and updates a marked section in the PR description.

# .github/workflows/kicad-diff.yml
name: KiCad visual diff
on:
  pull_request:
    paths: ["**/*.kicad_pcb", "**/*.kicad_sch"]
permissions:
  contents: read
  pull-requests: write   # only needed for pr-comment / pr-description
jobs:
  diff:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v6
        with: { fetch-depth: 0 }
      - uses: sksat/[email protected]
        with:
          path: hardware/main-board   # default: cwd
          upload-artifact: 'true'
          pr-comment:      'true'
          pr-description:  'true'

Job summary embeds combined PNGs as base64 data URIs (no extra hosting needed) up to a 1 MiB cap; if a project's images would overflow, the action drops the rest, emits ::warning::, and links to the artifact for the full set. PR comment / description are kept text-only and link to the artifact for images.

install-kicadiff: bunx (default) pulls the latest published kicadiff on demand; pin a version with install-kicadiff: <semver>. Pre-installed on PATH? Use install-kicadiff: skip.

More

  • DESIGN.md — architecture, render pipeline, cache key shape, manifest schema, viewer mode semantics
  • examples/blink/ — minimal KiCad project used as the test fixture and a usable starting point. Ships with a .claude/settings.json PostToolUse hook (kicadiff hook) that re-renders the diff every time a .kicad_pcb / .kicad_sch is Edited / Written.
  • examples/mcu-board/ — a more realistic small-board layout: an 8-pin MCU stand-in with the usual stuff around it (5 V → 3.3 V AMS1117 LDO, decoupling caps, reset switch with pull-up, status LED, and a 6-pin programming/breakout header). Hierarchical schematic — root for the power chain and MCU itself, peripherals.kicad_sch sub-sheet for the reset/LED/header — so the per-page tabs in the viewer have something to switch between.