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

@svgsketch/core

v0.4.0

Published

Core types, document format, and rendering engine for SVGSketch

Downloads

192

Readme

@svgsketch/core

Core SDK, renderer, and document engine for SVGSketch. This package defines the .svgs file format and provides everything needed to build, serialize, load, validate, render, and migrate SVGSketch documents programmatically — no browser or editor required.

Install

npm install @svgsketch/core

Quick start

import { Document, Circle, Rectangle } from '@svgsketch/core';

const doc = new Document({ width: 400, height: 300 })
  .title('Hello')
  .add(new Circle(200, 150, 80).fill('#2563eb'))
  .add(new Rectangle(10, 10, 100, 60).fill('#ef4444').cornerRadius(8));

const svg = doc.toSVG();      // rendered SVG string
const svgs = doc.toJSON();    // canonical `.svgs` document

What it includes

| Module | Exports | | ----------- | --------------------------------------------------------------- | | types | HistorySnapshot, SerializedShape, SerializedSymbolDef, … | | format | parseDocument, stringifyDocument, migrateSnapshot, validateSnapshot, substituteVariables | | renderer | renderToSvg | | sdk | Document, Circle, Rectangle, …, Timeline, Track | | codegen | generateCode — SVG / React / Vue / D3 / CSS output |

The .svgs format

A .svgs file is a deterministic JSON serialization of a HistorySnapshot — the complete state of an SVGSketch document. It is designed for:

  • Git-friendly diffs: canonical key ordering, one property per line.
  • Round-trip fidelity: every editor-persisted field survives save → load → render without loss.
  • External tooling: the schema is fully typed in @svgsketch/core and can be produced or consumed without running the editor.

Top-level structure

{
  "schemaVersion": 1,
  "documentMetadata": { /* title, author, license, … */ },
  "templateVariables": [ /* { name, type, defaultValue, … } */ ],
  "viewboxes":        [ /* { id, x, y, width, height } */ ],
  "guides":           [ /* { id, orientation, position, … } */ ],
  "measurements":     [ /* dimensioning annotations */ ],
  "groups":           [ /* { id, parentId, siblingIndex, … } */ ],
  "clipMaskGroups":   [ /* <clipPath> / <mask> definitions */ ],
  "customPatterns":   [ /* user-defined fill patterns */ ],
  "symbols":          [ /* reusable component definitions */ ],
  "animationTimeline": { /* tracks + keyframes */ },
  "shapes":           [ /* array — order IS z-order */ ]
}

See src/types/serialized.ts for the exhaustive schema.

Ordering rules

  • shapes preserves array order — the position of a shape in the array is its painter's-model z-order. Sorting would silently reorder rendering and destroy user intent.
  • Id-keyed collections (groups, viewboxes, guides, clipMaskGroups, customPatterns, symbols) are sorted by id. Their order has no semantic meaning — groups use parentId + siblingIndex to record position.
  • Object keys within each shape are sorted alphabetically.
  • Indentation is 2 spaces, one property per line, with a trailing newline by default.

These rules combine to give identical documents a byte-identical serialization, so diffing .svgs files in git produces meaningful line-level changes rather than noisy reorderings.

Schema versioning

schemaVersion is written on save and checked on load. The constant CURRENT_SCHEMA_VERSION in @svgsketch/core is the latest version. A document missing schemaVersion is treated as version 1.

On load, parseDocument calls migrateSnapshot which walks the MIGRATIONS registry — each entry at key N transforms a version-N snapshot into version-(N+1). Unknown older versions (no migration registered) throw. Newer versions (from-the-future documents) pass through unchanged; loaders should refuse them at a higher layer.

Compatibility rules for schema changes:

  1. Never rename an existing serialized property. Add a new one alongside and read both with a fallback.
  2. Never change a property's type. Add a new property instead.
  3. Never make a previously optional field required without a migration.
  4. Never remove a shape type — old documents referencing it would silently lose shapes.
  5. When adding new optional properties, always handle their absence on the read side with ?? or if-guards.

Template variables & bindings

Two complementary mechanisms for parameterizing documents:

  • {{variable}} references — string placeholders that are substituted at render time. Valid in any string property, and in numeric fields (e.g. radius: "{{r}}") where they resolve to numbers. Defaults live in templateVariables; overrides can be passed to substituteVariables(snapshot, { r: '50' }) or to doc.toSVG({ variables: { r: '50' } }).

  • state.bindings — a map from a geometry property name to a CSS custom-property name (without the leading --). When a property is bound, state[property] holds the resolved value (what the renderer uses if no substitution runs), and bindings records the variable the editor should re-bind to on the next edit. Example:

    {
      "id": "c1",
      "type": "circle",
      "state": {
        "radius": 50,
        "bindings": { "radius": "card-radius" }
      }
    }

Round-trip fidelity

The format guarantees that for any valid snapshot s:

stringifyDocument(parseDocument(stringifyDocument(s))) === stringifyDocument(s);
renderToSvg(parseDocument(stringifyDocument(s))) === renderToSvg(s);

The tests/format/roundtrip.test.ts integration suite enforces this across a document that touches shapes, groups, symbols, template variables, bindings, and animation tracks. When the format grows a new field, that test must still pass — if it regresses, a field is being dropped somewhere in the pipeline.

Validation

validateSnapshot(snapshot) returns { valid, errors, warnings } with dot-paths (e.g. shapes[2].state.width) for each problem. Validation runs automatically on parseDocument unless { validate: false } is passed. Rules include:

  • Shape IDs are unique within a document.
  • type is a known shape type (circle, rectangle, spline, …) or a plugin-registered custom type.
  • Numeric geometry fields (x, y, width, height, radius, …) are finite numbers — or {{variable}} references, which resolve to numbers at render time.
  • Viewbox dimensions are positive.
  • Group references point to existing shapes.

Errors block loading; warnings are surfaced but do not.

Minimal example

import {
  Document,
  Circle,
  parseDocument,
  substituteVariables,
  renderToSvg,
} from '@svgsketch/core';

// Build
const doc = new Document({ width: 200, height: 200 })
  .add(new Circle(100, 100, 75).fill('{{accent}}').id('c1'))
  .defineVariable('accent', 'color', '#3498db');

// Serialize
const svgs = doc.toJSON();

// Deserialize, substitute, render
const snapshot = parseDocument(svgs);
const resolved = substituteVariables(snapshot, { accent: '#e74c3c' });
const svg = renderToSvg(resolved);

CLI

The companion @svgsketch/cli package exposes svgsketch validate, svgsketch render, svgsketch info, svgsketch vars, and svgsketch codegen commands that operate on .svgs files headlessly — suitable for CI/CD pipelines.