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

@01.works/diff-layer

v0.0.1-dev.0

Published

Event-driven browser overlay for visualizing AI-authored UI changes.

Downloads

97

Readme

@01.works/diff-layer

Event-driven browser overlay for visualizing UI changes authored by AI agents.

This package does not track React renders. It renders explicit change events provided by an app, AI tool, browser extension, or test harness.

Resolved changes render as persistent target outlines with compact AI markers. Click a marker or timeline item to inspect one selected change in the timeline panel. This keeps multiple nearby changes visible without stacking detail cards over the app.

Quick Start In Your App

Install the dogfood channel:

pnpm add @01.works/diff-layer@dev

1. Install the overlay in development

import { installAIChangeOverlay } from '@01.works/diff-layer/client';

installAIChangeOverlay({
  mutationRetryMs: 1000,
});

Without an explicit enabled option, the overlay installs only when runtime NODE_ENV is exactly development. Browser runtimes with no detectable NODE_ENV default to disabled. For those bundlers, pass the bundler's own development flag, such as enabled: import.meta.env.DEV in Vite.

2. Mark the UI you want to review

export function BillingSummary() {
  return (
    <section data-ai-id="billing-summary">
      <h2 data-ai-id="billing-title">Current plan</h2>
      <button data-ai-id="upgrade-cta">Upgrade</button>
    </section>
  );
}

Stable data-ai-id hooks make explicit AI change events easy to map back to visible UI without depending on brittle generated class names.

3. Push a change from an AI tool, extension, or test harness

window.__AI_CHANGE_OVERLAY__?.push({
  id: crypto.randomUUID(),
  source: 'ai',
  label: 'Upgrade CTA copy changed',
  selector: "[data-ai-id='upgrade-cta']",
  before: 'Upgrade',
  after: 'Compare plans',
  reason: 'Clarified that the next step shows plan options before purchase.',
  filePath: 'app/billing/page.tsx',
  line: 38,
  timestamp: Date.now(),
});

The event is explicit: the overlay shows what changed, where it changed, why it changed, and which source location is associated with the update.

window.dispatchEvent(
  new CustomEvent('ai-change-overlay:push', {
    detail: {
      id: crypto.randomUUID(),
      source: 'ai',
      label: 'Billing summary risk note added',
      selector: "[data-ai-id='billing-summary']",
      reason: 'Called out a plan limit that reviewers should verify.',
      filePath: 'app/billing/page.tsx',
      line: 52,
      timestamp: Date.now(),
    },
  }),
);

Use this path when the producer cannot import the package directly.

Public API

Root export:

import {
  CHANGE_OVERLAY_EVENT_NAME,
  CHANGE_OVERLAY_GLOBAL_NAME,
  getAIChangeOverlay,
  installAIChangeOverlay,
  registerChangeTarget,
  unregisterChangeTarget,
  type AIChangeOverlayGlobal,
  type ChangeEvent,
  type ChangeOverlayOptions,
  type ChangeSource,
  type CreateChangeEventInput,
  type PushChangeInput,
  type SourceLocation,
} from '@01.works/diff-layer';

Client export:

import {
  getAIChangeOverlay,
  installAIChangeOverlay,
} from '@01.works/diff-layer/client';

Options

| Option | Default | Description | | --- | --- | --- | | enabled | NODE_ENV === 'development' | Enables the overlay client. | | maxHistory | 20 | Maximum changes kept in the timeline. | | mutationRetryMs | 0 | How long to watch for targets that render after the event. | | root | document.body | DOM node that receives overlay and timeline elements. | | onOpenSource | undefined | Callback for the timeline source action. |

Change outlines and markers stay visible until the reviewer clears active overlays from the timeline or destroys the client. The selected change remains available in the timeline inspector while it is still in history. This package is a review aid for explicit AI-authored changes, not a transient render flash.

Change Event

type ChangeEvent = {
  id: string;
  source: 'ai' | 'manual' | 'system';
  label: string;
  selector?: string;
  componentName?: string;
  filePath?: string;
  line?: number;
  before?: string;
  after?: string;
  reason?: string;
  timestamp: number;
};

Malformed global or event payloads are ignored at runtime.

CustomEvent API

Non-importing producers can dispatch the event name directly:

window.dispatchEvent(
  new CustomEvent('ai-change-overlay:push', {
    detail: {
      id: crypto.randomUUID(),
      source: 'ai',
      label: 'Pricing card layout changed',
      selector: "[data-ai-id='pricing-card']",
      reason: 'Improved scanability of the primary plan',
      timestamp: Date.now(),
    },
  }),
);

Component Targets

Use component names when a component boundary is easier to identify than a selector:

import { registerChangeTarget } from '@01.works/diff-layer';

registerChangeTarget('BillingSummary', "[data-ai-id='billing-summary']");

Remove registrations when the target is no longer valid:

import { unregisterChangeTarget } from '@01.works/diff-layer';

unregisterChangeTarget('BillingSummary');

Queue Before Install

Events can be queued before installation by assigning the global to an array:

window.__AI_CHANGE_OVERLAY__ = window.__AI_CHANGE_OVERLAY__ ?? [];

if (Array.isArray(window.__AI_CHANGE_OVERLAY__)) {
  window.__AI_CHANGE_OVERLAY__.push({
    id: crypto.randomUUID(),
    source: 'ai',
    label: 'Billing title changed',
    selector: "[data-ai-id='billing-title']",
    before: 'Plan',
    after: 'Current plan',
    timestamp: Date.now(),
  });
}

Late Targets

Enable mutationRetryMs when events can arrive before the target is mounted:

installAIChangeOverlay({
  enabled: true,
  mutationRetryMs: 1000,
});

Source Hook

Clicking a rendered source action copies filePath or filePath:line to the clipboard by default. Provide onOpenSource when you also want the source action to open a trusted editor link.

Keep editor opening enabled only in development and only for trusted workspace-relative paths. Only a trusted local bridge that validates workspace containment should handle absolute paths.

installAIChangeOverlay({
  onOpenSource: (change) => {
    if (change.filePath === undefined) return;

    const workspaceRoot = '/absolute/path/to/your/project';
    const relativePath = change.filePath.replaceAll('\\', '/');

    if (
      relativePath.startsWith('/') ||
      relativePath.split('/').includes('..') ||
      /^[a-z][a-z0-9+.-]*:/i.test(relativePath)
    ) {
      return;
    }

    const absolutePath = `${workspaceRoot}/${relativePath}`;
    const suffix = change.line === undefined ? '' : `:${change.line}`;

    window.location.href = `vscode://file/${encodeURI(absolutePath)}${suffix}`;
  },
});

The callback runs after the copy attempt. Clipboard failures are ignored so a trusted editor-opening callback can still run.

Verification

pnpm --filter @01.works/diff-layer test
pnpm --filter @01.works/diff-layer typecheck
pnpm --filter @01.works/diff-layer build
pnpm --filter @01.works/diff-layer test:packaged

Dev-Tag Publishing

This package is configured for dogfood releases on npm's dev dist-tag:

pnpm version:dev
pnpm publish:dev

Every npm publish still needs a unique version. Consumers install the dogfood channel explicitly:

pnpm add @01.works/diff-layer@dev

Do not publish dogfood builds with the latest dist-tag.