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

@create-design/source

v0.4.0

Published

Deterministic source formats for create-design documents

Readme

@create-design/source

@create-design/source owns the deterministic source boundary for create-design. It exposes the current complete DesignDocument model and a repository-native directory codec that splits independently editable facts into validated JSON units.

Complete document versions

Complete documents use a strict, version-dispatched codec. Version six is the current schema. It replaces v5's optional root scene with a nonempty ordered layers collection. Each layer persists a stable ID, display name, ordered object/group children, a symbolic UI color, and optional hidden and locked states. UI colors are planning metadata: they never become artwork paint or affect PDF, SVG, or PNG output. Canonical colors follow the fixed order red, blue, yellow, purple, green, pink, cyan, orange, indigo, lime, magenta, and teal; readers assign missing legacy colors by layer order and cycle after the twelfth layer. Every object and group has exactly one structural parent, and groups cannot cross layer boundaries. Version five introduced the nonempty ordered artboards collection; each artboard persists a stable ID, display name, global { x, y, width, height } rectangle, and optional nonnegative bleed/safeArea edge insets. Array order is canonical output order; active artboard and active layer state are deliberately absent from the document. decodeDesignDocument() accepts complete version-one through version-five documents and deterministically migrates them to v6. A v5 scene, or the object order when scene is absent, becomes the children of one visible, unlocked layer:artwork named Artwork. Every legacy page becomes the single equivalent artboard:page named Artboard 1. Existing object IDs, group IDs, hierarchy paint order, global coordinates, geometry, transforms, and appearance are preserved. Missing v1/v2 path IDs are derived from the owning object and source order, and their artboard receives the legacy implicit origin (0, 0). Prior width-only strokes receive the renderer-neutral butt cap, miter join, miter limit 4, and solid-dash defaults. The v1 decoder continues to accept both shipped object forms: canonical geometry/transform/appearance objects are migrated, while older { contours, fillId } objects become path geometry with an identity transform and fill appearance. validateDesignDocument() validates only the current version, while parseDesignDocumentText() additionally owns JSON decoding.

Malformed, partial, and future-version inputs fail with field-located diagnostics. Callers must retain their last valid document when decoding fails; createInitialDocument() provides the canonical new-authoring default shared by browser and headless callers, while version-specific migration defaults remain internal to the codec.

Coordinate and identity contract

Canonical geometry lives in one unbounded global document plane measured in points. X increases right and Y increases down. Object geometry is local to its object and reaches the global plane only through the object's persisted affine transform. Artboards are independent named rectangles in that plane; ordinary objects are not artboard children. Artwork may intersect several artboards or none. Adding, moving, resizing, renaming, or reordering an artboard must therefore never rewrite object geometry or transforms. Guides use the same global axis values.

Canvas world coordinates are identical to document coordinates; pan and zoom are view-only transforms. Native create-design clipboard objects remain in the global Y-down plane. Shared create-* vector and font-outline clipboard payloads use an artboard-independent Cartesian Y-up plane, so their boundary conversion is (x, y) -> (x, -y) for points and vectors. PDF lowering derives a page-local, bottom-left Y-up transform from the selected artboard: [1 0 0 -1 -artboard.x artboard.y+artboard.height]. These clipboard and PDF transforms, including any deliberate paste offset, are projections and never canonical geometry mutations.

Clipboard formats do not carry editable create-design layers. Copies therefore flatten visible objects in canonical layer/group paint order, omit objects from hidden layers, and retain visible locked-layer artwork without changing the source document's authored descendant flags.

Object IDs are document-wide. Contour and point IDs are required and unique within their owning object. Edits preserve every unaffected identity. Copying or deriving a distinct object assigns a new object ID and new path IDs; transforming, renaming, restyling, reordering, editing an artboard, or projecting to canvas/PDF does not. This is the foundation expected by multi-selection work in #254 and global multi-artboard/output work in #283.

Version-four directory

The fourth directory version matches the current application model: ordered artboards, ordered first-class layers, authored path/rectangle/ellipse geometry, independent affine object transforms, optional fill/stroke appearance, one palette, structural groups, and empty asset and font inventories. Path geometry may persist an explicit nonzero or evenodd fill rule; omitted legacy rules retain the original even-odd rendering behavior.

create-design.json
document.json
palette.json
artboards/
  index.json
  page.json
scene/
  layers/
    index.json
    artwork.json
  groups/
    index.json
  objects/
    index.json
    <indexed path>.json
    <indexed path>.txt  # one adjacent raw unit per live-text object
assets/
  index.json
