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

cross-stitch

v2.0.0

Published

This repository defines a json schema to represent cross stitch patterns and provides javascript/typescript tools to work with them.

Readme

cross-stitch

This repository defines a schema to represent cross stitch patterns and provides javascript/typescript tools to work with them.

For full code documentation, please visit this page.

Installation

Install via npm using the below terminal command

    npm install cross-stitch

Usage

cross-stitch validates and serializes patterns through a small set of functions. The schemas underneath are built with Zod and are published on the cross-stitch/schema subpath (see the Zod schemas below), but you do not need to use Zod directly for everyday work. Parsing never throws, and encodePattern throws only on an invalid pattern (encodePatternSafe is the non-throwing variant). Counts and dimensions are derived on demand and are not stored on the pattern.

import { parsePattern, parsePatternJson, encodePattern, calculateTotals, calculateDimensions } from 'cross-stitch';

// Validate an in-memory value
const result = parsePattern(value);
if (result.success) {
    const pattern = result.data; // fully typed CrossStitchPattern
} else {
    console.error(result.issues); // every problem found, as typed PatternIssue objects
}

// Validate a JSON string. Malformed JSON is reported as an issue, never thrown.
const parsed = parsePatternJson(jsonString);

if (result.success) {
    // Serialize a validated pattern back to a JSON string
    const json = encodePattern(result.data); // or encodePatternSafe(...) for a non-throwing result

    // Counts and dimensions are derived on demand
    const totals = calculateTotals(result.data);
    const { stitchWidth, stitchHeight, offsetX, offsetY } = calculateDimensions(result.data);
}

Each validation problem is a typed PatternIssue, discriminated on kind. Cross-stitch-specific variants carry structured data (unknown-color-reference with the offending colorId, duplicate-color-id, unreachable-placement with its angle and placement, and the segment-span rules), and a schema-violation catch-all covers structural failures. Every issue also carries a path and a human-readable message.

When you build a pattern by hand instead of parsing one, type it as CrossStitchPatternInput - the pre-validation shape that accepts plain numbers for ids and coordinates and lets defaulted fields be omitted - then parse it:

import { parsePattern } from 'cross-stitch';
import type { CrossStitchPatternInput } from 'cross-stitch';

const draft: CrossStitchPatternInput = {
    version: 1,
    colors: [{ id: 0, name: 'Blue', symbol: '@', strands: [{ brand: 'DMC', code: '825', name: 'Dark Blue' }] }],
    stitches: [{ kind: 'full', colorId: 0, x: 0, y: 0 }]
};
const result = parsePattern(draft);

Advanced: the Zod schemas

Every schema is published on the cross-stitch/schema subpath (CrossStitchPattern, CrossStitchPatternJson, Stitch, Color, and the rest), kept off the root import so everyday use never pulls in Zod. Reach for them to compose schemas (.pick, .extend) or to read raw Zod issues; they are the same validators the functions above are built on.

import { z } from 'zod';
import { CrossStitchPattern, CrossStitchPatternJson } from 'cross-stitch/schema';

const result = CrossStitchPattern.safeParse(value); // Zod's native result, with result.error.issues
if (result.success) {
    const json = z.encode(CrossStitchPatternJson, result.data); // or z.safeEncode(...) to avoid throwing
}

The full DMC floss palette is published on a separate subpath so you only load it if you need it:

import { dmcFloss } from 'cross-stitch/dmc';

const orangeSpice = dmcFloss['721']; // e.g. { brand: 'DMC', code: '721', name: 'Orange Spice - Medium', strandCount: 1, hex: '#f27842' }

Not every entry has a hex; it is present only where DMC publishes one.

JSON Schema

A JSON Schema for the pattern document is generated from the Zod schema and published as cross-stitch.schema.json. It is shipped in the package (importable as cross-stitch/schema.json) and carries the canonical $id https://raw.githubusercontent.com/neilcochran/cross-stitch/master/cross-stitch.schema.json, so non-JavaScript tooling can reference it to validate or annotate pattern documents.

It validates document structure only. The semantic rules - three-quarter reachability, unique color ids and symbols, every stitch referencing a color that exists, and the back / long span limits - have no JSON Schema representation and are enforced only by the Zod schema and the parse* functions. Regenerate it with npm run schema.

Versions

View all versions of in the CHANGELOG.md

License

This project is licensed under the MIT License - see the LICENSE.md file for details

CrossStitchPattern Schema:

This section documents the pattern shape. See a full example below.

