3.5 KiB
Architecture
Colour Tools is a client-only React application built as relocatable static files. The UI and calculation engine are intentionally separated so colour operations can be tested without a browser and UI state can keep showing the last valid result while an input is incomplete.
Layers
src/colour/is the serialisable colour domain. It parses and formats colours, converts gamuts, composites layers, interpolates stops, evaluates contrast and Delta E, simulates colour-vision deficiencies, and builds or exports palettes. Its public API is re-exported fromsrc/colour/index.ts.src/palette/contains browser-independent raster bounds, sampling and deterministic OKLab clustering.src/workers/palette.worker.tsexposes the expensive extraction path to a dedicated worker.src/components/contains the seven workspaces and shared accessible controls. Workspace selection is represented by a URL fragment, so a view can be bookmarked without router or server support.src/hooks/owns bounded device-local UI persistence. Image bytes are not stored there.src/toolbox/contains the checked manifest identity. The shared Toolbox shell supplies navigation, contextual actions and theme behaviour without changing the standalone application domain.
Colour values
The engine's ColourValue is a plain object: colour-space identifier, three
numeric coordinates and alpha. It deliberately carries coordinates that may
sit outside a display gamut. Color.js 0.7.1 supplies standards-aligned parsing
and conversion primitives; Colour Tools wraps these in typed, bounded domain
operations and stable UI formats.
Browser preview is a separate operation. It maps a value to sRGB and reports whether mapping occurred. This keeps display limitations from mutating the source colour used by later conversions or comparisons.
Raster pipeline
The image picker validates the selected file before decode, rejects excessive bytes/dimensions/pixels, then draws the decoded image to a same-origin in-memory Canvas 2D surface. Sampling reads a bounded neighbourhood. Palette extraction subsamples deterministically, converts points to OKLab and clusters them with a fixed initialization and iteration bound. The worker client can fall back to the same pure function when workers are unavailable.
Temporary object URLs are revoked and outstanding extraction is aborted when an image is replaced or removed. No image or extracted palette is transmitted.
Build and deployment
Vite builds with a relative base. scripts/generate-toolbox-manifest.mjs
checks package, application and Toolbox versions plus immutable source
identity. scripts/prepare-release-files.mjs places project documentation and
the exact installed runtime licence inventory beside the executable app.
The service worker is relative-scope and deployment-subpath aware. It is progressive enhancement: the app remains usable when registration is rejected. The deterministic packager rejects symbolic links, source maps, secret-like filenames and root-absolute asset references before creating the release ZIP and SHA-256 sidecar.
Testing boundaries
Unit tests cover parsing, numerical operations, invalid inputs, raster bounds,
sampling and palette determinism. Browser smoke tests run the production build
under a restrictive policy at /deep/nested/colour/, exercise all major
workspaces and fail on uncaught errors or external network requests. The
Toolbox contract checker validates the static artifact independently.