Skip to main content
Auric Artisan · Documentation

HDR Gamut Plot Developer Reference

Architecture and maintenance notes for the standalone HDR Gamut Plot Lab tool, including page structure, state, UI ids, RGB gamut metadata, PQ and HLG transfer math, ICtCp and JzAzBz conversions, canvas rendering, research panels, image analysis, batch conversion, exports, share URLs, public API, and Auric Library binding.

Published: May 24, 2026 Updated: May 24, 2026 Category: Reference Author: Chirag Bansal
Back to Documentation Auric Artisan Home

Overview

HDR Gamut Plot Lab is implemented as a browser-only IIFE in js/tool/hdr-gamut-plot.js. The engine owns color-space constants, spectral locus data, sRGB and BT.2020 matrices, PQ and HLG transfer functions, ICtCp and JzAzBz conversions, CIE diagram rendering, tone curves, perceptual planes, EOTF comparison, gamut boundary rings, image analysis, batch conversion, copy/export helpers, URL state, and window.AAHdrGamutPlot. The HTML shell in tool/general/gamut-and-rendering/hdr-gamut-plot/index.html declares the controls, canvases, tabs, and the Reference tab's standards, formulas, citations, and research notes.

Table of contents

  1. 1. File map
  2. 2. Page shell and UI contract
  3. 3. State model
  4. 4. Color data and transfer functions
  5. 5. Perceptual conversions
  6. 6. Rendering pipeline
  7. 7. Research tools
  8. 8. Exports and URL state
  9. 9. Public API and library binding
  10. 10. Extension checklist
  11. 11. Testing and risk notes

1. File map

+
  • Tool shell: tool/general/gamut-and-rendering/hdr-gamut-plot/index.html contains metadata, hero content, tab navigation, controls, canvases, export controls, the Reference tab's standards, formulas, citations, and research notes, toast node, fullscreen chart overlay, and script includes.
  • Tool engine: js/tool/hdr-gamut-plot.js contains the standalone runtime, rendering code, transfer math, export builders, state, URL restore, and public API.
  • Views and register: js/tool/hdr-gamut-plot-views.js builds the Curves, Planes, Data, Export, and Reference views from window.AAHdrEngine, and js/tool/hg/hg-sources.js provides the dataset register as window.AAHdrSources.
  • Library binding: js/library/tool-bindings.js registers /tool/general/gamut-and-rendering/hdr-gamut-plot/ as tool id hdr-gamut-plot, category Gamut & Rendering, asset type preset.
  • Shared runtime capture: js/library/tool-bindings.js also maps hdrGamut to window.AAHdrGamutPlot.getState and restore to window.AAHdrGamutPlot.restoreState.
  • Discovery outputs: documentation changes must be reflected in data/documentation.json, RSS, feed, sitemaps, PWA cache manifest, and search index by running the discovery scripts.

2. Page shell and UI contract

+
  • Application root: hg-app wraps the tool with role="application".
  • Tabs: tab buttons use data-hg-tab and panel ids p-hg-lab, p-hg-curves, p-hg-planes, p-hg-data, p-hg-actions (Export), and p-hg-reference.
  • Control ids: the engine reads hg-color-space, hg-overlay-toggles, hg-adv-toggles, hg-axes, hg-observer, hg-peak, hg-curve-type, hg-hlg-env, hg-signal-level, hg-plot-mode, and hg-tmo.
  • Label ids: runtime labels include hg-peak-val, hg-curve-peak-label, hg-axes-label, hg-axes-status, hg-hlg-gamma, and hg-ictcp-I-label.
  • Canvas ids: primary render targets are hg-gamut-canvas, hg-curve-canvas, hg-ictcp-canvas, hg-compare-canvas, hg-eotf-canvas, and hg-boundary-canvas.
  • Action ids: the Export rail uses hgTakeSeg, hgFormatSeg, hgTakeIt, and hgCopyIt with the preview in hgPreview; other actions are hg-upload-btn, hg-batch-run, and hg-batch-csv.
  • Do not rename ids casually: the engine uses direct id lookups. Any id change must be reflected in event binding, restore, export handlers, Library capture expectations, and tests.

3. State model

+

The authoritative state is produced by readState() in js/tool/hdr-gamut-plot.js.

  • colorSpace: active working key, default Rec2020 in the page and sRGB fallback in the engine. Its triangle is drawn at 3.5 px instead of 2.
  • overlays: object keyed by sRGB, P3, and Rec2020 with boolean checkbox state.
  • spectral: whether to draw the spectral locus.
  • purples: whether to draw the line of purples.
  • ictcpMarker: the ICtCp marker checkbox, which is disabled; nothing draws the marker yet.
  • axes: xy or uvp.
  • observer: observer label state, currently 1931-2 or 2015-10. The locus is drawn from the CIE 1931 2° table either way.
  • peakNits: display or mastering peak in nits, parsed from hg-peak.
  • curveType: gamma22, gamma24, pq, or hlg.
  • hlgEnv: dark, dim, or bright.
  • signalLevel: normalized 0 to 1 sample level.
  • plotMode: ictcp or jzazbz.
  • tmo: reinhard, hable, aces, or uchimura.