{
    "schemaVersion": 1,
    "metadata": {},
    "fabric": {},
    "colors": [],
    "stitches": []
}
  • schemaVersion - The version of the cross-stitch document format. Must be the number 1.

  • metadata - An optional Metadata object holding descriptive, non-structural information about the pattern.

  • fabric - An optional Fabric object describing the fabric the pattern is stitched on.

  • colors - An array of Color objects defining the palette used in the pattern.

  • stitches - An array of Stitch objects defining every stitch in the pattern. Each stitch is tagged with a kind.

Beyond per-field validation, a complete pattern must satisfy three whole-pattern rules: color id values are unique, color symbol values are unique, and every stitch's colorId refers to a color that exists.

Metadata Schema:

Optional, descriptive information about the pattern. Every field is optional.

{
    "title": "Tiny Sampler",
    "author": "Jane Stitcher",
    "copyright": "(c) 2024 Jane Stitcher",
    "notes": "A contrived example."
}
  • title - The pattern title.

  • author - The pattern author or designer.

  • copyright - A copyright or license statement.

  • notes - Free-form notes or comments about the pattern.

Fabric Schema:

Describes the fabric the pattern is worked on.

{
    "count": 14,
    "hex": "#f5f5dc",
    "kind": "aida"
}
  • count - The fabric count in stitches per inch (for example 14 for 14-count Aida). A positive integer.

  • hex - An optional fabric color as a #rrggbb hexadecimal string.

  • kind - An optional fabric type, such as aida, evenweave, or linen.

Color Schema:

A Color represents a color used in the pattern. The color is made up of one or more strands of Floss. Each floss strand can be a different color/brand, allowing blended colors to be defined.

{
    "id": 1,
    "name": "Burnt Orange",
    "symbol": "@",
    "strands": []
}
  • id - A non-negative integer identifier referenced by stitches to select this color. Must be unique within the pattern.

  • name - A name for the overall color (since it could be a blend).

  • symbol - A single printable ASCII character (codes 33 to 126) used to represent the color on the chart. Must be unique within the pattern.

  • strands - An array of one or more Floss objects defining the strands that make up the color (its thread composition).

  • hex - The authoritative display color as a #rrggbb hexadecimal string. When present, render this; the strands describe how the color is achieved. Optional.

Floss Schema:

This represents floss of a single color and brand, and by default, a single strand. If more than one strand of the same floss is needed, count can be increased.

{
    "brand": "DMC",
    "code": "721",
    "name": "Orange Spice - Medium",
    "strandCount": 2,
    "hex": "#f27842"
}
  • brand - The name of the brand. See a list of supported brands here.

  • code - A string representing the brand code for the color. This is often a number, but can be a string like Ecru or Blanc.

  • name - The brand's name for the color.

  • strandCount - A positive integer giving the number of strands of this floss to use in the color. If not given, defaults to 1.

  • hex - An optional color value as a #rrggbb hexadecimal string.

Stitch Schema:

Every entry in stitches is one of six kinds, discriminated by its kind field. All stitches carry a colorId referencing a Color.

Coordinates use a lower-left origin. Cell-anchored stitches (full, half, quarter, three-quarter) sit on a grid square and take whole-integer x / y for the lower-left corner of that square. Segment stitches (back, long) take from and to points whose coordinates may also use half-step (0.5) values. No finer fraction is accepted, and all coordinates are non-negative.

Full Stitch Schema:

A full stitch covers a single square on the pattern in an 'X' shape. It is the combination of 2 opposing half stitches.

{
    "kind": "full",
    "colorId": 1,
    "x": 10,
    "y": 20
}
  • kind - The literal "full".

  • x - The x coordinate of the lower left corner of the square.

  • y - The y coordinate of the lower left corner of the square.

Example:

FullStitch image

{
    "kind": "full",
    "colorId": 1,
    "x": 1,
    "y": 1
}

Half Stitch Schema:

A half stitch is one diagonal across a grid square. It comes in two forms named for the corners they connect. A tl-br half goes from the top-left corner to the bottom-right corner. A bl-tr half goes from the bottom-left corner to the top-right corner. These are the only two valid values for angle.

{
    "kind": "half",
    "colorId": 1,
    "x": 10,
    "y": 20,
    "angle": "tl-br"
}
  • kind - The literal "half".

  • x - The x coordinate of the lower left corner of the square.

  • y - The y coordinate of the lower left corner of the square.

  • angle - The half-stitch diagonal: tl-br or bl-tr.

Examples:

Half Stitch tl-br

HalfStitch tl-br image

{
    "kind": "half",
    "colorId": 1,
    "x": 1,
    "y": 1,
    "angle": "tl-br"
}

Half Stitch bl-tr

HalfStitch bl-tr image

