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

@wcgw/vibe-check

v0.3.0

Published

React performance monitoring overlay with AI/vibe-coding issue detection

Readme

@wcgw/vibe-check

React performance-monitoring overlay with AI/vibe-coding issue detection. A drop-in widget that watches your page in real time — FPS, Web Vitals, memory, SEO/AEO audits, and detected problems — and hands each finding to your AI agent over MCP as a ready-to-paste fix prompt.

All UI is inline-styled (no CSS files), renders at a high z-index, ships a dark and a light theme, and respects prefers-reduced-motion.

What you get — six tabs

| Tab | What it shows | |---|---| | Monitor | Live FPS lifeline, Web Vitals, memory, console counts, SEO/AEO scores, active problems, and a compact persisted impact summary. | | Agent | The durable fix queue — every detected problem split across to fix / in progress / fixed, plus the full project impact card. Agent pickup, browser verification, and regressions persist per project. | | SEO | Search-visibility audit — a 0–100 score over the SEO criteria, each failing check expandable with Send to agent and Copy prompt actions. | | AEO | AI-answer-readiness audit (Answer Engine Optimization) — same shape as SEO, with Send to agent on every finding. | | Prompts | A library of proactive prompts to ask your AI agent, each copy-to-clipboard. | | Settings | Wording, markers, theme, history, collapsed/expanded placement, MCP status, impact Markdown/JSON export, and a separate two-step impact reset. |

On-page annotation markers point a badge at the actual offending DOM element (oversized images, heavy libraries, …); click one for an in-place popover with the same Send to agent, Copy prompt, and resolve actions.

Every detected issue uses this shared action row in the Agent, SEO, AEO, and annotation views. Prompts remains copy-only because it contains proactive ideas rather than detected issues with evidence to send through MCP.

The widget caches each project's latest workflow locally for an immediate refresh, while the local MCP hub remains authoritative and persists the full timeline in that project's .vibecheck/state.json. A fix is shown as verified only after two newer snapshots from the same page no longer contain the issue. The same local state records exact verified-fix and regression totals plus only those performance improvements supported by comparable snapshots. Impact copy uses “caught,” “verified,” and “helped,” and always includes measurement scope.

Installation

npm install -D @wcgw/vibe-check

Peer dependencies: react >= 18, react-dom >= 18

Complete setup

1. Drop the widget into your app

import { PerfToggle } from '@wcgw/vibe-check'

function App() {
  return (
    <>
      <YourApp />
      {import.meta.env.DEV && (
        <PerfToggle vibeCheckProps={{
          beaconUrl: 'http://127.0.0.1:4200',
          projectId: 'my-storefront',
        }} />
      )}
    </>
  )
}

