Files
2026-05-27 23:29:53 +01:00

8.2 KiB
Raw Permalink Blame History

Capability Spec Delta: image-quantisation

Package: @suaveplan/image-quantisation Status: PROPOSED

Every requirement below carries a **Verified by:** line at authoring time. No exceptions.

ADDED Requirements

Requirement: Package provides image complexity analysis

The package SHALL analyse raw RGBA pixel buffers and classify image complexity into one of four tiers: pixel-art, vector-clean, vector-aa, or photographic.

Scenario: Solid-colour image classified as pixel-art

  • WHEN a solid-colour 32×32 buffer is passed to analyseComplexity
  • THEN the returned tier is "pixel-art", uniqueColours is 1, and recommendedColours ≤ 32

Verified by: src/analysis/classify/classify.test.ts::"classifies solid colour as pixel-art"

Scenario: Gradient classified as photographic

  • WHEN a smooth gradient 64×64 buffer is passed to analyseComplexity
  • THEN the returned tier is "photographic", uniqueColours > 100, and recommendDithering is true

Verified by: src/analysis/classify/classify.test.ts::"classifies gradient as photographic"

Scenario: Vector-clean tier detected

  • WHEN a 32×32 image with 64 colours in 4×4 blocks is analysed
  • THEN the returned tier is "vector-clean"

Verified by: src/analysis/classify/classify.test.ts::"classifies vector-clean for moderate colours with medium pools"

Scenario: Vector-aa tier detected

  • WHEN a 64×64 image with 256 colours in 4×4 blocks is analysed
  • THEN the returned tier is "vector-aa"

Verified by: src/analysis/classify/classify.test.ts::"classifies vector-aa for high colour count with structure"


Requirement: Package provides pool detection and distribution

The package SHALL detect contiguous same-colour regions via 4-connected flood fill and compute pool size distribution statistics.

Scenario: Single pool for solid colour

  • WHEN detectPools is called on an 8×8 solid red buffer
  • THEN it returns exactly one pool with size 64 and colour {r:255,g:0,b:0,a:255}

Verified by: src/analysis/pools/pools.test.ts::"finds 1 pool for a solid colour"

Scenario: Pool distribution computed correctly

  • WHEN poolDistribution is called on pools from a checkerboard
  • THEN singletonRatio is 1 and mean is 1

Verified by: src/analysis/pools/pools.test.ts::"detects high singleton ratio in checkerboard"


Requirement: Package provides edge analysis

The package SHALL analyse edges between adjacent pixels and return sharpness metrics.

Scenario: Solid image has zero hard edges

  • WHEN analyseEdges is called on a solid-colour buffer
  • THEN hardEdges is 0 and meanEdgeDistance is 0

Verified by: src/analysis/edges/edges.test.ts::"solid image has zero hard edges"

Scenario: 1×1 image has zero edges

  • WHEN analyseEdges is called on a 1×1 buffer
  • THEN totalEdges is 0, sharpnessRatio is 0, and meanEdgeDistance is 0

Verified by: src/analysis/edges/edges.test.ts::"1x1 image has zero edges"


Requirement: Package provides colour quantisation

The package SHALL quantise RGBA pixel buffers to a target palette size using wrapped image-q algorithms.

Scenario: Gradient reduced to target colours

  • WHEN quantise is called on a 32×32 gradient with colours: 16
  • THEN paletteSize ≤ 16

Verified by: src/quantise/quantise.test.ts::"reduces a gradient to target colour count"

Scenario: All three algorithms supported

  • WHEN quantise is called with algorithm: "wuquant", "neuquant", and "rgbquant"
  • THEN each result has paletteSize ≤ 8

Verified by: src/quantise/quantise.test.ts::"supports different algorithms"

Scenario: Invalid dimensions throw structured error

  • WHEN quantise is called with width: 0
  • THEN it throws QuantisationError with code QUANTISATION.INVALID_DIMENSIONS

Verified by: src/quantise/quantise.test.ts::"throws on invalid dimensions"


