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

@vibeflow-tools/prototyping

v0.2.0

Published

In-app variant switching for React — page-level and component-level prototyping with URL persistence

Readme

@vibeflow-tools/prototyping

In-app variant switching for React — page-level and component-level prototyping with URL persistence and zero runtime dependencies.

npm website

npm install @vibeflow-tools/prototyping

Built for Coding Agents

ui-prototyping was built to enable coding agents to propose UI variants directly in your running app — without screenshots, back-and-forth prompts, or external design tools.

An agent can define multiple named variants (layouts, colour schemes, component densities) and register them with a few lines of code. You switch between them with a click, see the result immediately in your real app, and tell the agent which one to keep. No Figma. No mockups. No rebuild cycle.

This makes ui-prototyping one of the most efficient ways for developers to give and receive UI feedback when working with AI coding assistants.


Why It Matters

Designing and reviewing UI variations is slow when you have to change code, rebuild, and refresh every time you want to see a different state. ui-prototyping brings the switch directly into your running app:

  • Click to switch — numbered dot on each component, floating toolbar for all scopes at once
  • URL-persisted — share a URL and your reviewer sees the exact variant you're showing them
  • TypeScript-first — variant keys are narrowed to their literal types, config objects are fully typed
  • Zero runtime deps — peer-deps only (react, react-dom); nothing extra in your bundle
  • Vibeflow overlay integration — when the Vibeflow overlay is detected, the toolbar is accessible via the right-click context menu ("Prototyping" option)

Quick Start

import { VariantProvider, useVariant, PageVariantSwitcher } from '@vibeflow-tools/prototyping'

// 1. Define your variants
const heroVariants = {
  default:  {},
  compact:  { spacing: 'tight', titleSize: 'md' },
  expanded: { spacing: 'loose', titleSize: 'xl' },
}

// 2. Read the active variant
function HeroSection() {
  const v = useVariant('Hero', heroVariants)
  return (
    <section className={v.spacing === 'tight' ? 'py-4' : 'py-12'}>
      <PageVariantSwitcher name="Hero" variants={heroVariants} />
      <h1 className={v.titleSize === 'xl' ? 'text-4xl' : 'text-2xl'}>Welcome</h1>
    </section>
  )
}

// 3. Wrap your app
function App() {
  return (
    <VariantProvider>
      <HeroSection />
    </VariantProvider>
  )
}

Installation

npm install @vibeflow-tools/prototyping
# or
pnpm add @vibeflow-tools/prototyping
# or
yarn add @vibeflow-tools/prototyping

Requirements: React 18+, Node.js 18+.


Core API

<VariantProvider>

Wrap your app (or a subtree) with VariantProvider to enable the variant switching system. All hooks and switcher components below it share state via this provider.

<VariantProvider>
  <App />
</VariantProvider>

Props

| Prop | Type | Default | Description | |------|------|---------|-------------| | mode | "dev" \| "always" | "dev" | "dev" hides switcher UI in production (NODE_ENV === "production"). "always" always shows it — useful for A/B testing demos. | | defaultVisible | boolean | true | Initial UI visibility. Persisted in localStorage so users can hide/show across sessions. | | shortcuts | KeyboardShortcut[] \| false | default shortcuts | Custom keyboard shortcuts for toggling the variant UI. Pass false to disable. |


useVariant(name, variants)

Core hook. Registers the scope, resolves the active variant from URL → localStorage → default, and returns the matching config object.

const variants = {
  default:  {},
  compact:  { compact: true, density: 'low' },
  detailed: { showMeta: true, showComments: true },
}

function TaskCard() {
  const v = useVariant('TaskCard', variants)
  // v is typed as typeof variants[keyof typeof variants]
  return <div className={v.compact ? 'p-2' : 'p-4'}>…</div>
}

The first key is always the default variant (applied when no URL param or storage entry is present).


<VariantSwitcher>

A subtle indicator dot positioned on the edge of the parent element. Clicking it expands a numbered-dots picker.

function TaskCard() {
  const v = useVariant('TaskCard', variants)
  return (
    <div style={{ position: 'relative' }}>
      <VariantSwitcher name="TaskCard" variants={variants} />
      {v.compact ? <CompactView /> : <FullView />}
    </div>
  )
}

The parent must have position: relative for correct placement.

Deduplicates per scope — only the first VariantSwitcher for a given scope renders, even if the component is used multiple times on the page.

Props

| Prop | Type | Default | Description | |------|------|---------|-------------| | name | string | required | Scope name — must match the useVariant call | | variants | Record<string, object> | required | Same variant definitions passed to useVariant | | position | "right" \| "left" | "right" | Which side the dot appears on |


