Gamut Explorer Developer Reference
Architecture and maintenance notes for the standalone Gamut Explorer tool, including page structure, runtime state, color-space metadata, matrix derivation, chromaticity renderers, transfer functions, Lab and OKLab slices, Monte Carlo volume, custom local library storage, exports, share URLs, public API, and Library binding.
Overview
Gamut Explorer is implemented as a self-contained browser IIFE in js/tool/gamut.js. The engine
owns the color-space registry, 380-780 nm CMF data (the drawn spectral locus keeps 380-715 nm), CIE xy
and u-prime v-prime conversion,
RGB to XYZ matrix derivation, transfer functions, canvas renderers, Lab and OKLab slices, wireframes,
Halton-sampled volume and overlap metrics, local storage library exchange, URL state, exports, and
window.AAGamutLab. The HTML shell in
tool/general/gamut-and-rendering/gamut/index.html declares all controls and reference
content. js/tool/gt/gt-sources.js holds the dataset register, and
js/tool/gamut-views.js draws the Transfer, Compare, Data, Export, and Reference views.
1. File map
+- Tool shell:
tool/general/gamut-and-rendering/gamut/index.htmlcontains metadata, hero content, tab navigation, control panels, canvases, the export and library panels, the Reference view (standards, formulas, references, research notes), and fullscreen chart overlay. - Tool engine:
js/tool/gamut.jscontains the standalone IIFE that implements color math, state, rendering, exports, local library management, URL state, and the public API. - Library integration:
js/library/tool-bindings.jsregisters the/tool/general/gamut-and-rendering/gamut/route as tool idgamut. - Generated page helpers: the page loads generated inline scripts and
/js/unified.jsfor shared site behavior and chart interactions. - Documentation discovery: guide and reference entries are sourced from
data/documentation.jsonand generated into RSS, sitemaps, PWA cache manifest, and search outputs.
2. Page shell and UI contract
+- App root:
#gt-appwraps the Gamut Explorer interface. - Tabs: buttons use
data-gt-tab; panels usep-gt-lab,p-gt-transfer,p-gt-compare,p-gt-data,p-gt-actions, andp-gt-reference. - Primary selectors:
gtActiveSpace,gtDiagramMode,gtObserver,gtTransferPreset,gtVolumeRef,gtVolumeTarget, andgtSliceMode. - Overlay checkboxes:
gtShowSpectral,gtShowGrid,gtShowMacAdam,gtShowLabels,gtShowAllSpaces, andgtShowFill. - Probe outputs:
gtVertexX,gtVertexY,gtVertexLumi,gtVertexChip,gtVertexSRGB,gtVertexHex,gtVertexLab, andgtVertexMembership. - Primary inputs:
gtPrimRx,gtPrimRy,gtPrimGx,gtPrimGy,gtPrimBx,gtPrimBy,gtPrimWx, andgtPrimWy. - Matrix and metric outputs:
gtWhiteX,gtWhiteY,gtWhiteZ,gtMatrixRgb2Xyz,gtMatrixXyz2Rgb,gtAreaMetrics,gtVolumeMetrics, andgtSliceMetrics. - Canvas outputs:
gtMainCanvas,gtTransferCanvas,gtSliceCanvas, andgtWireCanvas. - Action controls:
gtExportPng,gtExportSvg, the Export tab'sgtTakeSeg,gtFormatSeg,gtTakeIt, andgtCopyIt, andgtImportFromText. - Exchange outputs:
gtPreview,gtExportStatus,gtLibraryBody,gtImportText, andgtExchangeStatus.
3. State model
+
Runtime state is declared inside boot(). Event handlers mutate the object, then call
targeted renderers. window.AAGamutLab.getState() returns a JSON clone of this state.
- Diagram state:
modeisxy,upvp, or3d. The page also renders separate slice and wireframe canvases regardless of the main diagram mode. - Space state:
spacesstarts assRGB,DisplayP3, andRec2020. Selecting a working space moves that key to the front of the active list. - Overlay state:
showLocus,showGrid,showLabels,showMacAdam,showFill, andshowAllSpacesmirror the checkbox controls. - Probe state:
probeXandprobeYstore the latest clicked or dragged coordinate. - Transfer state:
transferPresetselects the color-space metadata used bydrawTransferCurve(). - Custom state:
customPrimariesstores editable red, green, blue, and white xy values. - Volume state:
volumeRefandvolumeTargetselect the comparison pair for Monte Carlo volume and overlap. - Slice state:
sliceModechoosesLstarorOKLab, whilesliceLevelcontrols the lightness slider. - URL restore: the
squery parameter is decoded withdecodeState()and merged into state before rendering.
4. Color-space registry
+- Registry object:
SPACESstores all standard and runtime custom spaces. - Required fields: each space stores
r,g,b,w,label, andgamma. - Supported standard keys:
sRGB,DisplayP3,DCI-P3,Rec2020,Rec2100-PQ,Rec2100-HLG,AdobeRGB,ProPhotoRGB,AdobeWideGamut,ACES AP0,ACES AP1,NTSC-1953, andPAL-SECAM. - Custom key: solving editable primaries registers
SPACES.custom. - Local library keys: imported custom definitions register their
def.nameinsideSPACESduring import and restore. - Matrix cache:
_matCachestores derived matrices by space name. Custom updates must delete stale cache entries. - Chart colors:
GAMUT_COLORSprovides reusable stroke colors for diagrams and comparison overlays.
5. Color math and matrices
+- CMF grid:
LAMBDAspans 380 to 780 nm in 5 nm steps, with CIE 1931CMF_X,CMF_Y, andCMF_Zarrays. - Chromaticity:
xyToUpVp(),xyzFromXy(), andxyzToXy()provide xy, XYZ, and u-prime v-prime conversions. - Lab:
xyzToLab(),labToXyz(), andlchToLab()support volume, slices, probe output, and wireframe construction. - OKLab:
oklabToSrgb()supports OKLab slice boundary searches. - Matrix helpers:
mat3inv(),mat3mulv(),mat3mul(), andmat3diag()implement the small matrix operations. - Matrix derivation:
deriveMatrices(sp)converts primary xy to XYZ columns, solves scale factors against the white point, buildsrgb2xyz, and inverts it forxyz2rgb. - Transfer functions: sRGB, gamma, BT.2020, ROMM, PQ, and HLG functions are
provided through
srgbEOTF(),srgbOETF(),gammaEOTF(),gammaOETF(),bt2020EOTF(),bt2020OETF(),rommEOTF(),rommOETF(),pqEOTF(),pqOETF(),hlgEOTF(), andhlgOETF(). - Transfer dispatch:
resolveTransferLabel(),eotfForSpace(), andoetfForSpace()map registry gamma values to UI labels and functions;transferFidelity()marks HLG as partial because only the inverse OETF runs. - In-gamut tests:
isInGamutLinear()checks linear RGB bounds, whileisInGamut()converts XYZ through the target matrix before checking channels.
6. Rendering pipeline
+- Spectral locus:
buildSpectralLocus()derives xy and u-prime v-prime locus arrays from CMFs, cached bygetLocusXY()andgetLocusUpVp(). - Coordinate mapping:
xyToCanvas()andcanvasToXy()use bounds objects for xy, u-prime v-prime, Lab a*b*, and OKLab a/b canvases. - Shared drawing:
drawGrid(),drawLocus(),drawGamutTriangle(), anddrawMacAdamEllipses()build the 2D chromaticity layers. - Main diagram:
renderChromaticityDiagram()clears the canvas, optionally fills the locus with WebGL2, draws grid, locus, MacAdam ellipses, space triangles, and probe marker. - WebGL fill:
renderWebGLFill()compiles a compact WebGL2 shader pipeline that fills visible chromaticity coordinates inside the spectral locus. - Transfer curve:
drawTransferCurve()draws axes, active EOTF, and linear reference. PQ is displayed on a log-scaled luminance axis. - Slice renderer:
renderSliceDiagram()draws CIELAB or OKLab gamut boundary rings for active spaces. - Boundary solvers:
gamutSliceLab()andgamutSliceOKLab()search chroma by bisection at each hue angle. - Wireframe:
buildWireframe()creates Lab rings and meridians;drawWireframe()projects them to 2D with fixed view angles. - Comparison rows:
buildComparisonTable()combines xy area, percent of sRGB, u-prime v-prime locus share, Monte Carlo volume with its spread, transfer label, and white point into table data. - Probe:
queryPoint()converts a point to XYZ, Lab, sRGB preview HEX, and per-space triangle membership.
7. Exports, share state, and local library
+- PNG export:
exportCanvasPNG(canvas, filename)usescanvas.toDataURL("image/png")and a temporary anchor. - SVG export:
exportCanvasSVG(canvas)wraps the canvas PNG data URL in an SVG image element. - JSON export:
exportSpaceJSON(name)writes space name, label, primaries, white point, gamma, matrices, and xy area. - CSV export:
exportComparisonCSV(rows)writes comparison rows for name, xy area, percent of sRGB, Lab volume, transfer, and white point. - Share encode:
encodeState(state)Base64-encodes JSON state;buildShareURL(state)stores it as query parameters. - Share decode:
decodeState(str)parses the Base64 state and fails softly tonull. - Local library key: custom spaces are stored under
aa_gamut_library. - Library functions:
loadLibrary(),saveLibrary(),addCustomSpace(),removeCustomSpace(), andrestoreLibrary()manage custom definitions and runtime registry hydration. - Import format: import expects JSON with
name,primaries.r,primaries.g,primaries.b,whitePoint, and optionalgamma. - Reset behavior: Reset view restores xy mode, clears the probe, and restores primary overlay defaults without clearing custom library data.
8. Public API and library binding
+- Namespace: the tool exposes
window.AAGamutLabafter boot. - getState: returns a JSON-cloned copy of the internal runtime state.
- restoreState: validates the input object, merges it into state, renders main, slice, transfer, and wireframe canvases, then updates the library table.
- Shared runtime capture:
js/library/tool-bindings.jsincludesgamutLab: window.AAGamutLab?.getStatein full tool-state capture. - Shared runtime restore: restore routes include
["gamutLab", window.AAGamutLab?.restoreState]. - Tool binding: the route matcher uses
/tool/general/gamut-and-rendering/gamut/, idgamut, nameGamut Explorer, categoryGamut & Rendering, and asset typepreset. - Binding capture: the simple binding captures the first available tool canvas as
a
Gamut snapshot. If no canvas is available, it falls back tocaptureFormPreset(). - Binding restore: the simple binding uses generic form restore triggers
gamut-render,gamut-update, andgm-render. Preferwindow.AAGamutLab.restoreState()when exact runtime state is available. - Storage note: the tool's custom local library is separate from Auric Library
asset saves. The local color-space library uses browser
localStorage.
9. Extension checklist
+- Add new spaces to
SPACESwith stable key, primary xy arrays, white xy array, label, and gamma descriptor. - Add matching dropdown entries in
index.htmlfor working space, transfer preset, volume references, or comparison targets as needed. - Verify
deriveMatrices()returns invertible matrices for the new space. - When adding a transfer type, update
resolveTransferLabel(),eotfForSpace(),oetfForSpace(), equation output, standards text, and tests. - When changing state, update URL encode/decode expectations, public API restore, Library capture expectations, and documentation.
- When changing canvas sizes or ids, update export buttons, fullscreen helper assumptions, Library canvas capture behavior, and smoke tests.
- When adding import fields, keep
exportSpaceJSON(), import validation, local library restore, and docs in sync. - Regenerate discovery outputs after documentation changes with
scripts/generate-discovery.mjs,scripts/generate-pwa-cache-manifest.mjs, andsearch/client/build-index.js. - Document whether new gamut computations are xy-only, Lab volume, profile-based, or display-luminance-aware so users do not overread the result.
- Keep official standard names and transfer-function references accurate when adding or renaming spaces.
10. Testing and risk notes
+- Boot: the page loads, the Lab tab is active, all four canvases render, matrices populate, and the library table populates.
- Selectors: test every working space, diagram mode, transfer preset, volume reference, volume target, and slice mode.
- Overlays: toggle spectral locus, grid, MacAdam ellipses, labels, all spaces, and WebGL fill.
- Probe: click and drag the main canvas in xy and u-prime v-prime modes and verify coordinates, HEX, Lab, and membership output.
- Custom primaries: edit values, solve Custom, verify matrices, export JSON, import JSON, reload the page, and confirm the custom library restores.
- Volume: compute sRGB, Display P3, Rec.2020, and ACES comparisons on desktop and mobile-class devices because Monte Carlo loops are CPU-bound.
- Exports: test PNG, SVG, active JSON, comparison CSV, and share URL restore after multiple state changes.
- Library: save a canvas snapshot through Auric Library, restore runtime state when available, and confirm local custom-space storage remains separate.
- Numerical risk: changes to CMFs, matrix inversion, gamma functions, Lab conversion, or Halton sampling will shift diagrams, volume estimates, CSV output, JSON matrices, and saved expectations.
- Interpretation risk: xy area, Lab volume, and display/rendering gamut are not interchangeable. Keep UI and docs explicit about what each metric measures.