Requirement: Package provides spatial AA cleanup

The package SHALL merge small pools into nearest spatial neighbours below a colour distance threshold.

Scenario: Near-colour AA pixels merged

  • WHEN spatialCleanup is called on an AA edge buffer with default options
  • THEN the unique colour count drops from 3 to 2

Verified by: src/spatial/cleanup/cleanup.test.ts::"merges near-colour AA pixels into spatial neighbours"

Scenario: Pool size threshold respected

  • WHEN spatialCleanup is called with maxPoolSize: 0
  • THEN no merge occurs and colour count stays 3

Verified by: src/spatial/cleanup/cleanup.test.ts::"does not merge pools above maxPoolSize"


Requirement: Package provides adaptive pipeline

The package SHALL orchestrate analysis → spatial cleanup → quantisation in a single call, selecting strategy based on complexity tier.

Scenario: Pixel-art skips quantisation

  • WHEN adaptivePipeline is called on a solid-colour buffer
  • THEN quantisation is null and finalColours is 1

Verified by: src/pipeline/pipeline.test.ts::"skips quantisation for pixel-art"

Scenario: Photographic images are quantised

  • WHEN adaptivePipeline is called on a gradient
  • THEN quantisation is not null and finalColours ≤ 256

Verified by: src/pipeline/pipeline.test.ts::"quantises photographic images"

Scenario: Spatial cleanup applied for vector-aa

  • WHEN adaptivePipeline is called on a vector-aa image
  • THEN spatialCleanupApplied is true

Verified by: src/pipeline/pipeline.test.ts::"applies spatial cleanup for vector-aa images"


Requirement: Package validates options via Zod schemas

All public entry points that accept options SHALL validate them through exported Zod schemas before processing.

Scenario: Invalid options rejected by quantise

  • WHEN quantise is called with colours: 1
  • THEN it throws QuantisationError with code QUANTISATION.PROCESSING_FAILED

Verified by: src/quantise/quantise.test.ts::"throws on invalid options"


Requirement: Package emits OpenTelemetry instruments

The package SHALL emit a counter and histogram for quantise and adaptivePipeline invocations.

Scenario: Instruments exist and are lazily initialised

  • WHEN quantise is called
  • THEN internal getCounter() and getDuration() functions return valid OTel instruments

Verified by: src/quantise/quantise.test.ts::"reduces a gradient to target colour count" (implicit via execution path)


Requirement: Package defines stable error codes

The package SHALL declare error codes via defineCodes("QUANTISATION", [...]) and throw QuantisationError with those codes.

Scenario: Every code is reachable

  • WHEN invalid inputs are provided to quantise and adaptivePipeline
  • THEN each of INVALID_PIXEL_BUFFER, INVALID_DIMENSIONS, and PROCESSING_FAILED is thrown at least once

Verified by: src/quantise/quantise.test.ts::"throws on invalid dimensions" AND src/quantise/quantise.test.ts::"throws on mismatched buffer size" AND src/pipeline/pipeline.test.ts::"throws on invalid options"


Requirement: Package provides property-based tests

The package SHALL include fast-check property tests that verify invariants across random inputs.

Scenario: Palette size invariant

  • WHEN random RGBA buffers and colour counts are quantised
  • THEN result.paletteSize ≤ requested colours

Verified by: src/property.test.ts::"quantise palette size <= requested colours"

Scenario: Output dimensions invariant

  • WHEN random RGBA buffers are quantised
  • THEN output width, height, and pixels.length match input

Verified by: src/property.test.ts::"quantise output has same dimensions as input"


Requirement: Package includes benchmarks

The package SHALL include mitata benchmarks for quantise, analyseComplexity, and adaptivePipeline.

Scenario: Benchmark file exists and compiles

  • WHEN the benchmark file is inspected
  • THEN src/__benchmarks__/quantisation.bench.ts exists and imports the public API

Verified by: manual inspection of src/__benchmarks__/quantisation.bench.ts