135 lines
9.2 KiB
Markdown
135 lines
9.2 KiB
Markdown
# @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.
|
|
|
|
<!-- begin:auto-docs -->
|
|
## 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 `<svg>` string. I…
|
|
- [build](./src/svg/build/build.md) — This module owns `buildSVG`, the deterministic SVG serialiser the converter uses to produce its final `<svg>` 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…
|
|
<!-- end:auto-docs -->
|
|
|
|
## 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); // <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
|
|
|
|
```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.
|
|
|