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

@devosurf/vynt

v0.1.6

Published

vynt is a local utility for fast UI iteration with parallel agent variants in a single active workspace.

Downloads

512

Readme

vynt

vynt is a local utility for fast UI iteration with parallel agent variants in a single active workspace.

Why

  • Run multiple implementation paths in parallel.
  • Keep one active workspace and one dev server.
  • Compare variants quickly and choose a winner.
  • Keep rollback deterministic.

Current Scope

This scaffold provides:

  • Variant metadata storage at .vynt/state.json
  • Objective + variant hierarchy
  • Profile composition with one variant per objective
  • Conflict detection for composed profile selections
  • Workspace apply engine that restores the pinned base and applies selected patch artifacts
  • Docs for MVP architecture and phase plan

This scaffold does not yet capture screenshots automatically.

Recommended Core Workflow (Now)

Use vynt as a standalone CLI while you review UI manually in your browser.

  1. Start your web app once and keep it running.
  2. Register variants with add under each objective.
  3. Switch quickly with apply (single variant) or profile apply (cross-objective composition).
  4. Refresh the browser and review the result manually.
  5. Finalize objective winners after visual review.

This keeps the core loop simple: deterministic patch switching plus manual UI verification.

Browser Toolbar Devtool

You can run a local bridge and control variant switching directly in the browser.

  1. Use vynt/vite plugin in your Vite config (recommended) so bridge starts automatically.
  2. Mount the React provider (recommended) or inject toolbar.js for non-React pages.
<script src="http://127.0.0.1:4173/toolbar.js" data-vynt-bridge="http://127.0.0.1:4173"></script>

Toolbar capabilities in this MVP:

  • Objective + variant selection
  • Previous/next variant stepping with index counter (x/y)
  • Single-variant apply
  • Profile apply
  • Rollback to latest snapshot

React/Next helper component (one-line mount, no script fetch required):

// app/layout.tsx or root provider
import { VyntToolbarProvider } from "vynt/web/react/index.js"

export function DevTools() {
  return <VyntToolbarProvider />
}

The React provider renders the toolbar inline and talks directly to the bridge API (/status, /apply, /rollback, /events). It does not load toolbar.js. With vynt/vite plugin, provider default bridge URL is same-origin "/__vynt".

Vite auto-bridge setup (no separate vynt bridge serve command):

import { defineConfig } from "vite"
import react from "@vitejs/plugin-react"
import { vyntVitePlugin } from "vynt/vite"

export default defineConfig({
  plugins: [react(), vyntVitePlugin()],
})

Optional plugin config:

vyntVitePlugin({
  bridgeHost: "127.0.0.1",
  bridgePort: 4173,
  prefix: "/__vynt",
})

Manual script injection is still available when you are not using React:

<script src="http://127.0.0.1:4173/toolbar.js" data-vynt-bridge="http://127.0.0.1:4173"></script>

Custom bridge URL:

<VyntToolbarProvider bridgeUrl="http://127.0.0.1:4173" />

Use custom bridgeUrl when you do not use the Vite plugin proxy.

Test in a Real Project

Yes, you can test this today with the same link workflow.

  1. In this repo: bun link
  2. In your target web project: bun link vynt
  3. In target project root: vynt init "$(git rev-parse HEAD)" (if not already initialized)
  4. Add vyntVitePlugin() to your Vite config
  5. Mount the provider in your app:
import { VyntToolbarProvider } from "vynt/web/react/index.js"

export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html>
      <body>
        <VyntToolbarProvider />
        {children}
      </body>
    </html>
  )
}
  1. Open the app in browser; toolbar appears bottom-right.
  2. Use objective/variant selectors or previous/next stepping to switch quickly.

tmux-First Example

The project can be operated in tmux without requiring any plugin.

# start a tmux layout (server + live vynt status + operator pane)
scripts/vynt-tmux.sh start vynt-lab "npm run dev:web"

# quick objective/variant apply
scripts/vynt-tmux.sh apply hero <variant-id>

# quick profile apply
scripts/vynt-tmux.sh profile-apply <profile-id>

# interactive selector (uses fzf if installed)
scripts/vynt-tmux.sh selector
scripts/vynt-tmux.sh selector profile

OpenCode Integration: Standalone First, Plugin Later

  • Current recommendation: run vynt as a standalone CLI from terminal/tmux.
  • Future optional path: an OpenCode plugin hook that auto-registers variants from session lifecycle events.
  • Rationale: keep core switching reliable and tool-agnostic first; add automation hooks when the workflow stabilizes.

Future Optional Automation

  • capture: auto-screenshot routes per variant/profile using Playwright.
  • compare: side-by-side or grouped screenshot review.
  • Auth-protected pages can be supported by persisted Playwright auth state (cookies/local storage), so screenshots remain automated.

Quick Start

  1. npm install
  2. npm run dev -- init <base-ref>
  3. npm run dev -- objective create "landing hero redesign" --id x
  4. npm run dev -- add x "bold hero" ./patches/x-v2.patch --files=src/app.tsx,src/hero.tsx
  5. npm run dev -- profile create "design-a"
  6. npm run dev -- profile set design-a x <variant-id>
  7. npm run dev -- profile apply design-a
  8. npm run dev -- status
  9. npm run dev -- list

