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

@sxl-studio/export-icons

v1.0.0

Published

Export icons and assets from Figma with diff sync, fonts, and SF Symbols

Readme

SXL Export Icons

@sxl-studio/export-icons — installable CLI for exporting icon assets from Figma with incremental diff, flexible multi-config, font generation, SF Symbols pipeline, and optional Bridge/MCP source mode.

Install

npm install --save-dev @sxl-studio/export-icons

Environment and secrets

Create .env in your repository root and provide your Figma credentials there:

FIGMA_TOKEN=figd_xxxxxxxxxxxxxxxxx
SXL_ICONS_FILE_KEY=xxxxxxxxxxxx

Required Figma token scopes:

  • file_content:read
  • file_metadata:read

No write scopes are required for this CLI.

Add .env to .gitignore and never commit tokens:

.env
.env.local

CLI commands

# If package is installed in repo (recommended)
pnpm exec sxl-export-icons init
pnpm exec sxl-export-icons init --wizard

# One-shot run without install
pnpm dlx @sxl-studio/export-icons init
npx @sxl-studio/export-icons init

# Validate one or many configs
pnpm exec sxl-export-icons validate-config --config sxl-export-icons.config.yaml
pnpm exec sxl-export-icons validate-config --config-glob "packages/*/sxl-export-icons*.yaml"

# Sync (default command)
pnpm exec sxl-export-icons sync --config sxl-export-icons.config.yaml
pnpm exec sxl-export-icons sync --config sxl-export-icons.config.yaml --adopt-existing
pnpm exec sxl-export-icons sync --config sxl-export-icons.config.yaml --target font-subset-local
pnpm exec sxl-export-icons --config sxl-export-icons.config.yaml --dry-run
pnpm exec sxl-export-icons --config sxl-export-icons.config.yaml --full
pnpm exec sxl-export-icons --config-glob "packages/*/sxl-export-icons*.yaml" --report .reports/icons-sync.json

# Enable fallback if source mode=mcp failed
pnpm exec sxl-export-icons sync --config ./icons.yaml --allow-fallback-rest

# Clean generated files from state/config scopes
pnpm exec sxl-export-icons clean --config ./icons.yaml
pnpm exec sxl-export-icons clean --config ./icons.yaml --dry-run

# Print state coverage report
pnpm exec sxl-export-icons report --config ./icons.yaml

Do not use pnpx sxl-export-icons ... in registries with private proxy mapping. pnpx/dlx can try to resolve unscoped package sxl-export-icons and return 404.

Running from Cursor terminal

cd /Users/andysobol/Git/platform/packages/ds/tokens/tokens

# First run: adopt already downloaded files as baseline state
pnpm exec sxl-export-icons sync --config ../sxl-export-icons.config.yaml --adopt-existing

# Regular sync
pnpm exec sxl-export-icons sync --config ../sxl-export-icons.config.yaml

# Local subset conversion only
pnpm exec sxl-export-icons sync --config ../sxl-export-icons.config.yaml --target font-subset-local

Notes:

  • CLI auto-loads .env.local / .env from current and parent folders.
  • --adopt-existing is bootstrap mode for empty scope state.
  • During REST source loading, CLI shows live progress stages/pages (REST 1/3, REST 2/3, REST 3/3) so long runs are observable.

Config v3

Canonical filename: sxl-export-icons.config.yaml.

Legacy config version: 2 (icons.config.yaml) is supported via auto-migration. When v2 config is loaded, relative paths are resolved from the current workspace root to keep legacy behavior.

version: 3

env:
  figmaTokenVar: FIGMA_TOKEN

bridge:
  baseUrl: http://127.0.0.1:37830
  authTokenVar: BRIDGE_AUTH_TOKEN

state:
  file: .sxl/cache/icons-state.json

safety:
  allowOutsideWorkspace: false

sources:
  - id: ds-icons
    mode: rest # rest | mcp
    fileKeyVar: SXL_ICONS_FILE_KEY
    pageName: Icons
    downloadSpeed: 20
    descriptionExportMarker:
      key: sxl-studio-export-icon
      includeWhenMissing: true
    selectors:
      includeComponentSetNames: []
      includeComponentNames: []
      variantMatch:
        style: outline

