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

@mark1russell7/layout-contract

v0.3.2

Published

The shared contract of the packing and highways layout engines: the input and record formats, the turn rule, margins, tolerances and hard rules.

Readme

@mark1russell7/layout-contract

The shared contract of two layout engines: packing places boxes, and highways routes the edges between them. Neither engine depends on the other. Both use this contract, so a placement and a routing compose.

The package has one runtime dependency: @mark1russell7/rigor-generators, the home of the seeded generator mulberry32.

The contents

| Part | Exports | |---|---| | Geometry | Point, Rect, Region, Side, Sides, Margin, marginSides, grow, boundsOf, regionArea, translate, overlapOf | | The shape kinds | ShapeKind, SHAPE_KINDS, SHAPE_KIND_IDS, ShapeKindSpec, ShapeGeometry, DEFAULT_SHAPES, ShapeSupport, ShapeBound, RuleLevel, ShapeLevel, ShapeCheck, isShapeKind, shapeKindOf, shapeKindsOf, itemShapeOf, shapeKindProblem, shapesOf, ruleLevel, shapeLevel, shapeSupportProblems, boxArea, checkShapes | | The input layout-input/1 | LayoutInput, LayoutBox (Item for the packer), Port, portPoint, LayoutEdge, LayoutContainer, Obstacle, LayoutCell, LayoutGenerator, PairGap, canonicalInput | | The packer | PackInput, PackLink, toPackInput, packLinks, Placement, PackOutput, StageTrace, applyPack | | The record layout-record/1 | LayoutRecord, Stage, Supports, RunFacts, RunEnv, toLayoutRecord, checkLayoutRecord, parseLayoutRecord | | The strategies | StrategyInfo | | The measures | MeasureSpec, Direction, JointMeasureId, JOINT_MEASURES, JOINT_MOVED_MIN, Verdict, compareMeasure, minEffectOf | | The balance and stability measures | balanceOf, Balance, nearestGaps, procrustesOf, ProcrustesOptions, perChange, balanceMeasures, balanceMeasureSpecs, BALANCE_MEASURE_SUFFIXES, BalanceMeasureSuffix, BALANCE_SIDE_DEPTH, PlacedBox | | Text layout, in the subpath /text | layoutText, TextLayout, TextLayoutOptions, createMeasurer, TextMeasurer, canvasAdvance, AdvanceFn, fontKey, graphemesOf, textMeasures, TEXT_MEASURES, TEXT_UNITS | | The edges step | edgeStep, EdgeShape, EdgeStepParams, EDGE_DENSITY, EDGE_STEP_VERSION | | The random numbers | mulberry32, fnv1a32, stepRandom, randomInt | | The hashes | sha256Hex, canonicalJson, documentHash, outputHash, HashOptions | | The promotion guards | outputGroups, OutputGroup, exercised, ExerciseEvidence | | The portfolio | portfolio, Portfolio, PortfolioKey, PortfolioLevel, PortfolioOptions, PortfolioPick, PortfolioTrace, Member, MemberTrace, MemberStatus, pickMoves | | The pick rule | selectBest, SelectCandidate, SelectLevel, Selection, PickSpec | | The corpus checks | ClaimBreak, checkDeclared, declaredCounts, declaredClaimOf, DeclaredClaim, Declares, corpusHashOf, CorpusEntry | | The families | familyOf, FamilyBy, FamilyCell, FAMILY_ANY_KIND | | The verdict | verdict, VerdictOptions, VerdictResult, VerdictRecord, VerdictSide, VerdictInterval, FamilyVerdict, VerdictPermutation, VerdictSignTest, VerdictLabel, VerdictScope, VerdictBreadth, VERDICT_EXACT_MAX, VERDICT_EXACT_CAP, VERDICT_RUNS, VERDICT_DRAWS, VERDICT_SEED | | The split files | checkSplit, splitFolds, leaveOneSeedOut, splitFileName, SPLIT_SCHEMA, CorpusSplit, SplitFold, SplitCorpus | | The strategy space | StrategySpace, SpaceStage, StageOption, OptionSupports, ShapeFilter, SpaceParam, ParamWhen, MemberRule, SpaceConstraint, OptionRef, StrategyConfig, StageChoice, ParamKind, ParamValue, STRATEGY_SPACE_SCHEMA | | The space functions | checkSpace, checkConfig, canonicalConfig, configId, spaceSize, spaceShapeKinds, paramLevels, enumerateSpace, productSpace, joinConfigs, splitConfig, SpaceSize, SpaceSizeOptions, EnumerateOptions, GridOptions, SampleOptions | | The turn | turnBox, turnPort, turnMargin, turnRegion, turnSide, turnPoint | | The tolerances | EPS, RECORD_EPS, RECORD_SCALE, Tolerance, DEFAULT_TOLERANCE | | The hard rules | countOverlaps, countObstacleHits, regionHitsRect, rectInRegion, countOutside, ContainerTest, countPortsOffBorder, packHard, PackHard, PACK_HARD_RULES, placedRect, checkInput |

