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

uisnap

v0.2.3

Published

CLI debugging tool designed for AI coding agents. Captures browser state to disk for token-efficient analysis. Works with Claude Code, Cursor, and other AI assistants.

Readme

uisnap

CLI debugging tool designed for AI coding agents

Stop having your AI assistant repeatedly reload pages and parse megabytes of DOM. Capture browser state once, query efficiently many times.

Why uisnap?

When AI agents debug frontend issues, they typically:

  1. 🔴 Load the full page HTML (~15K tokens)
  2. 🔴 Parse console logs (~8K tokens)
  3. 🔴 Analyze network requests (~5K tokens)
  4. 🔴 Repeat for every question

uisnap changes this:

  1. ✅ Capture once: ~2K tokens
  2. ✅ Query many times: ~200 tokens each
  3. 17x token reduction

Philosophy

Capture once, query many - Expensive browser operations write to disk once. Cheap local queries analyze data repeatedly without re-running the browser.

Built for: Claude Code, Cursor, Aider, and other AI coding assistants.

Installation

Requirements

  • Node.js 18, 20, or 22 LTS (recommended)
  • Node.js 24 may work but is untested
  • Node.js 25+ is not supported (duckdb lacks pre-built binaries)

1. Install the CLI tool

npm install -g uisnap
npx playwright install chromium

2. Install Claude Code Skill (Recommended for Claude Code users)

Teach Claude when and how to use uisnap automatically:

# Project-level (recommended - commit to git for team sharing):
uisnap setup-skill
git add .claude/skills/

# Or user-level (personal use only):
uisnap setup-skill --global

Once installed, Claude Code will automatically know:

  • ✅ When to capture browser state vs. parse HTML
  • ✅ How to use each analysis command
  • ✅ Best practices for token-efficient debugging

Without the skill: You'll need to manually tell Claude which commands to use.

With the skill: Just say "debug console errors on example.com" and Claude handles the rest.

See SKILL-INSTALLATION.md for details.

Quick Start

# Capture page state (auto-generates timestamped directory)
uisnap snapshot https://example.com

# Analyze the latest snapshot using the "latest" symlink
uisnap analyze-console snapshots/example.com/latest/console.jsonl
uisnap analyze-network snapshots/example.com/latest/network.jsonl
uisnap query-a11y snapshots/example.com/latest/a11y.yaml --links

# Or specify explicit path for baselines/comparisons
uisnap snapshot https://example.com snapshots/baseline/

Commands

Capture Commands

Snapshot - Capture full page state:

uisnap snapshot <url> [output-dir]

If output-dir is omitted, auto-generates: snapshots/{hostname}/{timestamp}/

Chrome Performance Trace - Capture browser performance metrics:

uisnap exec chrome-perf-trace.js <url> [output-dir]

Captures Chrome DevTools performance trace with automatic DuckDB import. Analyzes paint, layout, JavaScript execution, and other browser internals.

Auto-generated structure:

snapshots/
├── example.com/
│   ├── 2025-12-25-143052/
│   ├── 2025-12-25-144315/
│   └── latest -> 2025-12-25-144315/  (symlink to most recent)
└── myapp.com/
    └── ...

Each snapshot captures:

  • a11y.yaml - ARIA accessibility snapshot
  • console.jsonl - Console messages (one JSON per line)
  • network.jsonl - Network requests (one JSON per line)
  • metadata.json - Page metadata (title, URL, viewport, timestamp)

Exec - Execute custom scripts for multi-step flows or custom data extraction:

uisnap exec <script.js> <url> [output-dir]

If output-dir is omitted, auto-generates: snapshots/{hostname}/{script-name}-{timestamp}/

Scripts have access to:

  • page, context, browser - Playwright instances
  • utils.captureStep(page, name, action) - Auto-capture steps with numbering
  • utils.writeJson, writeJsonl, appendJsonl - Data writing helpers
  • fs, path - Node.js modules
  • args - Remaining command-line arguments

Analysis Commands