<PageVariantSwitcher>

A dark segmented control fixed to the top-left of the viewport — ideal for page-level layout or theme switching.

function DashboardPage() {
  const layout = useVariant('DashboardLayout', layoutVariants)
  return (
    <>
      <PageVariantSwitcher name="DashboardLayout" variants={layoutVariants} />
      <main className={layout.sidebar ? 'with-sidebar' : ''}>…</main>
    </>
  )
}

Props

| Prop | Type | Default | Description | |------|------|---------|-------------| | name | string | required | Scope name — must match the useVariant call | | variants | Record<string, object> | required | Same variant definitions passed to useVariant |


<VariantDevToolbar>

An optional floating toolbar that shows all registered variant scopes at once in a single panel. Use this when you have many scopes and want a central control panel.

function App() {
  return (
    <VariantProvider>
      <VariantDevToolbar />  {/* ← add once near the root */}
      <MainContent />
    </VariantProvider>
  )
}

The toolbar button (vibeflow icon) appears bottom-right of the page. When the Vibeflow overlay is detected, the button is hidden — access the toolbar instead via the overlay's right-click context menu.

Keyboard shortcuts:

  • Alt+H — toggle all switchers on/off
  • Ctrl+Shift+V — toggle all switchers on/off
  • Escape — close the toolbar panel

registerVariant(name, variants)

Module-level registration. Use this to centralise all variant definitions in one file instead of re-passing them to every component.

// variants.ts
import { registerVariant } from '@vibeflow-tools/prototyping'

registerVariant('TaskCard', {
  default:  {},
  minimal:  { compact: true },
  detailed: { showMeta: true, showComments: true },
})

registerVariant('KanbanBoard', {
  default: {},
  dense:   { rowHeight: 'sm' },
})
// TaskCard.tsx
function TaskCard() {
  // Pass an empty object — registered variants are merged automatically
  const v = useVariant('TaskCard', {})
  return <div className={v.compact ? 'p-2' : 'p-4'}>…</div>
}

Inline variants always win over registered ones when both are provided.


Persistence

Active variants are persisted in two places:

| Layer | Storage | Scope | |-------|---------|-------| | URL param | ?vf-<name>=<variant> | Shareable — copy the URL to share a specific variant | | localStorage | vf-<name> | Session — survives page reloads in the same browser |

URL takes precedence over localStorage.


Keyboard Shortcuts

| Shortcut | Action | |----------|--------| | Alt+H | Toggle all variant switchers on/off | | Ctrl+Shift+V | Toggle all variant switchers on/off |

Both shortcuts call toggleUiVisible() on the VariantProvider. To open the VariantDevToolbar panel, click the vibeflow icon button in the bottom-right corner.

Customise or disable shortcuts via the shortcuts prop on VariantProvider:

// Custom shortcuts
<VariantProvider shortcuts={[{ key: 'v', alt: true }]}>
  <App />
</VariantProvider>

// Disable all shortcuts
<VariantProvider shortcuts={false}>
  <App />
</VariantProvider>

Vibeflow Overlay Integration

When the Vibeflow overlay is injected into the page, VariantDevToolbar automatically hides its standalone vibeflow icon button and registers itself with the overlay. The toolbar is then accessible via the overlay's right-click context menu under "Prototyping" — both on the bottom-right trigger and when right-clicking any element on the page.

No configuration needed — detection is automatic.

Tip for AI coding agents: Combine ui-prototyping with the Vibeflow overlay so variants are instantly accessible via right-click anywhere on the page. The agent defines the variants; you switch and approve. See the ui-prototyping webpage for a live demo.


Advanced: Power User Utilities

The following URL/localStorage utilities are exported for cases where you need manual control:

import {
  readVariantFromUrl,
  writeVariantToUrl,
  removeVariantFromUrl,
  readVariantFromStorage,
  writeVariantToStorage,
  removeVariantFromStorage,
  resolveActiveVariant,
  readUiVisibleFromStorage,
  writeUiVisibleToStorage,
} from '@vibeflow-tools/prototyping'

TypeScript

All exports are fully typed. The useVariant hook preserves key-literal types so your IDE autocompletes variant config properties:

const variants = {
  default: {},
  compact: { compact: true as const, rows: 3 as const },
}

function MyComponent() {
  const v = useVariant('MyComponent', variants)
  // v.compact is typed as `true | undefined`
  // v.rows is typed as `3 | undefined`
}

Contributing

pnpm install
pnpm --filter @vibeflow-tools/prototyping run build
pnpm --filter @vibeflow-tools/prototyping run test
pnpm --filter @vibeflow-tools/prototyping run test:coverage

License

Apache-2.0 — see NOTICE for third-party attributions.