The Registry API
Learn how to use the register() and unregister() methods to dynamically add or remove color models, spaces, parsers, formatters, and algorithms.
The Saturon Registry API allows you to deeply extend the engine without modifying the core library. Whether you need a proprietary color model, a custom string parser, or a specific gamut mapping algorithm, the registry seamlessly injects your custom logic directly into the global execution graph.
All extensions are managed through two batch-processing methods: register() and unregister().
API Signature
import { register, unregister } from "saturon/registry";
// Add new features
register(category, [{ name: "identifier", value: implementation }]);
// Remove features and flush caches
unregister(category, ["identifier"]);Saturon supports seven distinct registration categories.
1. Named Colors ("named-colors")
Inject hardcoded color aliases into the CSS string parser. These become instantly available to Color.from() and relative color syntax operations.
Expected Value: [R, G, B] (Array of 3 numbers, 0-255)
register("named-colors", [
{ name: "brandprimary", value: [88, 101, 242] },
{ name: "brandaccent", value: [254, 231, 92] },
]);
import { Color } from "saturon";
const btn = Color.from("brandprimary");2. Custom Color Models ("color-models")
Registers a standalone CSS color model/function (e.g., cmyk(), hsi()). This requires defining the component bounds and providing conversion functions to an existing "bridge" model (like rgb or xyz).
Expected Value: ColorModelConverter
register("color-models", [
{
name: "my-rgb",
value: {
bridge: "rgb", // Route conversions through standard RGB
targetGamut: "srgb",
components: {
r: { index: 0, value: [0, 255] },
g: { index: 1, value: [0, 255] },
b: { index: 2, value: [0, 255] },
},
toBridge: (coords) => coords, // Native -> Bridge
fromBridge: (coords) => coords, // Bridge -> Native
},
},
]);Once registered, the engine auto-generates the grammar, allowing:
Color.from("my-rgb(100 50 25)") or Color.from("from my-rgb(100 50 25) my-rgb(r g calc(b * 2))").
3. Custom Color Spaces ("color-spaces")
Registers matrix-based color spaces for use inside the CSS color(...) function (e.g., color(display-p3 1 0 0)).
Expected Value: ColorSpaceConverter
register("color-spaces", [
{
name: "custom-p3",
value: {
bridge: "xyz-d65",
components: ["r", "g", "b"],
// Conversion matrices (Linear Space <-> XYZ-D65)
toBridgeMatrix: [
[0.48657, 0.26566, 0.19821],
[0.22897, 0.69173, 0.07928],
[0.0, 0.04511, 1.04394],
],
fromBridgeMatrix: [
[2.49349, -0.93138, -0.40271],
[-0.82868, 1.76266, 0.02362],
[0.03584, -0.07617, 0.95688],
],
// Non-linear transfer functions
toLinear: (c) => (c < 0.04045 ? c / 12.92 : Math.pow((c + 0.055) / 1.055, 2.4)),
fromLinear: (c) => (c <= 0.0031308 ? c * 12.92 : 1.055 * Math.pow(c, 1 / 2.4) - 0.055),
},
},
]);4. Output Formatters ("formatters")
Adds a new serialization format for .to() and .toString(). Formatters require a bridge model and a format method to construct the string.
Expected Value: ColorFormatter
register("formatters", [
{
name: "hex-alpha",
value: {
bridge: "rgb",
fromBridge: (coords) => coords,
format: (coords, options) => {
const [r, g, b, a = 1] = coords;
const toHex = (n: number) => Math.round(n).toString(16).padStart(2, "0");
return `#${toHex(r)}${toHex(g)}${toHex(b)}${toHex(a * 255)}`;
},
},
},
]);
const color = Color.from("rgb(255 0 0 / 0.5)");
console.log(color.to("hex-alpha")); // "#ff00007f"5. Grammar Parsers & Shortcuts
If you need Saturon to understand completely new string syntaxes, use the "parsers" and "shortcuts" categories.
Shortcuts ("shortcuts")
Shortcuts are fast, regex-based interceptors evaluated before the main AST parser.
register("shortcuts", [
{
name: "<my-shortcut>",
value: {
appendTo: "<color>", // Hook this directly into the main parser
parse: (str) => {
if (str === "mystic-red") {
return { model: "rgb", coords: [255, 50, 50, 1] };
}
return null;
},
},
},
]);Advanced AST Parsers ("parsers")
For complex grammar, inject W3C-style syntactical nodes directly into grammarMap.
register("parsers", [
{
name: "<custom-prefix-syntax>",
value: {
appendTo: "<color>",
rule: "'custom:' <hex-color>",
parse: (node) => {
// Return model and coords extracted from the AST node
return { model: "rgb", coords: [255, 255, 255] };
},
},
},
]);6. Gamut Mapping Methods ("fit-methods")
Defines custom algorithms for mapping out-of-gamut colors to safe values during .within() or formatted output.
Expected Value: FitFunction
register("fit-methods", [
{
name: "ceiling-clip",
value: (colorData) => {
// A brutal algorithm that forces any out-of-range value to 100
return colorData.coords.map((val) => (val > 100 ? 100 : val));
},
},
]);
const color = Color.from("color(display-p3 2 0 0)");
color.within("srgb", { method: "ceiling-clip" });Unregistering Components
To cleanly remove a plugin, pass its category and name to unregister().
Saturon will automatically prune the grammar trees, drop the parsers, and flush the global shortest-path caches to guarantee there are no dead routing edges.
import { unregister } from "saturon/registry";
unregister("color-models", ["my-rgb"]);
unregister("named-colors", ["brandprimary", "brandaccent"]);Next Steps: Explore the Recipes
For in-depth, detailed examples on implementing these advanced extensions, head over to the Recipes Overview.
Gamut Mapping & Out-of-Gamut Handling
Safely handle colors that exceed display capabilities using Saturon's inGamut(), within(), fit(), and format options.
Configuring device-cmyk() Color Profiles
Register real ICC-backed color profiles so device-cmyk() produces accurate, print-ready color instead of a naive approximation.