targets:
  - id: web-svg
    mode: sync # sync | convert-local
    sourceIds: [ds-icons]
    download:
      enabled: true
      pruneUntracked: false
    output:
      path: assets/icons/svg
      format: svg # svg | png | jpg | webp | gif | pdf
      scale: 1
      quality: 100
      qualitySize: null
      width: null
      height: null
      modeWH: null # null | cover | proportion | fill
    naming:
      case: kebab # kebab | snake | camel | pascal
      separator: "-"
      pattern: "{prefix}{variant.style}{sectionName}{baseName}{suffix}"
      prefix: null
      suffix: null
      includeSectionName: false
      collisionStrategy: add-nodeid # error | add-nodeid | add-index
    font:
      enabled: true
      path: assets/icons/font
      formats: [woff2, woff, ttf, eot, svg]
      fontName: icons
      engine: webfonts-generator # webfonts-generator | advanced
      includeNames: [] # optional subset for font/SF generation
      excludeNames: [] # optional exclusion list
    sfSymbols:
      enabled: true
      path: assets/icons/ios
    overrides:
      - name: flags-webp
        match:
          sectionName: Flags
        patch:
          output:
            format: webp
            quality: 85

Source mode: rest and mcp

  • mode: rest — direct Figma REST API.
  • mode: mcp — read via SXL Bridge/Remote Connect (/api/command with page/tree traversal).
  • If mode: mcp fails and --allow-fallback-rest is passed, CLI auto-falls back to REST for sources with resolved fileKey.

bridge block in config is used only for mode: mcp.
For mode: rest it is ignored.

Target mode: sync and convert-local

  • mode: sync (default) — reads Figma sources, downloads/updates assets, then runs aux pipelines.
  • mode: convert-local — does not use Figma sources; reads existing local SVG files from output.path and runs font/SF pipelines.

Rules for convert-local:

  • sourceIds must be empty;
  • download.enabled must be false;
  • output.format must be svg;
  • at least one of font.enabled or sfSymbols.enabled must be true.

To run only a local-conversion target from mixed config:

pnpm exec sxl-export-icons sync --config ./sxl-export-icons.config.yaml --target font-subset-local

Description marker filter

You can control export in Figma description of COMPONENT / COMPONENT_SET:

sxl-studio-export-icon: true

or

sxl-studio-export-icon: false

Config:

sources:
  - id: ds-icons
    descriptionExportMarker:
      key: sxl-studio-export-icon
      includeWhenMissing: true

Rules:

  • marker true -> include
  • marker false -> exclude
  • marker missing -> use includeWhenMissing

What is exported

  • Only COMPONENT nodes.
  • For COMPONENT_SET, exports each COMPONENT variant child as a separate item.
  • Variant matching works with arbitrary property names (for example styleMode, platform, state, ...), not only style.
  • If source sets sectionName/sectionId, items outside that section are skipped.

One or multiple formats

  • target.output.format is a single format per target.
  • To export the same source in multiple formats, add multiple targets with shared sourceIds.
targets:
  - id: icons-svg
    sourceIds: [ds-icons]
    output:
      path: assets/icons/svg
      format: svg
      scale: 1
      quality: 100
      qualitySize: null
      width: null
      height: null
      modeWH: null
  - id: icons-webp
    sourceIds: [ds-icons]
    output:
      path: assets/icons/webp
      format: webp
      scale: 1
      quality: 90
      qualitySize: null
      width: null
      height: null
      modeWH: null

Incremental diff behavior

Scope identity: sourceId::targetId.

  • NEW — node appears first time in scope.
  • UPDATEDupdatedAt/fingerprint changes, file missing, format changed, or scope config hash changed.
  • DELETED — node removed from source scope.
  • RENAMED — canonical name/path changes while format stays same.
  • UNCHANGED — no content and no config-impact changes.

State file stores scope metadata, config hash, and exported item hashes. For REST sources, node fingerprints are computed from render-relevant node data (geometry=paths), so pure vector-shape edits are detected even when metadata timestamps stay unchanged.

Bootstrap behavior (first run without scope state):

  • every matched icon is treated as NEW and re-exported;
  • this guarantees replacement/update even when files already exist on disk.
  • with --adopt-existing, existing files are adopted as UNCHANGED baseline instead of forced re-download.