Analyze Console:

uisnap analyze-console <console.jsonl>

Provides:

  • Message counts by type (error, warning, log)
  • Grouped errors with counts and locations
  • Grouped warnings with counts and locations

Analyze Network:

uisnap analyze-network <network.jsonl>

Provides:

  • Request counts by resource type, method, status
  • Failed requests (4xx, 5xx)
  • Slow requests (>1s)
  • Requests by domain

Query A11y:

uisnap query-a11y <a11y.yaml> <query>

Queries:

  • --buttons - List all buttons
  • --links - List all links
  • --headings - List all headings
  • --inputs - List all input fields
  • --interactive - List all interactive elements
  • --images - List all images
  • <text> - Search by text content

Analyze Chrome Trace:

uisnap trace-analyze <trace.db> [options]

Options:

  • --long-tasks - Show tasks over threshold (default: 50ms)
  • --js-time - Show JavaScript execution time breakdown
  • --layout-paint - Show layout and paint performance
  • --threshold=N - Set threshold in ms (default: 50)
  • --full - Show all details

Progressive disclosure: Default shows summary with hints for next steps.

Import Chrome Trace (manual import if needed):

uisnap trace-import <trace.json> <output.db>

Imports Chrome DevTools trace JSON into queryable DuckDB database. Usually not needed since chrome-perf-trace.js auto-imports.

Example Workflow

Basic Debugging

# 1. Capture page state (creates timestamped snapshot)
uisnap snapshot https://myapp.com

# 2. Check for errors (use "latest" for convenience)
uisnap analyze-console snapshots/myapp.com/latest/console.jsonl

# 3. Check network failures
uisnap analyze-network snapshots/myapp.com/latest/network.jsonl

# 4. Find the submit button
uisnap query-a11y snapshots/myapp.com/latest/a11y.yaml "Submit"

# 5. Make fixes, capture again - never overwrites!
uisnap snapshot https://myapp.com

# 6. Analyze latest results
uisnap analyze-console snapshots/myapp.com/latest/console.jsonl

Iterative Debugging

The auto-timestamped structure is perfect for iterative debugging:

# First attempt
uisnap snapshot https://myapp.com
# Creates: snapshots/myapp.com/2025-12-25-143052/

# Make code changes...

# Second attempt
uisnap snapshot https://myapp.com
# Creates: snapshots/myapp.com/2025-12-25-144315/

# "latest" always points to most recent
uisnap query-a11y snapshots/myapp.com/latest/a11y.yaml --buttons

# View history
ls snapshots/myapp.com/
# 2025-12-25-143052/
# 2025-12-25-144315/
# latest -> 2025-12-25-144315/

Regression Testing

# Before deployment (use explicit path for baseline)
uisnap snapshot https://myapp.com snapshots/baseline/

# After deployment (auto-generated)
uisnap snapshot https://myapp.com

# Compare baseline vs latest (TODO: implement compare command)
# compare snapshots/baseline/ snapshots/myapp.com/latest/

Performance Analysis

Initial page load:

# Snapshot captures everything including Chrome trace
uisnap snapshot https://myapp.com
uisnap diagnose snapshots/myapp.com/latest/ --performance

Continuous tracing (scroll, animations, interactions):

# Use the scroll-perf example or write your own
uisnap exec examples/scroll-perf-trace.js https://myapp.com

# 2. Start with summary
uisnap trace-analyze snapshots/myapp.com/latest/chrome-trace.db
# Shows: Total tasks, duration, hints for next steps

# 3. Identify long blocking tasks
uisnap trace-analyze snapshots/myapp.com/latest/chrome-trace.db --long-tasks
# Shows: Tasks over 50ms with timestamps

# 4. Analyze JavaScript execution
uisnap trace-analyze snapshots/myapp.com/latest/chrome-trace.db --js-time
# Shows: JS execution breakdown by type (total, avg, max)