updateAll() debounces redraw with requestAnimationFrame, refreshes labels, redraws the three primary canvases, and updates metrics.

4. Color data and transfer functions

+
  • SPACES: built-in gamut registry with sRGB/Rec.709, Display-P3, and Rec.2020 labels, RGB primary xy coordinates, and D65 white point.
  • SP_CLR: display colors for the three gamuts.
  • Spectral locus: L2 is a flat CIE 1931 2 degree xy array from 380 nm to 700 nm in 5 nm steps.
  • sRGB matrices: M_S2X and M_X2S convert D65 sRGB values to and from XYZ.
  • BT.2020 matrix: M_BT_XYZ supports HDR perceptual conversion paths and JzAzBz calculations.
  • ICtCp matrices: M_BT_LMS and M_LMS_BT support BT.2100-style LMS conversion before PQ encoding.
  • PQ constants: PQ_M1, PQ_M2, PQ_C1, PQ_C2, PQ_C3, and PQ_MAX drive pqEotf(), pqOetf(), and pqEncode().
  • HLG helpers: hlgOetf(), hlgEotf(), and hlgSysGamma() drive curve generation and HLG environment labeling.
  • Tone curves: curvePoints() creates plotted samples for gamma, PQ, and HLG modes.
  • Tone mapping: tmReinhard(), tmHable(), tmAces(), tmUchimura(), and applyTMO() provide the operator options exposed in the UI. drawPerceptualPlane() calls applyTMO() and prints the mapped luminance on the plane.

5. Perceptual conversions

+
  • sRGB helpers: srgbGamma(), srgbLinear(), rgbToXyz(), xyzToSrgb(), hexToRgb(), and rgbToHex() support hover, batch, and color fill workflows.
  • CIELAB: xyzToLab() is used by hover sampling and batch output.
  • Chromaticity: xyToUpVp() converts xy into u-prime v-prime, while coordForAxes() returns coordinates for the active diagram mode.
  • ICtCp: pqEncodeLMS(), rgbToICtCp(), and ictcpToRgb() convert HDR RGB values into intensity and chroma components.
  • JzAzBz: xyzToJzAzBz() converts absolute XYZ values into Jz, Az, and Bz through its own quantiser, jzEncodeLMS() with JZ_P = 134.034375, for the perceptual plane and boundary calculations.
  • Gamut area: triArea() and gamutArea() calculate triangle area in the selected axes, and locusArea() and locusShare() turn it into the share of the spectral locus that powers metrics, CSV, CSS, and comparison output.

6. Rendering pipeline

+
  • Theme helpers: canvas renderers use the TH color helpers, which take the dark palette of the .hg-band deck in both light and dark page themes.
  • Chromaticity diagram: drawChromDiagram() renders background fill, spectral locus, line of purples, visible gamut triangles, labels, the D65 white point, and hover-ready coordinates.
  • Fill cache: changing overlay checkboxes or axes clears fillCache so chromaticity fill can be recomputed safely.
  • Tone curve: drawToneCurve() plots the selected curve with gamma 2.2 and, unless gamma 2.2 is selected, PQ reference curves on a log luminance axis that reaches 10000 nits whenever PQ is drawn.
  • Perceptual plane: drawPerceptualPlane() renders ICtCp Ct/Cp or JzAzBz Az/Bz output using the active plot mode, signal level, peak, and curve type.
  • Metrics table: updateMetrics() fills hg-metrics-body with transformed primaries, white point coordinates, share of the spectral locus, and triangle area.
  • Hover sampler: mouse movement over hg-gamut-canvas maps screen position back to xy, derives XYZ and Lab, computes ICtCp from the current signal level, and writes hg-hover-info.

7. Research tools

+
  • EOTF comparison: drawEotfComparison() draws PQ, HLG at 1000 nits, and gamma 2.2 on a log luminance grid from 0.1 to 10000 nits.
  • Boundary rings: drawGamutBoundary() draws ICtCp or JzAzBz rings at 0.1, 1, 10, 100, 500, 1000, 4000, and 10000 nits for enabled overlays.
  • Comparison chart: compareSpaces() renders a bar chart of each space's share of the spectral locus and updateCompareTable() fills hg-compare-tbody.
  • Batch conversion: runBatch() parses six-digit hex colors from comma-separated or line-separated input, calculates Lab, ICtCp, and JzAzBz values, writes an HTML table, and returns rows for the CSV download.
  • Image analysis: analyseImage() samples every fourth pixel from a local canvas, decodes it as sRGB to xy chromaticity, and writes the share of each gamut the pixels occupy, with no luminance figures, to hg-image-results. The sampled points are kept in the module-level imageCloud, which the chromaticity diagram draws as dots.
  • Image cap: uploaded image canvases are capped to 1024 pixels in each dimension before analysis to keep the browser responsive.

8. Exports and URL state

