# @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](./src/converter/converter.md) — This module is the public-facing entry point of `@suaveplan/emblem-solver`. It coordinates the entire pipeline — schema… - [converter](./src/converter/converter.md) — This module is the public-facing entry point of `@suaveplan/emblem-solver`. It coordinates the entire pipeline — schema… - [errors](./src/errors/errors.md) — This module exposes the typed error surface for `@suaveplan/emblem-solver`. It defines the stable, namespaced code regi… - [errors](./src/errors/errors.md) — This module exposes the typed error surface for `@suaveplan/emblem-solver`. It defines the stable, namespaced code regi… - [fixtures](./src/fixtures/fixtures.md) — This module is the canonical test-fixture surface for the package. Each exported function returns a deterministic `RGBA… - [fixtures](./src/fixtures/fixtures.md) — This module is the canonical test-fixture surface for the package. Each exported function returns a deterministic `RGBA… - [analyse](./src/grid/analyse/analyse.md) — This module owns `analyseGrid`, the diagnostic phase of the conversion pipeline. It walks an RGBA grid once, buckets op… - [analyse](./src/grid/analyse/analyse.md) — This module owns `analyseGrid`, the diagnostic phase of the conversion pipeline. It walks an RGBA grid once, buckets op… - [helpers](./src/helpers/helpers.md) — This module is the shared kernel of utility functions used by the analyser, the solver strategies, and the optimisers.… - [helpers](./src/helpers/helpers.md) — This module is the shared kernel of utility functions used by the analyser, the solver strategies, and the optimisers.… - [parse](./src/io/parse/parse.md) — This module owns the two import paths into the solver: `parseRGBABuffer` turns a raw RGBA `Uint8Array` (e.g. the output… - [parse](./src/io/parse/parse.md) — This module owns the two import paths into the solver: `parseRGBABuffer` turns a raw RGBA `Uint8Array` (e.g. the output… - [merge](./src/optimizer/merge/merge.md) — This module owns `mergeAdjacentRects`, the post-processing pass that combines pairs of edge-sharing same-extent rectang… - [merge](./src/optimizer/merge/merge.md) — This module owns `mergeAdjacentRects`, the post-processing pass that combines pairs of edge-sharing same-extent rectang… - [overlap](./src/optimizer/overlap/overlap.md) — This module owns `optimiseOverlap`, the deepest cover-reduction pass in the package. It looks for three patterns that t… - [overlap](./src/optimizer/overlap/overlap.md) — This module owns `optimiseOverlap`, the deepest cover-reduction pass in the package. It looks for three patterns that t… - [redundancy](./src/optimizer/redundancy/redundancy.md) — This module owns `eliminateRedundant`, the final cross-layer optimisation the converter runs after every layer's cover… - [redundancy](./src/optimizer/redundancy/redundancy.md) — This module owns `eliminateRedundant`, the final cross-layer optimisation the converter runs after every layer's cover… - [schemas](./src/schemas/schemas.md) — This module owns the runtime validation surface for `@suaveplan/emblem-solver`. It exposes `ConvertOptionsSchema`, a Zo… - [schemas](./src/schemas/schemas.md) — This module owns the runtime validation surface for `@suaveplan/emblem-solver`. It exposes `ConvertOptionsSchema`, a Zo… - [greedy](./src/solver/greedy/greedy.md) — This module provides the greedy selector that drives the primary covering strategy. `enhancedGreedyCover` picks rectang… - [greedy](./src/solver/greedy/greedy.md) — This module provides the greedy selector that drives the primary covering strategy. `enhancedGreedyCover` picks rectang… - [histogram](./src/solver/histogram/histogram.md) — This module enumerates every distinct maximal-rectangle candidate inside an opaque-pixel grid. It is the candidate pool… - [histogram](./src/solver/histogram/histogram.md) — This module enumerates every distinct maximal-rectangle candidate inside an opaque-pixel grid. It is the candidate pool… - [layer](./src/solver/layer/layer.md) — This module owns `processLayerMultiStrategy`, the function the converter calls once per layer in the current ordering.… - [layer](./src/solver/layer/layer.md) — This module owns `processLayerMultiStrategy`, the function the converter calls once per layer in the current ordering.… - [ordering](./src/solver/ordering/ordering.md) — This module provides the layer-ordering machinery the converter consults when it has to decide which colour sits on the… - [ordering](./src/solver/ordering/ordering.md) — This module provides the layer-ordering machinery the converter consults when it has to decide which colour sits on the… - [strip](./src/solver/strip/strip.md) — This module implements `stripDecomposition`, a complementary cover strategy that ignores the maximal-rect candidate poo… - [strip](./src/solver/strip/strip.md) — This module implements `stripDecomposition`, a complementary cover strategy that ignores the maximal-rect candidate poo… - [build](./src/svg/build/build.md) — This module owns `buildSVG`, the deterministic SVG serialiser the converter uses to produce its final `` string. I… - [build](./src/svg/build/build.md) — This module owns `buildSVG`, the deterministic SVG serialiser the converter uses to produce its final `` string. I… - [telemetry](./src/telemetry/telemetry.md) — This module owns the OpenTelemetry instruments emitted by `convert()`. It exposes a counter (`emblem_solver.convert.tot… - [telemetry](./src/telemetry/telemetry.md) — This module owns the OpenTelemetry instruments emitted by `convert()`. It exposes a counter (`emblem_solver.convert.tot… - [types](./src/types/types.md) — This module is the single source of truth for the public type surface of `@suaveplan/emblem-solver`. It defines the imm… - [types](./src/types/types.md) — This module is the single source of truth for the public type surface of `@suaveplan/emblem-solver`. It defines the imm… ## Install ```sh bun add @suaveplan/emblem-solver ``` ## Quick start ```ts 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); // … 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 ```ts 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 or `pixels.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.