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

snps-cli

v0.1.8

Published

CLI for Synapse

Readme

snps-cli

Command-line tool for syncing design-system entities — components, tokens, typography and icons — straight from Figma into your codebase, and for pulling ready-made UI components from a shadcn-style registry.

It reads a single synapse.config.json, fetches the source of truth from the Figma REST API, and writes generated SCSS/CSS mixins, TypeScript variant types, Markdown structure docs, SVG icons and token files to the paths you configure.

Install

npm i -D snps-cli

The binary is snps:

npx snps --help
# or, if installed globally
snps --help

Quick start

# 1. Create synapse.config.json in the current directory
npx snps init

# 2. Authenticate with Figma (saves a token into synapse.config.json)
npx snps login

# 3. Describe what to sync
npx snps add tokens --file <figmaFileKey>
npx snps add component button

# 4. Pull it from Figma
npx snps sync

Commands

Run snps <command> --help for command-specific options.

General

| Command | Description | | --- | --- | | snps login | Authenticate with Figma via OAuth; the token is saved to synapse.config.json. | | snps init | Scaffold a new synapse.config.json in the current directory. | | snps push-errors [--no-clear] | Post accumulated sync errors back to the Figma file as comments. --no-clear keeps the local error log. |

add — write entity config to synapse.config.json

| Command | Description | | --- | --- | | snps add icons [--path] [--file] [-f] | Configure icons (paths.icons, config.icons.figmaFile). | | snps add tokens [--path] [--file] [--component] [-f] | Configure tokens. Default frame name: Colors. | | snps add tokens --group <name> [--prefix [value]] [--separator] [--output] [-f] | Add a token group (spacing, radius, …) with its own prefix — see Token groups. | | snps add typography [--path] [--file] [--component] [--format] [-f] | Configure typography. --format accepts a CSV such as css,scss. | | snps add component [name] [--all] [-f] | Download component source files from the components registry (see below). |

add component is different from the others: instead of only editing config, it fetches real component files from a registry repository and writes them to your project, resolving each component's dependencies transitively.

sync — fetch from Figma and write to disk

| Command | Description | | --- | --- | | snps sync [-f] | Sync every configured entity: tokens, typography, icons and components. -f forces every one of them. | | snps sync icons [--clear] [-f] | Fetch icons as SVGs. --clear empties the output dir first. | | snps sync tokens [-f] | Fetch tokens and emit CSS/SCSS variables. | | snps sync typography [-f] | Fetch typography and emit typography.css and/or typography.scss. | | snps sync component [name] [--all] [-f] | Sync one component, or all configured components. |

Common options

| Option | Description | | --- | --- | | -f, --force | Bypass the cache (on sync) or overwrite existing config/files (on add). | | -h, --help | Show help for a command. | | --version | Print the CLI version. |

Sync results are cached by the Figma file's last-modified time, so re-running sync only re-downloads what actually changed. Use --force to ignore the cache.

Configuration

Everything lives in synapse.config.json at the root of the project you run snps from.

{
  // Base output directories per entity type.
  "paths": {
    "components": "./",
    "tokens": "./tokens/",
    "icons": "./icons/",
    "typography": "./typography/"
  },

  "config": {
    // ── Components ──────────────────────────────────────────────
    "components": {
      // Global defaults, inherited by every component entry below.
      "figmaFile": "<figmaFileKey>",  // default file to read components from
      "types": true,                   // emit <name>.types.ts
      "structure": true,               // emit <name>.md
      "format": "scss",                // "scss" | "css" | ["scss", "css"]

      // One entry per component. The key is the Figma component name.
      "button": {
        "path": "./components/button", // where generated files go
        // Optional per-component overrides:
        "figmaFile": "<otherFileKey>", // read this component from another file
        "typesPath": "./types",        // override where <name>.types.ts goes
        "structurePath": "./docs",     // override where <name>.md goes
        "types": true,                 // override the global toggle
        "structure": true
      },
      "slider": { "path": "./components/slider" }
    },

    // ── Icons ───────────────────────────────────────────────────
    "icons": { "figmaFile": "<figmaFileKey>" },

    // ── Tokens ──────────────────────────────────────────────────
    "tokens": {
      "figmaFile": "<figmaFileKey>", // default file for every group
      "componentName": "Colors",     // single-source setup; ignored when "groups" is set
      "separator": "-",              // default glue between prefix and name

      // Optional: several token sources, each its own Figma COMPONENT_SET.
      // The key names the group and doubles as the default component name
      // and the default prefix.
      "groups": {
        "variables": { "component": "Colors" },                 // --bg-primary
        "spacing":   { "prefix": true, "separator": "_" },      // --spacing_xs
        "radius":    { "component": "Rounding", "prefix": "r" } // --r-xs
      }
    },

    // ── Typography ──────────────────────────────────────────────
    "typography": {
      "figmaFile": "<figmaFileKey>",
      "format": ["css", "scss"],
      "componentName": "Typography",
      "variables": true              // emit CSS variables per property
    }
  },

  // Populated by `snps login`.
  "figma": { "token": "<figma-token>" }
}