+
  • PNG export: exportPNG() serializes the selected canvas with toDataURL("image/png") and downloads it through a temporary anchor.
  • Download helper: downloadText() writes the batch CSV as hdr-batch-ictcp.csv through a temporary object URL and reports the file name through the toast. The Export tab's copy buttons live in hdr-gamut-plot-views.js.
  • JSON export: buildGamutJSON() exports all built-in gamut definitions plus metadata for axes, peak nits, curve type, and tool name.
  • CSV export: buildCSV() exports RGB primary coordinates, white point, area, and share of the spectral locus, with the locus area in a footer.
  • CSS export: buildCSSVars() exports locus-share and area variables, primary coordinate variables, plane, locus area, peak nits, and selected curve type.
  • Share state: stateToURL() stores axes, peak, curve, and mode.
  • URL restore: loadFromURL() applies those four query parameters before event binding and initial render.
  • Share limitation: overlays, observer, HLG environment, signal level, and tone mapping operator are not encoded in the share URL. Full Library restore handles a wider state object.

9. Public API and library binding

+
  • Boot: boot() loads URL state, binds events, renders the tool, then exposes window.AAHdrEngine and window.AAHdrGamutPlot.
  • API shape: window.AAHdrGamutPlot = { getState, restoreState }. getState() returns readState(). restoreState(saved) applies known fields, restores overlay checkboxes, calls updateAll(), and returns true for valid objects.
  • Restored fields: restore maps colorSpace, axes, observer, peakNits, curveType, hlgEnv, signalLevel, plotMode, and tmo to their matching control ids.
  • Overlay restore: if saved.overlays exists, each checkbox in hg-overlay-toggles is set from the matching key.
  • Simple binding: attachTool() matches the HDR route, uses tool id hdr-gamut-plot, name HDR Gamut Plot, href /tool/general/gamut-and-rendering/hdr-gamut-plot/, category Gamut & Rendering, and asset type preset.
  • Capture fallback: Library capture first calls firstToolCanvas() and saves HDR gamut plot as a canvas image. If no canvas exists, it falls back to captureFormPreset({ name: "HDR gamut preset" }).
  • Binding restore: the generic form binding triggers hdr-render and hdr-update. Prefer the public API restore when a full saved state object is available.

10. Extension checklist

+
  1. Add new RGB gamuts to SPACES with a stable key, label, red, green, blue, and white xy arrays.
  2. Add a display color to SP_CLR and update overlay controls if the new gamut should be user-toggleable.
  3. Update metrics, JSON, CSS, CSV, comparison, and docs if the new gamut should appear in exports.
  4. When adding a transfer curve, update curvePoints(), keyboard shortcuts, labels, formula copy, share URL expectations, and tests.
  5. When adding a perceptual model, update drawPerceptualPlane(), drawGamutBoundary(), batch conversion, result headings, and exports.
  6. When changing state fields, update readState(), restoreState(), stateToURL() if appropriate, Library capture notes, and documentation.
  7. When changing canvas ids or dimensions, update export handlers, Library canvas capture behavior, fullscreen helpers, responsive CSS, and smoke tests.
  8. When changing image analysis, document whether pixels are assumed SDR, display-referred, or scene-referred so users do not treat estimates as calibrated measurements.
  9. Regenerate documentation discovery outputs after article edits with scripts/generate-discovery.mjs, scripts/generate-pwa-cache-manifest.mjs, and search/client/build-index.js.
  10. Keep standard names exact: Rec.709, Display-P3, Rec.2020, BT.2100, ST 2084 PQ, HLG, ICtCp, and JzAzBz.

11. Testing and risk notes

+
  • Boot: verify the Lab tab appears, controls have defaults, the three primary canvases render, and the metrics table populates.
  • Controls: exercise every color space, overlay toggle, advanced toggle, axes mode, observer value, peak value, curve type, HLG environment, signal level, plot mode, and tone mapping operator.
  • Keyboard: test 1, 2, 3, 4, and A outside form controls.
  • Hover: move over the chromaticity diagram in xy and u-prime v-prime modes and verify the coordinate readout updates without console errors.
  • Actions: test JSON, CSS, CSV, link copy, compare chart, diagram PNG, curve PNG, and perceptual plane PNG.
  • Research: confirm the EOTF comparison draws on the Curves tab and the gamut boundary on the Planes tab, upload a sample image in the Lab, then run batch conversion and download the batch CSV on the Export tab.
  • URL: create a share URL, reload it, and verify axes, peak, curve, and plot mode restore before first render.
  • Library: save a preset snapshot, confirm the canvas preview, restore full runtime state, and verify overlay checkboxes return to saved values.
  • Numerical risk: changes to PQ constants, HLG gamma, matrices, spectral locus, or JzAzBz constants will alter diagrams, batch output, exported JSON, and comparison metrics.
  • Interpretation risk: xy area, u-prime v-prime area, ICtCp/JzAzBz plots, and browser image estimates answer different questions. Keep UI copy and docs explicit about what each result means.