8.2 KiB
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
tieris"pixel-art",uniqueColoursis 1, andrecommendedColours≤ 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
tieris"photographic",uniqueColours> 100, andrecommendDitheringistrue
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
tieris"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
tieris"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
detectPoolsis called on an 8×8 solid red buffer - THEN it returns exactly one pool with
size64 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
poolDistributionis called on pools from a checkerboard - THEN
singletonRatiois 1 andmeanis 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
analyseEdgesis called on a solid-colour buffer - THEN
hardEdgesis 0 andmeanEdgeDistanceis 0
Verified by: src/analysis/edges/edges.test.ts::"solid image has zero hard edges"
Scenario: 1×1 image has zero edges
- WHEN
analyseEdgesis called on a 1×1 buffer - THEN
totalEdgesis 0,sharpnessRatiois 0, andmeanEdgeDistanceis 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
quantiseis called on a 32×32 gradient withcolours: 16 - THEN
paletteSize≤ 16
Verified by: src/quantise/quantise.test.ts::"reduces a gradient to target colour count"
Scenario: All three algorithms supported
- WHEN
quantiseis called withalgorithm: "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
quantiseis called withwidth: 0 - THEN it throws
QuantisationErrorwith codeQUANTISATION.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
spatialCleanupis 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
spatialCleanupis called withmaxPoolSize: 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
adaptivePipelineis called on a solid-colour buffer - THEN
quantisationisnullandfinalColoursis 1
Verified by: src/pipeline/pipeline.test.ts::"skips quantisation for pixel-art"
Scenario: Photographic images are quantised
- WHEN
adaptivePipelineis called on a gradient - THEN
quantisationis notnullandfinalColours≤ 256
Verified by: src/pipeline/pipeline.test.ts::"quantises photographic images"
Scenario: Spatial cleanup applied for vector-aa
- WHEN
adaptivePipelineis called on a vector-aa image - THEN
spatialCleanupAppliedistrue
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
quantiseis called withcolours: 1 - THEN it throws
QuantisationErrorwith codeQUANTISATION.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
quantiseis called - THEN internal
getCounter()andgetDuration()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
quantiseandadaptivePipeline - THEN each of
INVALID_PIXEL_BUFFER,INVALID_DIMENSIONS, andPROCESSING_FAILEDis 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, andpixels.lengthmatch 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.tsexists and imports the public API
Verified by: manual inspection of src/__benchmarks__/quantisation.bench.ts