Skip to main content
Auric Artisan · Documentation

Tone Mapping Developer Reference

Architecture and maintenance notes for the Tone Mapping Lab, including page structure, helper behavior, state, transfer functions, tone operators, color-space matrices, Bradford adaptation, CPU image processing, scopes, exports, URL state, public API, Library integration and testing risks.

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

Overview

Tone Mapping Lab is implemented as a browser-only CPU pipeline in js/tool/tone-mapping.js, with page-level tab, guide, dropdown and fullscreen helpers in js/tool/tone-mapping-page.js. The runtime owns EOTF/OETF conversion, tone mapping operators, color-space transforms, Bradford white-point adaptation, procedural and uploaded sources, grading, gamut mapping, scopes, LUT exports, batch analysis, compact URL state, window.AAToneMapping and window.AAToneEngine, which js/tool/tone-mapping-views.js reads to render the Lab, Operators, Scopes, Data, Export and Reference views.

Table of contents

  1. 1. File map
  2. 2. Page shell and helper contract
  3. 3. State model
  4. 4. Transfer functions and operators
  5. 5. Color spaces and adaptation
  6. 6. Image pipeline
  7. 7. Scopes and rendering
  8. 8. Exports, batch 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/tone-mapping/index.html declares metadata, hero content, the six tab panels, controls, canvases, hidden action buttons and fullscreen overlay.
  • Page helper: js/tool/tone-mapping-page.js handles guide dismissal, tabs, dropdown label synchronization and fullscreen chart copying.
  • Runtime: js/tool/tone-mapping.js contains transfer functions, operators, matrices, state, processing, scopes, exports, batch analysis and public API. js/tool/tone-mapping-views.js renders the six views and js/tool/tm/tm-sources.js holds the dataset register as window.AAToneSources.
  • Library binding: js/library/tool-bindings.js registers the route as tone-mapping, name Tone Mapping, category Gamut & Rendering and asset type preset.
  • Runtime Library hooks: shared capture maps toneMapping to window.AAToneMapping.getState and restore to window.AAToneMapping.restoreState.

2. Page shell and helper contract

+
  • App root: tm-app wraps all tool controls and panels.
  • Tabs: the helper activates panels by data-tm-tab and panel ids p-tm-lab, p-tm-operators, p-tm-scopes, p-tm-data, p-tm-export and p-tm-reference.
  • Guide: the helper still stores tm-guide dismissal in local storage under aa_tm_guide_dismissed, but the current shell has no guide element.
  • Dropdown sync: tone-mapping-page.js patches the value setter for hidden dropdown inputs such as tm-source, tm-src-encoding, tm-op, tm-working, tm-target-prim and tm-oetf. The current shell uses native selects and a segmented operator control, so the patch finds no custom dropdown to sync.
  • Fullscreen charts: the helper copies source canvases into tnm-chart-fs-canvas for tm-view, tm-curve, tm-hist, tm-waveform, tm-vectorscope and tm-compare-canvas.
  • Control contract: the runtime depends on stable ids. Rename controls only with matching updates to readState(), restoreState(), event binding, URL state, exports and docs.

3. State model

+

The authoritative settings object is produced by readState().

  • Source: source, srcEnc, srcPrim, srcWhite, srcPeak and exposure.
  • Operators: op, lowOp, lowA and lowB.
  • CDL and creative grading: contrast, saturation, lift, gamma, gain, temp, tint, hue and vibrance.
  • Working and output: working, gamutMap, targetPrim, targetWhite, peak and oetf.
  • Custom curve: useCustom, knee, mid and shoulder.
  • Overlays and split: showOog, dither, falseColor, splitEnable and splitPos.
  • Runtime globals: hdrImg stores the current source, mappedImg stores the processed RGBA result and stateA/stateB store A/B split buffers.

4. Transfer functions and operators