{
    "kind": "half",
    "colorId": 1,
    "x": 1,
    "y": 1,
    "angle": "bl-tr"
}

Quarter Stitch Schema:

A quarter stitch spans a quarter of a grid square and can be located in the top-right, bottom-right, bottom-left, or top-left quadrant of the square as indicated by placement. A quarter stitch is a half stitch cut in half: one end is always at the center of the square, and the other extends to the corner indicated by placement.

{
    "kind": "quarter",
    "colorId": 1,
    "x": 10,
    "y": 20,
    "placement": "top-right"
}
  • kind - The literal "quarter".

  • x - The x coordinate of the lower left corner of the square.

  • y - The y coordinate of the lower left corner of the square.

  • placement - The corner of the square the quarter stitch reaches: top-right, bottom-right, bottom-left, or top-left.

Examples:

Quarter Stitch Top Right

QuarterStitch top right image

{
    "kind": "quarter",
    "colorId": 1,
    "x": 1,
    "y": 1,
    "placement": "top-right"
}

Quarter Stitch Bottom Right

QuarterStitch bottom right image

{
    "kind": "quarter",
    "colorId": 1,
    "x": 1,
    "y": 1,
    "placement": "bottom-right"
}

Quarter Stitch Bottom Left

QuarterStitch bottom left image

{
    "kind": "quarter",
    "colorId": 1,
    "x": 1,
    "y": 1,
    "placement": "bottom-left"
}

Quarter Stitch Top Left

QuarterStitch top left image

{
    "kind": "quarter",
    "colorId": 1,
    "x": 1,
    "y": 1,
    "placement": "top-left"
}

Three Quarter Stitch Schema:

A three quarter stitch is a half stitch plus a quarter stitch in the same square, so both an angle and a placement are given. The quarter can only reach the two corners the half does not occupy. A tl-br half occupies the top-left and bottom-right corners, so its quarter is top-right or bottom-left. A bl-tr half occupies the bottom-left and top-right corners, so its quarter is top-left or bottom-right.

{
    "kind": "three-quarter",
    "colorId": 1,
    "x": 10,
    "y": 20,
    "angle": "tl-br",
    "placement": "top-right"
}
  • kind - The literal "three-quarter".

  • x - The x coordinate of the lower left corner of the square.

  • y - The y coordinate of the lower left corner of the square.

  • angle - The half-stitch diagonal: tl-br or bl-tr. See the Half Stitch schema.

  • placement - The corner the quarter stitch reaches. Must be reachable for the given angle (see above). See the Quarter Stitch schema.

Examples:

Three Quarter Stitch Top Right (tl-br + top-right)

ThreeQuarterStitch top right image

{
    "kind": "three-quarter",
    "colorId": 1,
    "x": 1,
    "y": 1,
    "angle": "tl-br",
    "placement": "top-right"
}

Three Quarter Stitch Bottom Left (tl-br + bottom-left)

ThreeQuarterStitch bottom left image

{
    "kind": "three-quarter",
    "colorId": 1,
    "x": 1,
    "y": 1,
    "angle": "tl-br",
    "placement": "bottom-left"
}

Three Quarter Stitch Top Left (bl-tr + top-left)

ThreeQuarterStitch top left image

{
    "kind": "three-quarter",
    "colorId": 1,
    "x": 1,
    "y": 1,
    "angle": "bl-tr",
    "placement": "top-left"
}

Three Quarter Stitch Bottom Right (bl-tr + bottom-right)

ThreeQuarterStitch bottom right image

{
    "kind": "three-quarter",
    "colorId": 1,
    "x": 1,
    "y": 1,
    "angle": "bl-tr",
    "placement": "bottom-right"
}

Back Stitch Schema:

Back stitches can go laterally, vertically, or diagonally. A back stitch may span at most one grid space in each direction; half-step (0.5) coordinates are supported. A segment longer than one space must be split into multiple back stitches (or use a Long Stitch).

{
    "kind": "back",
    "colorId": 1,
    "from": { "x": 0, "y": 0 },
    "to": { "x": 1, "y": 0 }
}
  • kind - The literal "back".

  • from - The start point of the stitch as { x, y }.

  • to - The end point of the stitch as { x, y }.

Examples:

Back Stitch Lateral

BackStitch lateral image

Red:

{
    "kind": "back",
    "colorId": 1,
    "from": { "x": 1, "y": 1 },
    "to": { "x": 2, "y": 1 }
}

Green:

{
    "kind": "back",
    "colorId": 1,
    "from": { "x": 1, "y": 2 },
    "to": { "x": 1.5, "y": 2 }
}