On first run the widget shows a small collapsed pill in the corner (so you can see it's working). Click it to expand, or press Alt+Shift+V to hide/show it.

2. Start the local hub

Keep this process running alongside your dev server. One hub supports all your local projects.

npx -y @wcgw/[email protected] hub

3. Wire the bridge into your AI agent

Choose Codex, Claude Code, or Cursor in the widget's setup card. For Codex:

codex mcp add vibe-check -- npx -y @wcgw/[email protected] connect

For Claude Code:

claude mcp add --scope local vibe-check -- npx -y @wcgw/[email protected] connect

For Cursor, merge this entry into the top-level mcpServers object in .cursor/mcp.json; keep any servers already present:

{
  "vibe-check": {
    "command": "npx",
    "args": ["-y", "@wcgw/[email protected]", "connect"]
  }
}

Restart the agent client after changing its MCP configuration. The card keeps the exact setup and project-specific watch instruction visible until the agent connects. Run npx -y @wcgw/[email protected] doctor --project my-storefront if a step is not turning green.

4. Watch, then send

Use the vibe-check MCP tools. Call list_projects, then call watch_for_issue with project_id "my-storefront" and keep waiting for the next issue I send from the widget.

The agent calls list_projects and watch_for_issue. When the widget says Agent connected, expand a detected issue and click Send to agent. The agent receives that issue and a fix suggestion in the pending tool result. You can send directly from Agent, SEO, AEO, or an on-page annotation; all four use the same confirmed-delivery behavior.

Only one agent may watch a project at a time. A second watcher is rejected and the widget warns you, while the original watcher stays connected. Give parallel dev servers different projectId values; they may share the same hub and port.

VibeCheck automatically excludes requests to the configured beaconUrl and its API paths from duplicate-request findings. Other localhost traffic remains visible, so a real duplicate request to your own app is still reported.

Components

<PerfToggle />

Keyboard-toggled wrapper. Renders the widget as a collapsed pill on first run; the shortcut hides/shows it.

<PerfToggle
  shortcut="alt+shift+v"              // Default — an uncontested combo. Supports ctrl/shift/alt/meta+key
  vibeCheckProps={{
    position: 'bottom-right',
    beaconUrl: 'http://127.0.0.1:4200',
    projectId: 'my-storefront',
  }}
/>

Note: ctrl+shift+p (the previous default) collides with the private-window shortcut in Firefox/Edge and can't be intercepted in Firefox — hence alt+shift+v.

<VibeCheck />

The full overlay widget.

<VibeCheck
  enabled={true}                                       // Start/stop monitoring
  position="bottom-right"                              // 'bottom-right' | 'bottom-left' | 'top-right' | 'top-left'
  panels={['fps', 'vitals', 'memory', 'console', 'issues']}
  beaconUrl="http://127.0.0.1:4200"                   // Optional: send data to local hub
  projectId="my-storefront"                           // Stable ID; required when several projects run
  startCollapsed={false}                               // Start as the collapsed pill instead of the open panel
  storageKey="vibe-check:preferences"                  // Optional: per-instance localStorage bucket (multiple embeds)
  engine={undefined}                                   // Optional: drive a provided engine (see "Scripted demos")
  onIssue={(issue) => console.warn('Issue:', issue.title)}
/>

position is the application fallback. A user-selected corner in Settings is saved per projectId and overrides that fallback. Pass storageKey to own the preference bucket explicitly. startCollapsed applies only on first use; after the user expands or collapses the widget, that choice survives refreshes.

Scripted demos

Pass an engine built with createScriptedEngine(...) from @wcgw/vibe-check-core to replay a canned, deterministic timeline (identical for every visitor) instead of reading live collectors — useful for landing-page and docs demos.

import { VibeCheck } from '@wcgw/vibe-check'
import { createScriptedEngine } from '@wcgw/vibe-check-core'

const engine = createScriptedEngine(myScenario)
<VibeCheck engine={engine} />

<VibeCheckProvider />

Context provider for sharing an engine instance across components. It's a re-export of Context.Provider, so you must pass value.

import { useState, useEffect } from 'react'
import { VibeCheckProvider, useVibeCheckEngine } from '@wcgw/vibe-check'
import { VibeCheckEngine } from '@wcgw/vibe-check-core'

function App() {
  const [engine] = useState(() => new VibeCheckEngine())
  useEffect(() => {
    engine.start()
    return () => engine.stop()
  }, [engine])

  return (
    <VibeCheckProvider value={engine}>
      <Dashboard />
    </VibeCheckProvider>
  )
}

function Dashboard() {
  const engine = useVibeCheckEngine()  // Same engine instance
  // ...
}

Hooks

For custom UIs and programmatic access. Each metric hook takes an enabled flag (defaults to false) and starts its own collector when enabled.

import { useVibeCheck, useFrameRate } from '@wcgw/vibe-check'

// Option A: use the engine, read everything from one snapshot
function Monitor() {
  const { snapshot } = useVibeCheck()
  return <div>FPS: {snapshot.frameRate.fps} · Issues: {snapshot.issues.length}</div>
}

// Option B: use individual collectors (each runs its own collector)
function FpsBadge() {
  const fps = useFrameRate(true)
  return <span>{fps.fps} fps</span>
}

Available hooks:

| Hook | Returns | Notes | |---|---|---| | useVibeCheck(config?, enabled?, engine?) | { engine, snapshot } | Owns the engine (or drives a provided one). Most consumers want this. | | useFrameRate(enabled?) | FrameRateStats | Standalone collector. | | useWebVitals(enabled?) | WebVitalsStats | Standalone collector. | | useMemory(enabled?) | HeapMemory \| null | Chrome only. | | useLongFrames(enabled?) | LongFrameStats | LoAF API. | | useDetectedIssues(engine?) | readonly VibeIssue[] | Subscribes to an engine (explicit or via provider). | | useIssueStore(liveIssues) | tracked + status helpers | localStorage-backed issue tracking. | | usePreferences(storageKey?, projectId?, startCollapsed?) | { prefs, updatePrefs, toggleMode } | Project-scoped UI mode, open/closed state, placement, annotation, theme, and history preferences. | | useClipboard(resetDelayMs?) | { copiedId, copy } | Used by the prompts panel. |

AI agent integration

The widget POSTs project-tagged snapshots to the local hub and dispatches a button-selected issue to that project's queue. The stdio bridge exposes 9 tools:

  • list_projects — active projects and watcher state
  • get_performance_snapshot — current frame rate, vitals, memory, issues
  • get_detected_issues — filterable by severity / detector
  • get_fix_suggestions — markdown fix guide for one issue
  • watch_performance — claim a project and long-poll for its next snapshot
  • watch_for_issue — claim a project and wait for a widget dispatch
  • acknowledge_issue / resolve_issue — close the loop after a fix
  • release_project — explicitly release the current session's project lease

If exactly one project is active, project_id is optional. With multiple active projects the tools require it, preventing data from one dev server from leaking into another session.

See @wcgw/vibe-check-mcp for the tested Codex, Claude Code, and Cursor setup, doctor output, lease behavior, and port overrides.

Bundle size

The FPS chart (liveline, ~62KB) is lazy-loaded, so the collapsed pill and initial load skip it. pnpm size gzips the eager main chunk and checks it against a budget.

Styling

All UI uses inline styles routed through the --wcgw-* design tokens (declared once in an injected stylesheet). No CSS files or external style dependencies. Dark and light themes; respects prefers-reduced-motion.

License

MIT