The rules

  • The turn. A turn is 90 degrees clockwise, with the y axis down. A point (px, py) of a box of height h goes to (h - py, px). Each side moves one step clockwise. The router gets the turned box and ports, and does not read turn.
  • The margin. A margin is a ring around a box. No other box and no route enters it. A route from a port of the box crosses the ring at a right angle.
  • The gap. The gap is the free space between two boxes with their margins. Routes use it. Two boxes are mA + gap + mB apart.
  • The pair gaps. pairGaps gives a minimum distance to some pairs of boxes: { a, b, gap, lanes? }. For its pair, the gap of an entry replaces mA + gap + mB.
    • The order of a and b has no meaning. A pair without an entry keeps its margins and the global gap.
    • lanes is the count of the channels that the gap has space for. It is information only.
    • checkInput refuses an unknown box, a pair of one box, a repeated pair in either order, a negative or infinite gap and bad lanes.
    • canonicalInput puts a before b in each pair and sorts the list. documentHash uses this form, so an input without pairGaps keeps its hash.
    • The hard rule no-overlap reads pairGaps. For a pair of the list, in either order, the gap replaces the two margins. The pair breaks the rule only when the boxes are nearer than the gap.
    • The pairs that are not in the list keep their margins. Without pairGaps, the verdicts and the hashes of the records do not change.
  • The ports. A port can have a side. Without a side, the router picks the side. A fixed port has x and y on the border of the box, relative to its top-left corner.
    • A port with side and along is fixed at a fraction of its side. along is a number from 0 to 1, from the start of the side.
    • The start of left and right is the top end. The start of top and bottom is the left end. countPortsOffBorder uses the same start for x and y.
    • checkInput refuses along without a side, a value that is not a finite number from 0 to 1, and along with x or y.
    • portPoint(box, port) gives the point of a port, relative to the top-left corner of the box. A port without a fixed point gives undefined, because the router picks the point.
    • A turn changes along of left and right to 1 - along, because the start of the side moves to its other end. along of top and bottom stays.
    • An input without along keeps its hash.
  • The hard rules of a pack. no-overlap counts the pairs of boxes and the pairs of a box and an obstacle. A pair of pairGaps uses its gap in place of the margins. A locked box without a placement, or with a move of more than RECORD_EPS, breaks locked-kept. checkInput refuses a locked box without a position. Another box without a placement and not in overflow breaks complete.
  • The container rule. in-container counts each box that goes out of the container made smaller by inset. The box counts with its margin. By default, a shaped container counts as its bounding box.
  • The exact container. Give { exactContainer: true } to packHard or countOutside. Then a box of a shaped container with the size fixed must stay inside the shape. A cut corner, a notch and a hole count. A container with a free side keeps the bounding test. The default changes to the exact test at the next breaking version.
  • The shape kinds. An item is a rect, a polygon, a circle or a free shape. Each measure and rule declares its kinds. checkShapes refuses the other kinds. docs/SHAPES.md tells the rules.
    • regionArea(region) gives the exact area of a region. boxArea(box) gives the exact area of a box, or undefined for a free box. A box with an ellipse shape is free.
    • ShapeSupport.safe lists the kinds with a safe count: an upper bound that does not miss a break. ruleLevel(rule, kind) gives exact, safe or none.
    • no-overlap and in-container are safe on polygon, circle and free. checkShapes accepts a safe kind only with { level: "safe" }.
    • MeasureSpec.bound lists the kinds where the value of a measure is a bound of the true value, with its side upper or lower.
    • shapeLevel(use, kind) gives exact, safe, bound or none. checkShapes accepts a bound kind only with { level: "bound" }. The level safe refuses it.
    • A bound value proves only one side of a compare. docs/SHAPES.md tells what it proves for each direction.
    • shapeSupportProblems(uses) refuses a kind in two of the lists shapes, safe and bound.shapes.
    • MemberRule.view: "bounds" gives the members of a meta option the bounding box of each item. A shape filter then checks the members with rect.
    • A sample with a shape filter skips a meta option without a member list. It throws a RangeError only when the space has no config for the kinds.
  • The corpus dimensions. CorpusDimension.precision is the count of decimal places of a numeric value of a family. The registry rounds the value and the default to it before the invalidates compare. docs/CORPUS.md tells the rules.
  • The output hash. outputHash gives the first 16 hex characters of the SHA-256 of the canonical JSON of an output. Each number goes to the grid of RECORD_EPS first.
  • The corpus checks. checkDeclared and checkSplit give a list of ClaimBreak. An empty list tells that each claim is true. corpusHashOf gives the corpus hash of packing.
  • The verdict. verdict compares two strategies on one measure, with the family as the unit. A verdict counts only when it holds for the mean of the family means and for the mean of the inputs.
  • The record. A run writes one layout-record/1 line of JSON Lines. The formats of the engines tell the fields. These rules are new in 0.3.0:
    • deterministic is true when two runs with the same seed give the same output. A skipped record has null, because no run made a claim.
    • A record without skipped has a boolean deterministic. checkLayoutRecord refuses null on it.
    • An old skipped record has deterministic: true. checkLayoutRecord accepts it, and parseLayoutRecord gives null in its place.
    • env gives the computer of the run: node, os, arch, runner, cpu and cpus. A timing record also gives mode, and it can give context.
    • env.mode is the mode of the timing, for example process or fresh of paired-time/1. env.context is ci or local, with the Node flags.
    • checkLayoutRecord(value) gives the problems of one record. parseLayoutRecord(value) throws a TypeError with them. Both accept fields that the format does not know.
  • The tolerances. EPS (1e-6) is for the float compares in an engine. RECORD_EPS (1e-3) is for the compares on a written file. A record writes the tolerance of each hard rule in its field tolerance. The defaults are overlap 0.001 and through 0.5.