Use in Real Projects (bun link)

  1. In this repo: bun link
  2. Ensure Bun bin path is on your shell PATH (usually ~/.bun/bin).
  3. In any target project: bun link vynt
  4. Run from the target project: vynt --help

Then use the same commands directly (without npm run dev --), for example:

  • vynt init "$(git rev-parse HEAD)"
  • vynt objective create "hero exploration"
  • vynt status

Command Overview

All commands are invoked through vynt.

  • vynt init <base-ref>
  • vynt objective create <name> [--id <id>]
  • vynt objective list [--json]
  • vynt objective finalize <objective-id> <variant-id>
  • vynt add <objective-id> <name> <patch-file> [--files=a,b,c] [--session=<id>] [--notes=<text>]
  • vynt activate <objective-id> <variant-id>
  • vynt apply [<variant-id>] [--objective=<objective-id> --variant=<variant-id>] [--review]
  • vynt rollback [<snapshot-id>]
  • vynt bridge serve [--host <host>] [--port <port>]
  • vynt status [--json]
  • vynt opencode register <objective-id> <session-id> <name> <patch-file> [--files=a,b,c] [--notes=<text>]
  • vynt opencode register-auto <session-id> <name> <patch-file> [--objective=<objective-id>] [--files=a,b,c] [--notes=<text>]
  • vynt opencode capture <session-id> <name> [--objective=<objective-id>] [--notes=<text>] [--reset]
  • vynt profile create <name> [--id <id>]
  • vynt profile list [--json]
  • vynt profile set <profile-id> <objective-id> <variant-id>
  • vynt profile clear <profile-id> <objective-id>
  • vynt profile apply <profile-id>
  • vynt list [--json]

Helper Scripts

  • scripts/vynt-tmux.sh: tmux-first helper for start/apply/profile-apply/selector flows, including profile selector mode.
  • scripts/vynt-opencode-hook.sh: standalone OpenCode hook scaffold for registering session output with direct args or environment variables.
  • scripts/vynt-variants-parallel.sh: deterministic backend helper for /variants orchestration (setup, wait, finalize, cleanup) with patch-based register-auto; defaults to sandbox backend and supports worktree fallback.

Variant Generation Command

Use OpenCode custom command /variants <objective> [count] (configured in ~/.config/opencode/opencode.jsonc) to orchestrate multi-variant generation with subagent exploration and vynt registration.

Variant contract for generated UI patches:

  • If a variant changes UI markup (.tsx, .jsx, .vue, .svelte, .astro, .html) for an objective, include data-vynt-objective="<objective-id>" on the objective wrapper container.
  • vynt opencode register-auto now enforces this for UI patches and rejects registration when the marker is missing.
  • Subagents should preserve existing data-vynt-* attributes and never remove objective markers.

vynt opencode capture exists for explicit in-session registration of the current diff, including optional --reset back to base for the next variant iteration.

OpenCode Hook Scaffold (Standalone)

Use the helper script when you want a lightweight plugin-compatible registration path without hard-coupling to any specific OpenCode runtime internals.

# direct mode
scripts/vynt-opencode-hook.sh register hero ses_123 "hero bold" ./patches/hero.patch --files src/hero.tsx

# env mode (for hooks)
scripts/vynt-opencode-hook.sh env-template
scripts/vynt-opencode-hook.sh register-env

OpenCode Auto-Register Plugin Setup

Auto-registration is optional and runs through an OpenCode plugin event hook.

  1. Ensure global plugin file exists at ~/.config/opencode/plugin/vynt-autoregister.ts.
  2. Restart OpenCode so the plugin is loaded.

No config is required for objective routing.

Optional override file:

{
  "objectiveId": "hero",
  "namePrefix": "agent",
  "enabled": true
}

Save this as .vynt/opencode-autoregister.json in your project root.

Notes:

  • Auto-register now performs objective routing automatically.
  • If one objective matches changed files strongly, it is reused.
  • If routing is ambiguous, a new objective is auto-created from file/name hints.
  • Optional: set objectiveId only when you want to force all auto-registered variants into one objective.
  • You can override objective and title prefix through env vars:
    • VYNT_AUTO_OBJECTIVE_ID
    • VYNT_AUTO_NAME_PREFIX
  • On each session.idle, the plugin writes a patch to .vynt/patches/ and registers it through vynt opencode register-auto.

Layout

  • src/cli.ts: command entrypoint
  • src/bridge.ts: local HTTP/SSE bridge for browser devtool controls
  • src/state.ts: state load/save logic
  • src/types.ts: variant model types
  • web/vynt-toolbar.js: injected browser toolbar client
  • web/react/VyntToolbarProvider.js: React helper for script injection
  • web/react/index.js: tiny React barrel export for provider import
  • docs/mvp-spec.md: product spec
  • docs/architecture.md: technical architecture
  • docs/implementation-plan.md: phased execution plan