# 5. Check layout/paint performance
uisnap trace-analyze snapshots/myapp.com/latest/chrome-trace.db --layout-paint
# Shows: Layout and paint operation counts and timings

# 6. See everything at once
uisnap trace-analyze snapshots/myapp.com/latest/chrome-trace.db --full

# 7. Custom queries with DuckDB (advanced)
duckdb snapshots/myapp.com/latest/chrome-trace.db
> SELECT name, dur_ms FROM tasks WHERE name LIKE '%Paint%' ORDER BY dur_ms DESC LIMIT 10;

Custom Scripts

Multi-Step Flows

Use utils.captureStep() for multi-step interactions with automatic capture:

// login-flow.js
// Usage: uisnap exec login-flow.js https://myapp.com

// Step 1: Navigate
await utils.captureStep(page, 'goto-login', async () => {
  await page.goto('https://myapp.com/login');
});

// Step 2: Fill email (using Playwright's role-based selectors)
await utils.captureStep(page, 'fill-email', async () => {
  await page.getByLabel('Email').fill('[email protected]');
});

// Step 3: Submit
await utils.captureStep(page, 'click-submit', async () => {
  await page.getByRole('button', { name: 'Submit' }).click();
});

Creates:

snapshots/myapp.com/login-flow-2025-12-25-143052/
├── step-1-goto-login/
│   ├── a11y.yaml
│   └── metadata.json
├── step-2-fill-email/
│   └── ...
└── step-3-click-submit/
    └── ...

Simple Data Extraction

For custom data extraction without step capture:

// extract-data.js
await page.goto('https://example.com');

const data = await page.evaluate(() => {
  return {
    links: Array.from(document.links).map(l => l.href),
    headings: Array.from(document.querySelectorAll('h1')).map(h => h.textContent),
  };
});

utils.writeJson('data.json', data);

Output Formats

ARIA Snapshot (YAML)

- heading "Example Domain" [level=1]
- paragraph: This domain is for use in examples.
- link "Learn more":
  - /url: https://iana.org/domains/example

Console Logs (JSONL)

{"timestamp":"2025-12-25T10:30:00.000Z","type":"error","text":"Failed to load","location":{"url":"https://example.com/app.js","lineNumber":42}}
{"timestamp":"2025-12-25T10:30:01.000Z","type":"log","text":"User clicked submit","location":{"url":"https://example.com/app.js","lineNumber":100}}

Network Requests (JSONL)

{"url":"https://api.example.com/users","status":200,"statusText":"OK","method":"GET","resourceType":"fetch","timing":{"startTime":1234.5,"responseEnd":1456.7}}
{"url":"https://api.example.com/submit","status":500,"statusText":"Internal Server Error","method":"POST","resourceType":"fetch"}

Token Efficiency

Traditional approach:

  • Full DOM: ~15,000 tokens
  • Console logs: ~8,000 tokens
  • Screenshots: ~10,000 tokens
  • Total: ~40,000 tokens

This toolkit:

  • Capture to disk: ~2,000 tokens (one-time)
  • Analyze summaries: ~100 tokens
  • Query results: ~200 tokens
  • Total: ~2,350 tokens (~17x reduction)

Chrome performance traces:

  • Raw 36MB trace JSON: ~9,000,000 tokens
  • DuckDB import: ~100 tokens (one-time)
  • Canned query results: ~100-500 tokens
  • Total: ~600 tokens (~18,000x reduction)

Development

# Clone and install
git clone https://github.com/tonyhschu/uisnap
cd uisnap
npm install

# Build
npm run build

# Test locally
node dist/pw.js snapshot https://example.com test-output/

# Deploy skill to local Claude Code
./deploy-skill.sh

Local Deployment Script

The deploy-skill.sh script copies the skill to ~/.claude/skills/ making it available to all Claude Code instances on your machine:

./deploy-skill.sh

This removes any existing version and installs the latest skill instructions.

License

MIT

Contributing

See .claude/skills/uisnap/SKILL.md for guidance on working with this codebase in Claude Code.

For detailed reference: