
Research
/Security News
Miasma Mini Shai-Hulud Hits ImmobiliareLabs npm Packages
Miasma Mini Shai-Hulud hits @immobiliarelabs Backstage plugins, targeting GitLab and LDAP auth packages on npm.
@01.works/diff-layer
Advanced tools
Event-driven browser overlay for visualizing AI-authored UI changes.
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.
Install the dogfood channel:
pnpm add @01.works/diff-layer@dev
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.
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.
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.
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';
| 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.
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.
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(),
},
}),
);
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');
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(),
});
}
Enable mutationRetryMs when events can arrive before the target is mounted:
installAIChangeOverlay({
enabled: true,
mutationRetryMs: 1000,
});
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.
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
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.
FAQs
Event-driven browser overlay for visualizing AI-authored UI changes.
We found that @01.works/diff-layer demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Research
/Security News
Miasma Mini Shai-Hulud hits @immobiliarelabs Backstage plugins, targeting GitLab and LDAP auth packages on npm.

Security News
Rolldown paused Rust React Compiler integration after a 5MB binary size increase raised concerns about shipping React-specific code to all Vite users.

Security News
/Research
Mini Shai-Hulud expands into the Go ecosystem after hitting LeoPlatform npm packages and targeting GitHub Actions workflows.