Back Stitch Vertical

BackStitch vertical image

Red:

{
    "kind": "back",
    "colorId": 1,
    "from": { "x": 2, "y": 1 },
    "to": { "x": 2, "y": 2 }
}

Green:

{
    "kind": "back",
    "colorId": 1,
    "from": { "x": 1, "y": 1 },
    "to": { "x": 1, "y": 1.5 }
}

Back Stitch Diagonal

BackStitch diagonal image

Red:

{
    "kind": "back",
    "colorId": 1,
    "from": { "x": 1, "y": 2 },
    "to": { "x": 2, "y": 1 }
}

Green:

{
    "kind": "back",
    "colorId": 1,
    "from": { "x": 0, "y": 1 },
    "to": { "x": 0.5, "y": 1.5 }
}

Long Stitch Schema:

Long stitches span more than one space. They can move laterally, vertically, or diagonally just like back stitches, and they also support half-step (0.5) coordinates, but they have no maximum length.

{
    "kind": "long",
    "colorId": 1,
    "from": { "x": 0, "y": 0 },
    "to": { "x": 5, "y": 2 }
}
  • kind - The literal "long".

  • from - The start point of the stitch as { x, y }.

  • to - The end point of the stitch as { x, y }.

Examples:

LongStitch image

Red:

{
    "kind": "long",
    "colorId": 1,
    "from": { "x": 0, "y": 3 },
    "to": { "x": 2.5, "y": 0 }
}

Green:

{
    "kind": "long",
    "colorId": 1,
    "from": { "x": 0, "y": 3 },
    "to": { "x": 3, "y": 3 }
}

Totals and Dimensions:

Stitch counts and pattern size are not stored in the schema. Derive them from a validated pattern with the exported helpers:

  • calculateTotals(pattern) returns the overall stitch counts and a per-color breakdown ({ total, byColor }). total is a count object with one entry per stitch kind, keyed by camelCase name (full, half, quarter, threeQuarter, back, long), so counts read as total.threeQuarter. Each byColor entry is { colorId, counts }, where counts is a count object of the same shape, so per-color counts read as byColor[0].counts.threeQuarter.

  • calculateDimensions(pattern) returns { stitchWidth, stitchHeight, offsetX, offsetY } in whole stitches: the width and height of the stitched area's bounding box, plus the lower-left offset of that box (both offsets are 0 when the pattern is anchored at the origin or has no stitches).

  • stitchBounds(stitch) returns the axis-aligned bounding box ({ minX, minY, maxX, maxY }) of a single stitch, normalizing the cell-anchored and segment shapes into one position-and-extent value.

Full Schema Example:

The image below shows a tiny 3x3 pattern that uses every stitch kind. Here is the JSON that describes it:

full pattern example image

{
    "schemaVersion": 1,
    "metadata": {
        "title": "Tiny Sampler",
        "notes": "A tiny 3x3 example using every stitch kind."
    },
    "fabric": {
        "count": 14,
        "kind": "aida"
    },
    "colors": [
        {
            "id": 0,
            "name": "Dark Blue",
            "symbol": "@",
            "strands": [
                {
                    "brand": "DMC",
                    "code": "825",
                    "name": "Dark Blue",
                    "strandCount": 2
                }
            ]
        },
        {
            "id": 1,
            "name": "Orange Blend",
            "symbol": "&",
            "strands": [
                {
                    "brand": "DMC",
                    "code": "721",
                    "name": "Orange Spice",
                    "strandCount": 1
                },
                {
                    "brand": "DMC",
                    "code": "947",
                    "name": "Burnt Orange",
                    "strandCount": 1
                }
            ]
        }
    ],
    "stitches": [
        { "kind": "full", "colorId": 0, "x": 0, "y": 1 },
        { "kind": "three-quarter", "colorId": 0, "x": 2, "y": 1, "angle": "tl-br", "placement": "top-right" },
        { "kind": "half", "colorId": 1, "x": 1, "y": 1, "angle": "bl-tr" },
        { "kind": "quarter", "colorId": 1, "x": 2, "y": 0, "placement": "bottom-right" },
        { "kind": "back", "colorId": 1, "from": { "x": 0, "y": 0 }, "to": { "x": 1, "y": 0 } },
        { "kind": "long", "colorId": 1, "from": { "x": 0, "y": 3 }, "to": { "x": 3, "y": 2 } }
    ]
}

Supported brand values:

  • Anchor
  • Appletons
  • Cosmo
  • DMC
  • J&P Coats
  • Kreinik
  • Madeira
  • Presencia
  • Sullivans
  • Unbranded