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

seamlint

v0.1.0

Published

Geometry checker for sewing patterns: measures seam edges, notches, and curve continuity from DXF/SVG

Downloads

149

Readme

Seamlint

CI

A read-only geometry linter for sewing pattern pieces.

日本語版: README.ja.md

What is Seamlint?

Seamlint reads an exported pattern path (SVG, or ASTM DXF), samples it into points, and returns structured geometry diagnostics — sharp direction changes, seam length mismatches, endpoint gaps, tangent mismatches, ease and gather ratios, and open loops.

It is a measuring tool, not a CAD engine. Seamlint never edits a pattern and never auto-fixes. The value is a fast, explainable answer to "does this seam actually measure up?" — and, just as important, an explicit "cannot measure" when the geometry assumptions are broken, instead of a confident wrong number.

The current prototype is intentionally small: no runtime dependencies, MVP SVG command support, and a narrow, well-defined boundary with Loomit.

Quick Start

Requirements: Node.js 24+.

npm run check:sample        # curve kink on the sample SVG (text)
npm run check:sample-json   # same, as JSON
Seamlint: warning
Target: body-armhole
Length: 249.609 mm

[warning] geometry.curve_kink
  Path direction changes sharply near sampled point 27.
  target: body-armhole
  actual: {"angleDeg":45.809,"point":{"x":120,"y":72}}
  expected: {"maxAngleDeg":25}
  suggestion: Check whether this is an intentional corner or an unwanted kink.

CLI

Seamlint has three read-only subcommands. Text output is the default; --json prints machine-readable diagnostics.

slnt check   <svg> --path <id> [--compare-to <id>] [--expect-smooth] [--closed] [--json]
slnt inspect <svg> [--json]
slnt check-request [request.json] [--json]

During the MVP (the package is not published yet) run it directly:

node ./src/cli/slnt.ts <command> ...

slnt check

Measures one SVG path. With --compare-to, it compares two paths — by default seam length, or with --expect-smooth the endpoint gap + tangent. A single path is also checked for sharp direction changes (geometry.curve_kink).

# Compare two seams with a strict length tolerance
node ./src/cli/slnt.ts check ./examples/armhole-kink.svg \
  --path body-armhole --compare-to sleeve-cap --length-tolerance-mm 0.5

# Check two endpoints join smoothly
node ./src/cli/slnt.ts check ./examples/smooth-join.svg \
  --path front-yoke --compare-to front-panel --expect-smooth

# Check a path expected to close is actually closed
node ./src/cli/slnt.ts check ./examples/open-loop.svg --path neckline-loop --closed

| option | default | meaning | |---|---|---| | --compare-to <id> | — | Compare with another path in the same SVG | | --expect-smooth | off | With --compare-to, check smooth join (gap + tangent) instead of length | | --closed | off | Expect the selected path to be a closed loop | | --json | off | Print JSON diagnostics | | --curve-steps <n> | 24 | Minimum samples per Bézier segment (long curves are subsampled finer by arc length) | | --angle-threshold-deg <n> | 25 | Curve kink warning threshold | | --length-tolerance-mm <n> | 3 | Seam length warning threshold | | --endpoint-tolerance-mm <n> | 0.5 | Endpoint gap warning threshold | | --tangent-tolerance-deg <n> | 8 | Tangent mismatch warning threshold |

Exit code: error status → 1; ok/warning0. A warning alone does not fail the command.

slnt inspect

Inspects an exported SVG before trusting it for measurement — viewBox vs physical size, path ids (and duplicates), path/ancestor transforms, and marker-like elements.

node ./src/cli/slnt.ts inspect ./path/to/exported.svg --json

slnt check-request

Reads a Loomit GeometryCheckRequest (JSON, self-contained with inline geometryText) from a file argument or stdin, runs it, and prints a GeometryRequestReport. See Loomit integration below.

Library API

Seamlint can also be used as a local Node package API — an importable entrypoint for tools such as Loomit, not a Web API or server. It does not read files: callers load SVG/DXF text and pass it in, and Seamlint returns structured reports.

import { checkSvgPath } from "seamlint";

const report = checkSvgPath(svgText, {
  path: "body-armhole",
  compareTo: "sleeve-cap",
  lengthToleranceMm: 0.5
});

When the comparison path lives in a different SVG document, pass that source explicitly:

const report = checkSvgPath(bodySvgText, {
  path: "body-armhole",
  compareTo: "sleeve-cap",
  compareSvgText: sleeveSvgText,
  lengthToleranceMm: 0.5
});

Run a batch of checks over preloaded geometry sources:

import { checkGeometryRequest } from "seamlint";