Optional strict cleanup:

  • set download.pruneUntracked: true to remove files with the same target format in output.path that are not present in current Figma scope.
  • enable it only for dedicated output directories, because cleanup is path+format based.

Output policies

  • Paths are resolved relative to config file location.
  • Export outside workspace is blocked by default.
  • To allow external absolute/relative destinations set:
safety:
  allowOutsideWorkspace: true

Post-processing

  • svg -> SVGO optimization
  • png/jpg -> Sharp optimization + optional resize
  • webp -> export PNG from Figma, then convert to WebP
  • gif -> export PNG from Figma, then convert to GIF
  • pdf -> direct Figma export

Convert-only targets (no download)

If icons already exist locally and you only need font/SF conversion:

targets:
  - id: icons-font-only
    mode: convert-local
    sourceIds: []
    download:
      enabled: false
    output:
      path: assets/icons/svg
      format: svg
      scale: 1
      quality: 100
      qualitySize: null
      width: null
      height: null
      modeWH: null
    naming:
      case: kebab
      separator: "-"
      pattern: "{variant.style}{baseName}"
      includeSectionName: false
      collisionStrategy: add-nodeid
    font:
      enabled: true
      path: assets/icons/font
      formats: [woff2, woff, ttf, eot]
      fontName: ds-icons
      includeNames: [filled-casino-menu, outline-casino-menu]

Notes:

  • download.enabled: false skips file mutation (no download/rename/delete);
  • font.includeNames limits conversion to a selected subset;
  • names in font.includeNames / excludeNames can be provided with or without .svg;
  • source SVG files must already exist in output.path.

Font pipeline

  • Adapter-based interface with webfonts-generator default engine.
  • Supports woff2, woff, ttf, svg, eot.
  • Preserves stable codepoints (codepoints.json) between runs.
  • Generates preview (preview.html) + stylesheet.

SF Symbols pipeline

  • Generates Assets.xcassets/*.symbolset.
  • Uses symbol-rendering-intent in generated Contents.json.
  • Rejects complex SVG features (gradients, filters, masks, embedded images).

Multi-config usage

You can run many configs in one call:

pnpm exec sxl-export-icons sync \
  --config packages/ds-a/sxl-export-icons.config.yaml \
  --config packages/ds-b/sxl-export-icons.config.yaml \
  --report .reports/icons-mono.json

Or by glob:

pnpm exec sxl-export-icons sync --config-glob "packages/*/sxl-export-icons.config.yaml"

For multiple pages/sections from the same Figma file, define separate sources with the same fileKey/fileKeyVar and different pageName/sectionName.

Naming token notes (variant.*)

  • variant is a reserved token namespace in naming.pattern.
  • variant.<propName> uses any Figma variant property name (for example style, type, size, state).
  • Multi-prop naming is supported by chaining tokens:
    • "{prefix}{pageName}{variant.style}{variant.type}{baseName}"
  • If a property is missing for a node, that segment is skipped. In mixed sets this can cause collisions, so use collisionStrategy and/or add disambiguators like {sectionName} or {nodeId}.

Duplicate preflight (before download)

When duplicate output names are detected, CLI prints the full duplicate list (name + node id + variant props) and asks for action:

  • refresh — re-read source and re-check duplicates (after you fix names in Figma)
  • skip — keep one node and skip duplicate entries
  • all — download all duplicates using rename strategy (add-nodeid / add-index)
  • abort — stop sync

Interactive TTY mode uses keyboard selection (/ + Enter) instead of manual text input.

In non-interactive mode (CI), prompts are skipped and configured collisionStrategy is applied automatically.

Troubleshooting

  • Missing Figma token -> set env var from env.figmaTokenVar.
  • Path ... is outside workspace -> enable safety.allowOutsideWorkspace.
  • Bridge session is not connected -> start Utils/bridge, open plugin, enable Remote Connect.
  • Naming collision detected -> change naming.pattern or use collisionStrategy: add-nodeid/add-index.
  • Too many 429 responses -> lower downloadSpeed for source.

Contract references used in implementation

  • Figma REST: GET /v1/files/:key, GET /v1/images/:key, components/component_sets metadata endpoints.
  • Sharp conversion/encoding docs for WebP/GIF/resize.
  • webfonts-generator formats and options.

This utility keeps those contracts explicit in code and docs to reduce drift and regression risk.