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

@mikeyfrilot/websketch-ir

v0.1.0

Published

Grammar-based web UI representation for LLM consumption. Stop treating webpages like pictures.

Readme

@websketch/ir

"Stop treating webpages like pictures."

A grammar-based representation of web UI for LLM consumption. Instead of screenshots, WebSketch IR captures the intent and structure of a webpage in a compact, deterministic format that LLMs can reason about directly.

Why?

Current AI browser agents rely on:

  • Screenshots - expensive, lossy, requires vision models
  • Raw DOM - verbose, framework noise, hard to reason about

WebSketch IR compiles the DOM into a small vocabulary of UI primitives (NAV, FORM, BUTTON, INPUT, etc.) with normalized geometry. The result is:

  • Invariant - stable across CSS changes, framework differences, viewport sizes
  • Compact - ~100x smaller than screenshots
  • Readable - ASCII rendering an LLM can understand without vision

Installation

npm install @websketch/ir

Quick Example

import { renderAscii, diff, fingerprintCapture } from '@websketch/ir';

// Load a capture (from browser extension or other source)
const capture = JSON.parse(fs.readFileSync('capture.json', 'utf-8'));

// Render to ASCII (LLM-readable)
console.log(renderAscii(capture));

// Output:
// ┌──────────────────────────────────────────────────────────────────────────────┐
// │[NAV:primary_nav]                                                             │
// ├──────────────────────────────────────────────────────────────────────────────┤
// │                    ┌────────────────────────────────────────┐                │
// │                    │[FRM:login]                             │                │
// │                    │  [INP:email]                           │                │
// │                    │  [INP:password]                        │                │
// │                    │  [BTN:primary_cta]                     │                │
// │                    └────────────────────────────────────────┘                │
// └──────────────────────────────────────────────────────────────────────────────┘

// Compare two captures
const result = diff(captureA, captureB);
console.log(result.summary);
// { added: 2, removed: 0, moved: 3, resized: 1, text_changed: 1 }

// Get structural fingerprint
console.log(fingerprintCapture(capture));
// "e33442b6"

API

Rendering

// ASCII rendering (default 80x24)
renderAscii(capture, options?)

// LLM-optimized format with metadata and legend
renderForLLM(capture)

// Minimal structure-only view
renderStructure(capture, width?, height?)

Fingerprinting

// Full structural fingerprint (includes text)
fingerprintCapture(capture)

// Layout-only fingerprint (ignores text changes)
fingerprintLayout(capture)

Diffing

// Compare two captures
const result = diff(captureA, captureB, {
  includeText: true,      // Include text changes (default: true)
  matchThreshold: 0.5,    // Node matching threshold (default: 0.5)
  topChangesLimit: 10,    // Max top changes to return (default: 10)
});

// Human-readable diff report
formatDiff(result)

// JSON output
formatDiffJson(result)

Grammar

WebSketch IR uses a small vocabulary of UI primitives:

| Role | Description | |------|-------------| | PAGE | Root container | | NAV | Navigation (sidebar, navbar, menu) | | HEADER | Page/section header | | FOOTER | Page/section footer | | SECTION | Generic content section | | FORM | Form container | | LIST | Repeated items | | CARD | Content card/tile | | TABLE | Tabular data | | MODAL | Modal dialog | | TOAST | Notification | | INPUT | Text input | | BUTTON | Action trigger | | LINK | Navigation trigger | | DROPDOWN | Select/menu | | CHECKBOX | Boolean toggle | | RADIO | Single-select option | | IMAGE | Visual content | | TEXT | Text block |

Capture Format (v0.1)

interface WebSketchCapture {
  version: "0.1";
  url: string;
  timestamp_ms: number;
  viewport: {
    w_px: number;
    h_px: number;
    aspect: number;
  };
  compiler: {
    name: string;
    version: string;
    options_hash: string;
  };
  root: UINode;
}

interface UINode {
  id: string;
  role: UIRole;
  bbox: [x: number, y: number, w: number, h: number]; // 0-1 normalized
  visible: boolean;
  interactive: boolean;
  semantic?: string;      // e.g., "login", "search", "primary_cta"
  text?: TextSignal;      // hash + length, not content
  children?: UINode[];
}

Related Packages

Design Principles

  1. Rendered layout is truth - use getBoundingClientRect, not DOM positions
  2. UI intent > DOM structure - compile to small primitive vocabulary
  3. Normalize aggressively - remove stylistic noise; keep geometry + interactivity
  4. Stable under "div soup" - framework wrappers collapse automatically

License

MIT

Author

MCP Tool Shop