+
  • Transfer functions: srgbEotf(), srgbOetf(), gammaEotf(), gammaOetf(), pqEotf(), pqOetf(), hlgOetf() and hlgEotf().
  • Encoding dispatch: toLinear() and fromLinear() map UI encodings to linear scene values and output code values.
  • Tone operators: tmReinhard(), tmReinhardExt(), tmHable(), tmACES(), tmUchimura(), tmGammaScale(), tmScaledReinhard(), tmLog() and applyCustomCurve().
  • Main dispatch: applyTM() selects none, reinhard, uchimura, hable, aces, bt2446a (or gamma-scale), bt2446c (or scaled-reinhard), log or custom. The two former BT.2446 ids are not tone curves; OPERATORS marks them isCurve: false, so the Lab offers seven and they stay reachable only by saved links.
  • Low-level dispatch: applyLowOp() handles add, multiply, softclip, power, sigmoid, exp, log and tanh before the main tone mapper.
  • Curve drawing: drawCurveCanvas() plots applyTM() from input 0 through 5 against the current operator configuration.

5. Color spaces and adaptation

+
  • Matrix helper: MUL3() multiplies row-major 3x3 matrices by RGB or XYZ vectors.
  • Supported spaces: sRGB/Rec.709, Display P3, Rec.2020 and ACEScg have forward-to-XYZ and inverse-from-XYZ matrices.
  • White points: ILLUMINANT_XYZ defines D65, D60 and D50.
  • Conversion: toXYZ() and fromXYZ() convert between RGB working spaces and XYZ.
  • Bradford adaptation: BRAD_M, BRAD_MI and bradfordAdapt() adapt source and target white points.
  • Gamut mapping: processPixel() implements clip, preserve hue and soft compression after conversion into target primaries.

6. Image pipeline

+
  • Sources: genHDRScene() creates the default HDR test scene, genGradient() creates the procedural HDR ramp, genPatches() creates color-checker patches and uploads are decoded through a temporary canvas into Float32Array data.
  • Pixel path: processPixel() linearizes, converts to working space, adapts white point, applies exposure, low operator, tone mapping, CDL, temperature/tint, hue, vibrance, target conversion, gamut mapping, output OETF and optional dithering.
  • Image pass: processImage() loops over every pixel, writes an 8-bit mapped RGBA buffer and counts, and masks, pixels that leave the target gamut.
  • Viewport: renderViewport() writes the mapped buffer, false color buffer, out-of-gamut overlay or A/B split into tm-view.
  • Scheduling: scheduleUpdate() debounces work through requestAnimationFrame, processes the image, renders the viewport, updates scopes, chips and numeric labels.

7. Scopes and rendering

+
  • Histogram: computeHistogram() and drawHistCanvas() draw RGB channel histograms from mapped display data.
  • Waveform: computeWaveform() and drawWaveCanvas() bin luma by image column.
  • Vectorscope: computeVectorscope() and drawVecCanvas() render Cb/Cr distribution.
  • HUD chips: updateChipInfo() updates processing time, working and target spaces, operator, resolution, OOG warning, adjustment domain and behavior label.
  • Value labels: updateValueDisplays() refreshes exposure, source peak, low op parameters, contrast, saturation, peak, custom curve values and intent label.
  • Page fullscreen: fullscreen chart display is handled outside the runtime by tone-mapping-page.js.

8. Exports, batch and URL state

+
  • PNG: exportPNG() serializes tm-view as PNG, behind the hidden tm-export-png button.
  • JSON: exportJSON() downloads readState() and importJSON() maps JSON keys back to tm-* ids, behind hidden buttons.
  • 1D LUT: the Export tab uses exportCurveCube() (a 33-entry 1D .cube with DOMAIN_MIN/DOMAIN_MAX and a header naming the steps it omits) and exportCurveCSV() (1024 samples over 0–1 or 0–12). The older export1DLUT(), 1024 samples over 0–5 to tone-map-1d.csv, sits behind a hidden button.
  • 3D LUT: exportPipelineCube() writes a 17-point .cube that runs every pipeline step. The older export3DLUT(), a 33 point .cube with per-channel curve mapping, sits behind a hidden button.
  • URL: saveURL() stores op, exp, src, peak, oetf and tp. loadURL() restores those fields.
  • Batch: runBatch() parses six-digit HEX colors, applies processPixel() and writes source, mapped color and OOG status. exportBatchCSV() serializes the resulting table.
  • Presets: applyPreset() configures SDR 100, HDR 1000 and P3 600.
  • Benchmarks: runBench() repeatedly runs processImage() and reports average milliseconds per frame.
  • Operator comparison: the Operators tab builds its table from compareOperators() and draws every curve on tm-compare-canvas. The older runOperatorComparison(), which times each operator and draws a bar chart, sits behind the hidden tm-compare-run button.

