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

@0gfoundation/design-collab

v0.3.4

Published

Designer/front-end collaboration infrastructure: per-commit Storybook, an aggregated design gate, and branch sync that never hands a designer a conflict.

Readme

@0gfoundation/design-collab

Infrastructure for designer ↔ front-end collaboration in a shared codebase: a per-commit Storybook, one aggregated design gate, and branch sync that never hands a designer a merge conflict.

Every check here is a mechanism with no project knowledge in it — "a View must have a sibling story", "a generated artifact must match its source", "these identifiers must not reach a production bundle". Everything about your project arrives through design-collab.config.mjs. That split is the whole point: the mechanisms are portable, the paths are not.

Zero runtime dependencies. Node ≥ 20.

中文的完整接入指南:ADOPTING.zh-CN.md — what init reads and what it refuses to guess, how to read a gap, and what each of the twelve checks needs before it can tell you anything.

Getting started

pnpm add -D @0gfoundation/design-collab

Public on npmjs, so there is nothing else to configure — no .npmrc, no registry token in CI, no environment variable in your deploy platform. Then:

design-collab init             # writes the config; run it again to scaffold
                               # the agent skill and the CI workflow
design-collab install-drivers  # once per clone — see "Merge drivers" below
design-collab start            # before each piece of design work

init runs in two passes on purpose. Without a config there is nothing to fill the templates with, so the first pass writes only the config and stops. Once you have edited it, the second pass generates the skill and the workflow from your values, so the three artifacts cannot disagree with each other.

The first pass reads your repository rather than copying an example: where the app lives, your source root, the path aliases in tsconfig.json, your typecheck script, the base branch from origin/HEAD, and whether you have Storybook or an i18n library at all. It prints what it found and what it could not, and writes the reasons into the file next to each value. Anything it could not observe is absent rather than guessed — the package's defaults then apply, and the gap stays visible.

One field is always yours: writableSet is written empty and an empty set is rejected at load time. Which paths a designer owns is a decision, not a property of your tree.

Adoption is not silent

A check that cannot run does not report as one that passed. Three things used to look identical in the output and now do not:

| | Fails the run? | |---|---| | declared — you wrote checks: { 'message-parity': false } | no; it is an answer | | n/a — nothing relevant changed in this run | no | | gap — enabled, and it could not run | yes |

A gap is either a check whose configuration is missing, or one that ran and examined zero subjects. The second used to be the dangerous one: with globs describing a different repository, view-stories reported PASS — 0 file(s) covered and design-wiring reported PASS — no source files under src. The summary line then said "all N check(s) passed", because it counted only the checks that ran.

So the summary now states every state at once —

[design-collab] 14 passed, 2 failed, 3 n/a.

— and each gap is listed with the one sentence that says what to do about it. Configure it, or declare it inapplicable. Both are answers; leaving it silent is not.

Commands

| | | |---|---| | start | Preflight before writing code: branch topology, lineage, merge drivers, PR-body scaffold. | | check | Every gate CI runs, locally, reporting all failures at once. --with-storybook for the exact CI bar. | | prepare | Write what Storybook reads: the merged message catalogue and the three manifests. --skip-manifests for an app build, which wants the catalogue and nothing else. | | sync | Bring a design branch up to date — or stop cleanly, leaving the tree untouched. | | install-drivers | Wire the git merge drivers into this clone. | | sb | Resolve a commit to the Storybook that was built from it. | | init | Scaffold config, agent skill and CI workflow. |

sync, and why it exists

A gate that detects a conflict and stops there has moved the problem onto the person least equipped for it. The usual escalation — check out the integration branch, merge, resolve, push — is not something a designer can or should do.

design-collab sync rebases onto the base. If it cannot do so cleanly it aborts and leaves the branch exactly as it was — never a tree full of conflict markers — and prints a hand-off message naming each conflicting file and who last changed it on the base. The designer keeps designing; someone with front-end context gets a specific request.

It rebases rather than merges because a design branch that merges its base absorbs that line's history, and then conflicts against lockfiles and CI config its author never opened. check enforces that with a lineage check.

Merge drivers

Most "conflicts" in a design workflow are not disagreements:

  • i18n catalogs — two people adding two different keys. Merged per key.
  • Design tokens — two people adding two different custom properties. Merged per declaration.
  • Generated artifacts — recomputed from source instead of merged, because reconciling a derived file by hand is doing what a command does correctly.

On a genuine conflict all three keep the file valid and parseable rather than writing conflict markers into it, and name exactly which keys or declarations need a human.

install-drivers must run once per clone. .gitattributes maps paths to a driver and is committed; the driver command is local git config and cannot be — git refuses to execute a command that arrived with a repository, which is a security property, not an oversight. start checks for it and tells you.

Configuration

design-collab.config.mjs at the repo root. See design-collab.config.example.mjs — it is kept complete on purpose and doubles as the schema documentation.

The required fields are appRoot and writableSet. writableSet has no default because an empty set would reject every change and a permissive one would make the path guard decorative.

Disable any check by name: checks: { 'view-stories': false }.

One caveat about globs

The glob implementation here treats (, ), [ and ] as literals, so character classes and alternation are unavailable. That is deliberate: Next.js route directories are named (app) and [locale], and a general-purpose glob reads [locale] as a character class and silently fails to match the single most important path in the reference project.

Storybook

withDesignCollab() wraps a Storybook config to tag stories changed since the base, seed the manifests the manager imports statically, and — for Tailwind v4 — rewrite @theme to @theme static so the Foundations page shows live token values instead of a stale snapshot.

If your tokens are split across files pulled in with @import, the rewrite must inline them first: Tailwind v4 resolves @import itself, so an imported file is never handed to the bundler as its own module and a transform will never see it. Matching the imported filenames does not help. The template main.ts shows the working shape.

withDesignCollab() only GUARANTEES the manifests exist — Storybook does not await main.ts, so it seeds empty ones rather than blocking startup on a git diff. Re-deriving them is prepare's job, in front of Storybook:

"storybook":       "design-collab prepare && storybook dev -p 6006",
"build-storybook": "design-collab prepare && storybook build",
"build":           "design-collab prepare --skip-manifests && next build"

Do not copy a manifest generator into your project's scripts/. That is what the reference project did, and the result was ~1200 lines living in two places with nothing comparing them — a fix to one copy silently did nothing for the other.

Tests

node --test test/

The merge-driver and sync tests run against real git repositories. What those units promise is a behaviour of git merge and git rebase, and a mock can only confirm that the code calls git the way the test author imagined. Each driver test also asserts a baseline — that the same scenario conflicts without the driver — because otherwise a green suite cannot distinguish "the driver works" from "nothing ever collided".