fonts/
  index.json

Each fact has one owner:

  • document.json owns the title, guides, and live blend records;
  • palette.json owns ordered swatches;
  • the ordered artboard inventory owns output order and maps each stable ID to an independent unit that owns its name, global rectangle, and optional bleed/safe-area metadata;
  • the layer inventory owns layer order while each layer unit owns only its display metadata (including UI color), flags, and direct root children;
  • each group unit owns its ordered object or nested-group children;
  • the object inventory maps stable object IDs to stable source paths; and
  • each object JSON owns geometry, typography, frame, transform, and appearance; for a live-text object its durable geometry.contentPath references the exactly adjacent .txt unit that owns the authored characters.

For example, object:headline has a deterministic safe adjacent pair such as scene/objects/object%3Aheadline~72f07290.json and scene/objects/object%3Aheadline~72f07290.txt. The raw unit is UTF-8 text, not JSON: it has no quoting or wrapper, receives no automatic terminal newline, and preserves authored LF, CRLF, lone CR, whitespace-only/empty content, bidi text, Unicode scalars, and terminal newlines. Writers do not add a transport BOM; an authored leading U+FEFF is content and round-trips unchanged.

Object inventory order has no scene meaning. Renaming or editing structured object properties changes only its JSON unit, while a content-only text edit produces a narrow .txt diff. Reordering changes only the layer unit. IDs, display names, source paths, and stacking order are independent.

Structural groups, embedded fonts, and layers have explicit inventories. Groups are active and may nest; every object and group must have exactly one structural parent. Empty, hidden, and locked layers are retained. Source versions before four require the singleton layer:artwork; their version-one layer unit is deterministically named Artwork. The font inventory remains empty where the current DesignDocument has no faithful model. Asset inventory entries are active: each records a stable ID, safe path, media type, byte length, and SHA-256 digest. Asset bytes remain outside the JSON directory codec and are transferred atomically through @create-art/source-rpc; image decoding and placement semantics remain editor concerns.

Directory readers also accept source versions one and two and the earlier { contours, fillId } object-unit shape and deterministically normalize it to path geometry, an identity transform, and a fill appearance. They accept the originally shipped implicit (0, 0) artboard origin and missing path IDs, then assign the same v3 migration defaults as the complete-document decoder. Readers also normalize prior width-only stroke object units. Inline geometry.text from earlier sources hydrates without loss; the next canonical save atomically migrates it to object-version-two JSON plus the raw .txt sidecar. Writers emit the explicit ordered named global artboards, stable path IDs, and canonical separated object shape, ordered named layers, and mark the assembled complete document as version six. Splitting an artboard edit changes only that artboard unit; reordering changes only artboards/index.json; and object units retain byte-equivalent semantic values.

Authored path contours and points always carry stable id fields after assembly. Expansion and paste assign fresh identities so selection and later path edits never depend on array indexes.

Path contours also retain their explicit closed state. closed: false is canonical, lossless source rather than an incomplete document: directory and complete-document codecs preserve the open endpoints and their dangling controls exactly. Painting/lowering policy is intentionally downstream—fills derive the conventional straight endpoint closure, while strokes, direct editing, and explicit Close Path commands continue to use authored topology.

Live blend records persist a stable blend ID, two ordinary object IDs, the number of intermediate steps, and explicit contour/point correspondence. They never persist derived intermediate objects. Missing endpoints and stale correspondence remain schema-valid so the model can report a recoverable, entity-located diagnostic instead of making a project unreadable.

Use

import {
	assembleDesignDocument,
	splitDesignDocument,
} from "@create-design/source"

const split = splitDesignDocument(document)
if (!split.ok) throw new Error(split.errors[0].message)

const assembled = assembleDesignDocument(split.value)
if (!assembled.ok) throw new Error(assembled.errors[0].message)

Collection indexes explicitly pair IDs and safe relative paths. Assembly rejects missing and orphan units, unknown files, duplicate IDs and paths, indexed/contained identity mismatches, missing swatches, and objects without exactly one structural parent. Diagnostics retain both a source-unit path and a JSONPath-like field location.

formatSourceUnit() uses the versioned @create-art/source-format dprint contract. It emits readable, recursively key-sorted JSON with author array order, negative zero, and exactly one trailing newline preserved. Call it only from the trusted Node source-service boundary; browser code parses, validates, and submits semantic unit values without formatting them. Raw text units bypass JSON formatting and are written directly from the authored string. Derived canvas state, selection, bounds, blend steps, shaped glyphs, PDF data, previews, and export artifacts do not belong in canonical source.