9. Public API and library binding

+
  • API: window.AAToneMapping = { getState, restoreState }.
  • getState(): returns settings, whether the current source is an uploaded image, image size, whether a mapped buffer exists, whether A/B buffers exist and batch textarea input.
  • restoreState(saved): accepts a full object or bare settings, applies known ids, restores batch input, rebuilds the procedural source when needed, schedules an update and returns true.
  • Simple binding: attachTool() captures the first available canvas as Tone mapping output with asset type image, otherwise falls back to Tone mapping preset.
  • Generic restore: the simple binding triggers tm-render, tm-apply and tone-mapping-render. Prefer window.AAToneMapping.restoreState() for exact state restore.
  • Upload limitation: runtime state records upload presence and image size, not uploaded image bytes. Persist source images separately when needed.

10. Extension checklist

+
  1. When adding a tone operator, update applyTM(), the OPERATORS list, behavior labels, curve drawing, operator comparison, formulas, docs and tests.
  2. When adding a low-level operator, update applyLowOp(), low-op dropdown labels, parameter ranges and examples.
  3. When adding a color space, provide forward and inverse XYZ matrices, white-point behavior, dropdown entries, gamut mapping expectations and LUT tests.
  4. When changing state fields, update readState(), restoreState(), JSON export/import, URL state if appropriate, Library documentation and smoke tests.
  5. When changing scope math, verify histogram, waveform and vectorscope remain coherent for both procedural and uploaded sources.
  6. When changing LUT export, document whether the LUT represents only the curve or the full color pipeline.
  7. When changing page ids, update page helper dropdown sync, fullscreen map, runtime binding and Library binding.
  8. When changing uploaded image handling, test large images and memory use because CPU processing is linear in pixel count.
  9. Regenerate documentation discovery outputs after docs changes with scripts/generate-discovery.mjs, scripts/generate-pwa-cache-manifest.mjs and search/client/build-index.js.
  10. Keep user-facing copy clear that this is a diagnostic and design tool, not official ACES, Dolby Vision or calibrated measurement software.

11. Testing and risk notes

+
  • Boot: verify the HDR test scene appears, tone curve, histogram, waveform and vectorscope draw, and chips update.
  • Sources: test the HDR test scene, exposure gradient, color checker and uploaded images.
  • Operators: test none, Reinhard, Uchimura, Hable, the Narkowicz fit, Log and Custom, plus the two former BT.2446 ids through a saved link.
  • Pipeline controls: test source encoding, primaries, white points, exposure, low ops, CDL, working space, gamut map, target primaries, target white, peak and OETF.
  • Actions: test presets, every Export tab selection (the tone curve as .cube and CSV at both domains, the whole pipeline, a link), A/B split, custom curve presets and benchmarks.
  • Research: test operator comparison, batch table, batch CSV and false color.
  • Library: save a canvas preset, capture full state, restore state and confirm batch input returns.
  • Numerical risk: transfer constants, matrices, Bradford adaptation, tone operators and gamut mapping changes will alter viewport pixels, scopes, LUTs and exported JSON.
  • Performance risk: large uploaded images can block the main thread. Recheck interaction latency when expanding scope resolution or processing complexity.
  • Interpretation risk: the ACES option is a Narkowicz fit, the two operators once labelled BT.2446 do not implement BT.2446, and LUT exports are diagnostic approximations.