Token groups

Without groups, sync tokens reads a single Figma COMPONENT_SET (config.tokens.componentName, default Colors) and writes each variable exactly as it is named in Figma.

groups lets you read several sets, each with its own naming policy. This matters when a set uses short, self-contained names: a Spacing set with variants xs, s, m needs a prefix, while a color set already carries one in its names (bg-primary).

| Key | Default | Meaning | | --- | --- | --- | | component | the group key | COMPONENT_SET name in Figma (matched case-insensitively) | | figmaFile | config.tokens.figmaFile | read this group from another file | | prefix | false | false — no prefix; true — the group key; a string — a custom prefix | | separator | - | glue between the prefix and the token name | | output | tokens | base file name; the theme is appended as <output>.<theme>.css |

prefix and separator can also be set once on config.tokens as defaults for every group.

# spacing tokens from the "Spacings" set, emitted as --spacing_xs, --spacing_m, …
npx snps add tokens --group spacing --component Spacings --prefix --separator _

Each variant in the set must have the property carrying its value bound to a Figma variable, on the variant itself rather than a nested layer — a fill for colors, the width for spacings, the corner radius for radii. The bound property decides which extractor runs. Shadow tokens are the exception: effects cannot be bound to a variable, so a variant carrying a visible shadow and no binding is read as a shadow. Anything else without a binding is reported as an error rather than guessed at.

Notes:

  • The prefix is applied before the name is validated, so short names that are not legal CSS identifiers on their own (2xs, 0) become valid once prefixed.
  • The same prefix is applied when components are synced, so var(--…) in generated component styles always matches the variables in the token files.
  • Groups sharing an output are merged into one file per theme, with a comment header per group. Two groups resolving to the same variable name in the same file is reported as an error.
  • Changing a prefix regenerates the files even though the Figma file itself did not change.

Typography variables

By default sync typography writes each style as a rule with literal values, and components repeat those values inline — the same number lives in two places and drifts when the design changes.

With config.typography.variables: true, every property becomes a custom property and the rule points at it:

:root {
  --h1-bold-family: Inter;
  --h1-bold-weight: 700;
  --h1-bold-size: 72px;
}

.h1-bold {
  font-family: var(--h1-bold-family);
  font-weight: var(--h1-bold-weight);
  font-size: var(--h1-bold-size);
}

Names are --<style>-<property>, with the redundant font-/text- prefix dropped: family, weight, size, style, line-height, letter-spacing, decoration, transform.

sync component then references the same variables instead of literals — font-size: var(--h1-bold-size) — by matching the component's Figma text style (styles.text) against the typography set. That works on any plan: text styles, unlike variables, are part of the ordinary file response.

A property the style doesn't define never becomes a variable, and components keep its literal value, so a component can't reference a variable the generated file never wrote. Components fall back to literals entirely when typography isn't configured or its file is unreachable.

How component paths resolve

  • path is used as-is (relative to where you run snps); it is not prefixed by paths.components.
  • typesPath and structurePath fall back to the component's own path when omitted — so by default the mixin, types and structure doc all land in the same folder.
  • A component's figmaFile falls back to the global config.components.figmaFile.

What sync component generates

For a component named button, snps sync component button writes:

  • button.scss (or button.css) — a @mixin / class ruleset generated from the Figma layout, with values resolved to CSS custom properties (var(--token-name)) via your synced tokens.
  • button.types.ts — a TypeScript union of the component's Figma variant properties (enabled by types: true).
  • button.md — a Markdown snapshot of the component (enabled by structure: true), containing:
    • Description — the component description as entered in Figma;
    • Variants — the variant API (each property and its possible values);
    • Structure — the element hierarchy, annotated with the variant states under which each element appears.

The .md doc is meant as machine-readable context for an AI agent generating or refactoring the component to match the current design.

The component registry (add component)

snps add component treats a repository as a shadcn-style registry: it reads a registry.json from the configured repo, resolves the requested component plus its dependencies, and downloads each file into the matching directory.

// config.components.repo — defaults to the public Synapse components repo
"components": {
  "repo": "https://raw.githubusercontent.com/<owner>/<repo>/main"
}
snps add component button      # button + its dependencies (icon, ...)
snps add component --all       # every component in the registry
snps add component button -f   # overwrite existing files

Each registry.json entry declares its files and dependencies, so pulling one component automatically brings in everything it imports.

Authentication

snps login runs the Figma OAuth flow and stores the resulting token under figma.token in synapse.config.json. All sync commands read from there.

Because the token is written into synapse.config.json, keep that file out of version control (or strip figma.token) if the repo is public.

License

MIT