# 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`