Relocate the ~6k-file docs tree from the repo root into plugins/document-navigator/docs/ so the plugin is self-contained and portable. docs/superpowers/ (specs and plans) stays at the repo root. Moved via cp+rm rather than git mv because directory rename() fails with EPERM on this WSL /mnt DrvFs mount; git rename-detection pairs the identical-content files at commit time. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@suaveplan/emblem-solver - Minimal-rectangle SVG converter for pixelated sprite emblems: layered occlusion, overlapping rect optimisation, dual-axis maximal rectangles, strip decomposition, and exhaustive layer ordering
Minimal-rectangle SVG converter for pixelated sprite emblems.
Converts a pixel grid (RGBA[]) into the smallest possible set of
axis-aligned coloured rectangles by combining four covering strategies
(dual-axis maximal rectangles + greedy cover, per-island independent
cover, strip decomposition, adjacent-rect merge), pairwise + triple-wise
overlap reductions, and exhaustive z-stacking search across up to 8! layer
orderings. Outputs a deterministic SVG string ready for direct embedding
or further compression.
Documentation tree
- converter — This module is the public-facing entry point of
@suaveplan/emblem-solver. It coordinates the entire pipeline — schema…- converter — This module is the public-facing entry point of
@suaveplan/emblem-solver. It coordinates the entire pipeline — schema…
- converter — This module is the public-facing entry point of
- errors — This module exposes the typed error surface for
@suaveplan/emblem-solver. It defines the stable, namespaced code regi…- errors — This module exposes the typed error surface for
@suaveplan/emblem-solver. It defines the stable, namespaced code regi…
- errors — This module exposes the typed error surface for
- fixtures — This module is the canonical test-fixture surface for the package. Each exported function returns a deterministic `RGBA…
- fixtures — This module is the canonical test-fixture surface for the package. Each exported function returns a deterministic `RGBA…
- analyse — This module owns
analyseGrid, the diagnostic phase of the conversion pipeline. It walks an RGBA grid once, buckets op…- analyse — This module owns
analyseGrid, the diagnostic phase of the conversion pipeline. It walks an RGBA grid once, buckets op…
- analyse — This module owns
- helpers — This module is the shared kernel of utility functions used by the analyser, the solver strategies, and the optimisers.…
- helpers — This module is the shared kernel of utility functions used by the analyser, the solver strategies, and the optimisers.…
- parse — This module owns the two import paths into the solver:
parseRGBABufferturns a raw RGBAUint8Array(e.g. the output…- parse — This module owns the two import paths into the solver:
parseRGBABufferturns a raw RGBAUint8Array(e.g. the output…
- parse — This module owns the two import paths into the solver:
- merge — This module owns
mergeAdjacentRects, the post-processing pass that combines pairs of edge-sharing same-extent rectang…- merge — This module owns
mergeAdjacentRects, the post-processing pass that combines pairs of edge-sharing same-extent rectang…
- merge — This module owns
- overlap — This module owns
optimiseOverlap, the deepest cover-reduction pass in the package. It looks for three patterns that t…- overlap — This module owns
optimiseOverlap, the deepest cover-reduction pass in the package. It looks for three patterns that t…
- overlap — This module owns
- redundancy — This module owns
eliminateRedundant, the final cross-layer optimisation the converter runs after every layer's cover…- redundancy — This module owns
eliminateRedundant, the final cross-layer optimisation the converter runs after every layer's cover…
- redundancy — This module owns
- schemas — This module owns the runtime validation surface for
@suaveplan/emblem-solver. It exposesConvertOptionsSchema, a Zo…- schemas — This module owns the runtime validation surface for
@suaveplan/emblem-solver. It exposesConvertOptionsSchema, a Zo…
- schemas — This module owns the runtime validation surface for
- greedy — This module provides the greedy selector that drives the primary covering strategy.
enhancedGreedyCoverpicks rectang…- greedy — This module provides the greedy selector that drives the primary covering strategy.
enhancedGreedyCoverpicks rectang…
- greedy — This module provides the greedy selector that drives the primary covering strategy.
- histogram — This module enumerates every distinct maximal-rectangle candidate inside an opaque-pixel grid. It is the candidate pool…
- histogram — This module enumerates every distinct maximal-rectangle candidate inside an opaque-pixel grid. It is the candidate pool…
- layer — This module owns
processLayerMultiStrategy, the function the converter calls once per layer in the current ordering.…- layer — This module owns
processLayerMultiStrategy, the function the converter calls once per layer in the current ordering.…
- layer — This module owns
- ordering — This module provides the layer-ordering machinery the converter consults when it has to decide which colour sits on the…
- ordering — This module provides the layer-ordering machinery the converter consults when it has to decide which colour sits on the…
- strip — This module implements
stripDecomposition, a complementary cover strategy that ignores the maximal-rect candidate poo…- strip — This module implements
stripDecomposition, a complementary cover strategy that ignores the maximal-rect candidate poo…
- strip — This module implements
- build — This module owns
buildSVG, the deterministic SVG serialiser the converter uses to produce its final<svg>string. I…- build — This module owns
buildSVG, the deterministic SVG serialiser the converter uses to produce its final<svg>string. I…
- build — This module owns
- telemetry — This module owns the OpenTelemetry instruments emitted by
convert(). It exposes a counter (`emblem_solver.convert.tot…- telemetry — This module owns the OpenTelemetry instruments emitted by
convert(). It exposes a counter (`emblem_solver.convert.tot…
- telemetry — This module owns the OpenTelemetry instruments emitted by
- types — This module is the single source of truth for the public type surface of
@suaveplan/emblem-solver. It defines the imm…- types — This module is the single source of truth for the public type surface of
@suaveplan/emblem-solver. It defines the imm…
- types — This module is the single source of truth for the public type surface of
Install
bun add @suaveplan/emblem-solver
Quick start
import { convert, fromIndexedGrid } from "@suaveplan/emblem-solver";
const { pixels, width, height } = fromIndexedGrid(
[
[0, 1, 0],
[1, 1, 1],
[0, 1, 0],
],
new Map([[1, { r: 255, g: 0, b: 0 }]])
);
const { svg, totalRects, ratio } = convert(pixels, width, height);
console.log(svg); // <svg …>…</svg>
console.log(totalRects); // 2 — the cross collapses to two overlapping rects
console.log(ratio.toFixed(1)); // 2.5 — naïve per-pixel would have been 5 rects
API surface
| Symbol | Subpath | Purpose |
|---|---|---|
convert |
root | Public orchestrator |
analyseGrid |
/grid |
Per-colour islands, density, fragmentation |
parseRGBABuffer, fromIndexedGrid |
/io |
Input adapters |
buildSVG |
/svg |
Standalone serialiser |
dualAxisMaximalRects, enhancedGreedyCover, perIslandCover, stripDecomposition, processLayerMultiStrategy, permutations, factorial, getStaticOrdering |
/solver |
Composition primitives |
mergeAdjacentRects, optimiseOverlap, eliminateRedundant |
/optimizer |
Composition primitives |
ConvertOptionsSchema |
/schemas |
Zod input validation |
EmblemSolverError, EMBLEM_SOLVER_CODES |
/errors |
Typed errors |
Options
interface ConvertOptions {
/** Default: "auto" */
layerOrder?: "auto" | "area-desc" | "area-asc" | "island-aware" | "perimeter-desc";
/** Default: 40320 (= 8!) */
maxPermutations?: number;
/** Default: Math.random — supply a seeded RNG for deterministic auto-ordering on > 8-colour inputs */
rng?: () => number;
}
Errors
All failures throw EmblemSolverError whose .code is one of:
EMBLEM_SOLVER.INVALID_GRID— dimensions non-positive orpixels.length !== width * height.EMBLEM_SOLVER.INVALID_OPTIONS— Zod rejected the options bag.EMBLEM_SOLVER.INVALID_PIXEL— reserved for future use.
Observability
convert() emits two OpenTelemetry instruments via the meter
@suaveplan/emblem-solver:
- Counter
emblem_solver.convert.total - Histogram
emblem_solver.convert.duration_ms(unit:ms)
Instruments are registered lazily on first call, so importing the package has no observability side effects.
Tier
Universal: zero browser / Node / React dependencies. Runs unchanged on Bun, Node, Deno, and modern browsers.
License
MIT — Suaveplan Team.