Files
skills/plugins/document-navigator/docs/media/image/emblem-solver/README.md
admin 9bf56a806b Move docs/ package mirror into document-navigator plugin
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>
2026-05-30 01:10:00 +01:00

9.2 KiB

@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…
  • 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…
  • 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…
  • 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: parseRGBABuffer turns a raw RGBA Uint8Array (e.g. the output…
    • parse — This module owns the two import paths into the solver: parseRGBABuffer turns a raw RGBA Uint8Array (e.g. the output…
  • 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…
  • 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…
  • 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…
  • schemas — This module owns the runtime validation surface for @suaveplan/emblem-solver. It exposes ConvertOptionsSchema, a Zo…
    • schemas — This module owns the runtime validation surface for @suaveplan/emblem-solver. It exposes ConvertOptionsSchema, a Zo…
  • greedy — This module provides the greedy selector that drives the primary covering strategy. enhancedGreedyCover picks rectang…
    • greedy — This module provides the greedy selector that drives the primary covering strategy. enhancedGreedyCover picks rectang…
  • 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.…
  • 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…
  • 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…
  • 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…
  • 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…

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 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.