const report = checkGeometryRequest(request, {
  sources: {
    "./body.svg": bodySvgText,
    "./sleeve.svg": sleeveSvgText
  }
});

Other exports: inspectSvgExport(svgText, options) for the pre-measurement inspection, pointsForPath(svgText, id, options) for the sampled polyline, and projectAstmPassmarkToMarker(dxfText, blockName, point) for the ASTM passmark → marker projection helper. See src/types.ts for the full option and report shapes.

Loomit integration

Seamlint owns geometry measurement. Loomit owns project metadata, connector identity, assembly interpretation, and which artifact is the source of truth. The two communicate over a narrow GeometryCheckRequest contract via a subprocess + stdio JSON handoff — Loomit and Seamlint build independently.

loom slnt check
  → build a self-contained request (each part carries inline geometryText + format)
  → spawn: slnt check-request --json  (request JSON on stdin)
      ← Seamlint runs checkGeometryRequest → GeometryRequestReport on stdout (JSON)

Each check declares a JoinKind — what should be true geometrically:

  • sewn-seam — two edges should be the same finished length
  • eased-seam — one edge is intentionally longer, within an ease ratio
  • gathered-seam — a marked range gathers into another, within a gather ratio
  • seam-edge — two DXF parts sew along a shared edge; Seamlint finds which edge from the geometry
  • band-seam — a band meets several pieces whose finished edges (× cut quantity) sum to it, within a closure ratio (DXF only)
  • smooth-continuation — two endpoints meet with no gap and matching tangent (same source only)
  • closed-loop — a path expected to close actually closes

Correspondence points (notches/passmarks) are declared upstream; Seamlint never infers those. For the DXF seam-edge and band-seam kinds it does discover which edge the declared parts sew along — by length + notch signature, or, for a band's neighbours, by dart-fold — but that is edge discovery from the geometry, not inventing new correspondence points.

Coordinate assumptions & compatibility

Seamlint measures raw path coordinates and treats 1 SVG user unit as 1 mm. To avoid silently reporting wrong sizes, it refuses (with an error diagnostic) rather than guessing when:

  • a <path> or an enclosing <g> carries a transform (geometry.unsupported_transform), or
  • the root <svg> has a physical width/height that disagrees with its viewBox extent, i.e. a non-unit scale (geometry.unsupported_viewbox_scale).

MVP SVG support is limited to M, L, H, V, C, Q, and Z; other commands raise geometry.unsupported_svg_command. SVGs with no viewBox, or unitless/px sizes, are still assumed to be 1 unit = 1 mm — bake transforms into the coordinates and export at 1:1 before checking.

ASTM DXF is also supported as a geometry source: a pathRef resolves to a BLOCK, and the closed layer 14 polyline (the net/sewn line) is measured. When a closed layer 1 outline (the cut line) is present, Seamlint verifies the seam sits inside it rather than trusting the layer label alone.

Diagnostics

All results are structured data first; the CLI renders them. code, severity, target, expected, and actual are a compatibility surface that downstream tools read as JSON, so they are not renamed casually.

  • warning — a likely design/geometry issue for a human to review (does not fail the command)
  • error — the check could not be trusted or completed (too few points, path not found, unsupported command, non-mm unit, detected transform, …)

This is a measuring tool, not a CAD engine. Later versions can replace the MVP parser and sampler with libraries such as svg-pathdata, svg-path-properties, or bezier-js.

How This Was Built

Seamlint is built with AI coding agents, directed by me. The design, the geometry contracts, and every judgment call are mine; the agents write the code under the rules I set, which live in AGENTS.md. One of those judgment calls shapes the whole tool: Seamlint's numbers flow into physical cutting, so the worst failure is a confidently-wrong measurement, not a crash — when the geometry assumptions are broken it must return an explicit error rather than a quiet guess. The reasoning behind the design, including the choices I reversed and why, is recorded in the project's design history.

Status

Early prototype — a public alpha in preparation, not a published package yet (package.json is still private at 0.0.0).

Measures today — curve kinks, seam-length match, endpoint gap + tangent, open loops, and ease / gather ratios, over SVG or ASTM DXF. On DXF it splits a piece's net line into structural edges (darts, notches, bands) and measures the shared seam edge between two declared parts, disambiguating with a notch-count signature. It already runs end-to-end from Loomit over the GeometryCheckRequest subprocess contract.

Deliberately out of scope — Seamlint never edits, never auto-fixes, and never infers correspondence points; it refuses (with an error) to measure geometry whose assumptions are broken rather than returning a confident wrong number. Reading .val directly, an npm install path, and auto-normalizing exported SVG are not there yet.