@faceless-photolib/color
Color science for faceless-photolib — transfer functions, RGB/XYZ primaries, Bradford chromatic adaptation, and OCIO-style hub-and-spoke conversions through an ACEScg (AP1) scene-linear connection space.
Color science for faceless-photolib — a headless, color-managed, GPU-accelerated image-editing engine.
Provides transfer functions (sRGB, Rec.709/2020, gamma, PQ, HLG, and the LogC3/LogC4/S-Log3/Log3G10/ACEScc/ACEScct log variants), pinned RGB primaries with Lindbloom RGB↔XYZ matrices, Bradford chromatic adaptation, and an OCIO-style hub-and-spoke color manager. Every conversion routes through a single fixed connection space — ACEScg / AP1 scene-linear — so spaces convert via the hub rather than pairwise.
Install
pnpm add @faceless-photolib/colorUsage
import {
createStandardColorSpaceRegistry,
conversionFromWorkingSpace,
conversionToWorkingSpace,
applyConversion,
eotf,
inverseEotf,
PRIMARIES_SRGB,
} from "@faceless-photolib/color";
import { ColorSpaceIdSchema } from "@faceless-photolib/schemas";
// A registry seeded with the standard spaces (srgb, rec2020, display-p3, acescc, …).
const registry = createStandardColorSpaceRegistry();
const srgb = ColorSpaceIdSchema.parse("srgb");
// Build a conversion descriptor: sRGB → ACEScg connection space.
const toHub = conversionFromWorkingSpace(registry, srgb);
if (toHub.kind === "ok") {
// input transfer (decode) → matrix → output transfer (encode)
const linearAp1 = applyConversion(toHub.value, [0.5, 0.25, 0.75]);
// …and back to sRGB.
const fromHub = conversionToWorkingSpace(registry, srgb);
if (fromHub.kind === "ok") {
const roundTrip = applyConversion(fromHub.value, linearAp1);
}
}
// Scalar transfer-function evaluation (EOTF and its inverse).
const linear = eotf({ kind: "sRGB" }, 0.5); // encoded → scene-linear
const encoded = inverseEotf({ kind: "sRGB" }, linear); // scene-linear → encodedAPI
| Export | Description |
|---|---|
createColorSpaceRegistry(spaces?) | Build an immutable ColorSpaceRegistry; unknown ids resolve to a rejected Result plus a beacon, never identity. |
createStandardColorSpaceRegistry() | A registry seeded with the standard v1 spaces (srgb, srgb-linear, rec709, rec2020, rec2020-pq/hlg, display-p3, acescc, acescct) plus the ACEScg connection space. |
makeColorSpace(id, primaries, transferFn) | Build a ColorSpace, deriving its toReference/fromReference matrices (Bradford-adapted to the ACES white point). |
conversionToWorkingSpace(registry, ws) | Descriptor for connection → working-space (matrix + input/output transfers). |
conversionFromWorkingSpace(registry, ws) | Descriptor for working-space → connection (the inverse). |
applyConversion(descriptor, rgb) | CPU reference realization: decode → matrix → encode on an RGB triple. |
outputTransform(version, display) | Display + View output-transform descriptor (aces-1.x; aces-2.0 is gated and reports not-implemented). |
eotf(fn, encoded) / inverseEotf(fn, linear) | Evaluate a transfer function's EOTF / inverse EOTF on a scalar. |
rgbToXyzMatrix(space) | The 3x3 linear RGB→XYZ matrix, Bradford-adapted to the connection (ACES) white. |
CONNECTION_SPACE_ID / REFERENCE_PRIMARIES | The connection space id ("acescg") and its primaries (AP1). |
PRIMARIES_SRGB, PRIMARIES_REC2020, PRIMARIES_DISPLAY_P3, PRIMARIES_AP0, PRIMARIES_AP1, PRIMARIES_AWG4 | Pinned standard primaries tables. |
ColorSpaceRegistry, ColorConversionDescriptor, OutputTransformDescriptor | Public interface/descriptor types. |
All chromaticities and transfer-function constants are pinned to primary sources; conversions are exhaustively matched (no silent fallbacks) and route through the ACEScg / AP1 hub.
License
MIT
API reference
21 public exports · 21 documented · generated from source.
applyConversionfunctionapplyConversion(descriptor: ColorConversionDescriptor, rgb: readonly [number, number, number]): readonly [number, number, number]Apply a `ColorConversionDescriptor` to a linear-or-encoded RGB triple, following its declared order: input transfer (decode) → matrix → output transfer (encode). This is the CPU reference realization of the descriptor and is what the round-trip-stability requirement is tested against.
conversionFromWorkingSpacefunctionconversionFromWorkingSpace(registry: ColorSpaceRegistry, workingSpace: string & $brand<"ColorSpaceId">): Result<ColorConversionDescriptor>Compose the workingSpace→connection conversion descriptor — the inverse of `conversionToWorkingSpace`, auto-inserted after a declared-workingSpace op. - the input transfer is the working space's encoding (decode before matrix); - the matrix rotates working primaries back into connection primaries; - the output transfer is linear (connection space is scene-linear).
conversionToWorkingSpacefunctionconversionToWorkingSpace(registry: ColorSpaceRegistry, workingSpace: string & $brand<"ColorSpaceId">): Result<ColorConversionDescriptor>Compose the connection→workingSpace conversion descriptor for auto-insertion.
createColorSpaceRegistryfunctioncreateColorSpaceRegistry(spaces?: readonly { id: string & $brand<"ColorSpaceId">; primaries: { red: { x: number; y: number; }; green: { x: number; y: number; }; blue: { x: number; y: number; }; white: { x: number; y: number; }; }; transferFn: { ...; } | ... 11 more ... | { ...; }; toReference: [...]; fromReference: [...]; }[]): ColorSpaceRegistryBuild a registry seeded with the given color spaces (resolution is real; entries are seeded by implementers).
createStandardColorSpaceRegistryfunctioncreateStandardColorSpaceRegistry(): ColorSpaceRegistryA registry seeded with the standard v1 color spaces. The connection space (`acescg`/AP1) carries identity reference matrices; every other space's matrices are Bradford-adapted to the ACES white point.
eotffunctioneotf(fn: { kind: "linear"; } | { kind: "gamma"; exponent: number; } | { kind: "sRGB"; } | { kind: "rec709"; } | { kind: "rec2020"; } | { kind: "pq"; } | { kind: "hlg"; } | { kind: "logC3"; } | { kind: "logC4"; } | { ...; } | { ...; } | { ...; } | { ...; }, encoded: number): numberEvaluate a transfer function's EOTF (encoded → linear) on a scalar.
inverseEotffunctioninverseEotf(fn: { kind: "linear"; } | { kind: "gamma"; exponent: number; } | { kind: "sRGB"; } | { kind: "rec709"; } | { kind: "rec2020"; } | { kind: "pq"; } | { kind: "hlg"; } | { kind: "logC3"; } | { kind: "logC4"; } | { ...; } | { ...; } | { ...; } | { ...; }, linear: number): numberEvaluate a transfer function's inverse EOTF (linear → encoded) on a scalar.
makeColorSpacefunctionmakeColorSpace(id: string, primaries: { red: { x: number; y: number; }; green: { x: number; y: number; }; blue: { x: number; y: number; }; white: { x: number; y: number; }; }, transferFn: { kind: "linear"; } | { kind: "gamma"; exponent: number; } | ... 10 more ... | { ...; }): { ...; }Build a `ColorSpace` entry from its primaries + transfer function, deriving the `toReference`/`fromReference` matrices (RGB↔reference-RGB with Bradford CAT) at config-load time. The connection space (`acescg`) resolves to identity matrices.
outputTransformfunctionoutputTransform(version: "aces-1.x" | "aces-2.0", display: string & $brand<"ColorSpaceId">): Result<OutputTransformDescriptor>Build the Display + View output-transform descriptor (ACES 1.x default). ACES 2.0 is gated behind its explicit flag: the engine builds an `aces-1.x` descriptor by default, and only when `aces-2.0` is requested does it report `not-implemented` (the ACES 2.0 RRT/ODT is a later phase; D3).
rgbToXyzMatrixfunctionrgbToXyzMatrix(space: { id: string & $brand<"ColorSpaceId">; primaries: { red: { x: number; y: number; }; green: { x: number; y: number; }; blue: { x: number; y: number; }; white: { x: number; y: number; }; }; transferFn: { ...; } | ... 11 more ... | { ...; }; toReference: [...]; fromReference: [...]; }): [...]Build the 3x3 RGB→XYZ matrix from primaries + white using Bradford chromatic adaptation to the connection white point. The matrix maps this space's linear RGB into CIE XYZ adapted to the reference (ACES) white.
ColorConversionDescriptorinterfaceinterface ColorConversionDescriptorA backend-agnostic descriptor for a reference↔workingSpace conversion (Shader IR node).
ColorSpaceRegistryinterfaceinterface ColorSpaceRegistryA registry of resolvable color spaces keyed by id.
OutputTransformDescriptorinterfaceinterface OutputTransformDescriptorA backend-agnostic Display + View output-transform descriptor.
CONNECTION_SPACE_IDconstCONNECTION_SPACE_ID: "acescg"The id of the fixed connection (working/reference) space.
PRIMARIES_AP0constconst PRIMARIES_AP0ACES AP0 (ACES2065-1) primaries, ACES white (findings.json:479).
PRIMARIES_AP1constconst PRIMARIES_AP1ACES AP1 (ACEScg) primaries, ACES white (findings.json:479).
PRIMARIES_AWG4constconst PRIMARIES_AWG4ARRI Wide Gamut 4 (AWG4) primaries, D65 white (findings.json:455).
PRIMARIES_DISPLAY_P3constconst PRIMARIES_DISPLAY_P3Display-P3 primaries, D65 white (SMPTE EG 432-1; standard display gamut).
PRIMARIES_REC2020constconst PRIMARIES_REC2020Rec.2020 primaries, D65 white.
PRIMARIES_SRGBconstconst PRIMARIES_SRGBsRGB / Rec.709 primaries, D65 white.
REFERENCE_PRIMARIESconstconst REFERENCE_PRIMARIESThe reference-space primaries (ACEScg / AP1).
@faceless-photolib/diagnostics
Runtime diagnostics for faceless-photolib — warnNotImplemented / warnDegraded / warnUnexpected beacons backed by a dedup registry, used instead of // TODO comments.
@faceless-photolib/geometry
Pure 2D affine + homography math for layer transforms: row-major mat3 algebra, W3C unmatrix decompose/recompose into TRS, 4-point DLT homography, and resampling kernel weights (Y-down convention).