An example

import { applyPack, packHard, toPackInput, type LayoutInput } from "@mark1russell7/layout-contract";

const input: LayoutInput = {
  schema: "layout-input/1",
  id: "example",
  container: { w: 200, fixed: "width" },
  gap: 4,
  boxes: [{ id: "a", w: 40, h: 20, margin: 2 }],
};
const output = myPacker(toPackInput(input));
const placed = applyPack(input, output);
const hard = packHard(input, output);

The docs

The comments of the source name each doc as docs/<NAME>.md. The docs are in the repository, not in the npm package:

| Doc | The subject | |---|---| | docs/BALANCE.md | The balance and stability measures of a pack and of a joint layout | | docs/TEXT.md | The text layout of the subpath /text: the rules, the units and the measures | | docs/CORPUS.md | The shared corpus registry, its dimensions and families | | docs/CORPUS-CHECKS.md | The corpus checks and the split files | | docs/JOINT-CORPUS.md | The joint corpus | | docs/JOINT-MEASURES.md | The joint measures | | docs/PORTFOLIO.md | The portfolio and its pick rule | | docs/PROMOTION.md | The promotion guards | | docs/SHAPES.md | The shape kinds, the levels of a rule and what a bound value proves | | docs/STRATEGY-SPACE.md | The strategy space | | docs/VERDICT.md | The verdict over families |

The formats are in docs/FORMAT.md of packing and docs/LAYOUT-RECORDS.md of highways. The TSDoc of ShapeBound also has the table of what a bound value proves.