Color Blindness Simulator Developer Reference
Architecture and maintenance notes for the Color Blindness Simulator: registry records, the Workbench and Palette audit views, mode-aware catalog rendering, floating panels, simulation modules, metrics, verification, and Library capture and restore.
Overview
The Color Blindness Simulator is a registry-driven ES module workspace. The page opens on a Workbench view that
runs the shared model engine directly, renders a catalog from static simulation metadata, opens
simulations as in-DOM floating panels, lazy-loads condition modules, routes controls into a shared
simulation core, and exposes Library restore through window.AAVisionSim.
Most feature work touches the registry, a disease module, panel state, Library binding, and discovery
files together.
1. File map
+- Page shell:
tool/vision-simulation/index.htmlprovides metadata, hero content, guide surfaces, filters, card hosts, SVG filters, and script imports, plus the view bar host ([data-vlab-navhost]), the Workbench container (#vd-workbench), and the container for the other four views (#vd-app). - Page entry:
js/tool/vision-deficiency.jsrenders the scope menu, cards, mode switching, favorites, Open Panels, keyboard shortcuts, andwindow.AAVisionSim, and lazy-loads the Compare, Palette audit, and Analytics views fromjs/tool/vision-compare.js,vision-audit.js, andvision-analytics.js.js/tool/vision-workbench.jsrenders the Workbench view and the view tabs. - Gating:
js/tool/vision-deficiency-gating.jsapplies the free daily simulation limit and usage meter around catalog activation; no mode or category is locked. - Registry:
tool/modules/registry/simulations.jsdefines the category map, 78 simulation records, model option presets, complexity values, and lazy module paths. - Condition facts:
tool/modules/registry/condition-facts.js, generated byscripts/generate-condition-facts.mjs, is the Node-safe list of all 78 conditions with severity score, summary, prevalence, color or spatial transform, and baked preview. The Workbench, the Palette audit, the catalog cards, and the API read it. - Workbench support:
js/tool/vision-field-effects.jsholds the field families shared by the Workbench stage and the catalog card, andjs/tool/vision-url-state.jswrites the shareable#v=hash, including the current view. - Floating panels:
tool/modules/floating/panel-manager.js,floating-panel.js,panel-state.js,panel-extensions.js,control-center.js, andverification-panel.jsmanage the workspace. - Core:
tool/modules/core/simulation-core.jsmounts the standard simulator UI, whileengine.jsprovides the model registry. - Models:
tool/modules/models/register-all.jsregisters CVD matrix, cone isolation, grayscale, inversion, rod vision, tint, and spectral model handlers. - Diseases:
tool/modules/diseases/*.jsexport condition-specificdiseaseConfigobjects and math functions. - Library binding:
js/library/tool-bindings.jscaptures and restores Color Blindness Simulator assets under tool idvision-simulation. - Styles:
css/vision-deficiency.css,vision-panel.css,vision-universal.css, andvision-workbench.cssown the workspace-specific surfaces with shared support from analyzer, color science, unified, dark mode, and legal CSS.
2. Page shell and registry
+The registry is the source of truth for what the page can show and what a panel can open. The page does not hard-code the full catalog; it asks the registry for categories and filtered simulation records.
- Counts: the current registry contains 78 simulations, 11 categories, 17 Basic simulations, and 61 Advanced simulations.
- Category keys:
color-vision,cone-isolation,ocular-conditions,retinal-dystrophies,optic-nerve-disorders,corneal-anterior-segment,perceptual-effects,vascular-retinal,vitreous-structural,developmental-congenital, andfunctional-aging. - Record fields: each simulation has
slug,name,category,prefix,complexity, optionalmodels,legacyHref, andmodulePath. - Model presets: CVD panels can expose Brettel (1997), Vienot (1999), and Machado-like choices. Cataract exposes yellow brunescence, sclerotic haze, and combined modes.
- Helpers:
getSimulation(),listSimulations(),listAllCategories(),listSimulationsByCategory(),filterByComplexity(), andloadDiseaseConfig()isolate catalog access. - Lazy import:
loadDiseaseConfig(slug)imports the disease module only when a panel is opened.
3. Catalog, modes, and search
+- Entry state:
js/tool/vision-deficiency.jsstores active category, favorites, recents, guide dismissal, and the current complexity mode in localStorage-backed state. - Special tabs:
__all__,__favorites__,__compare__,__audit__,__analytics__,__image__, and__open__route the page into non-category views. - Search: card filtering is debounced by 120 ms and checks each card's text: name, category, description, and its kind, complexity, and prevalence tags.
- Mode bridge:
getComplexityMode(),setComplexityMode(),applyModeVisibility(), andwatchModeVisibility()keep the page aligned with platform Basic, Advanced, and Both modes. - Favorites: favorite slugs live under
aa_vd_favorites. Recents live underaa_vd_recentsand are capped at 12. - Card activation:
onCardActivate()callspanelManager.open(sim, { allowDuplicate }). Shift, Ctrl, and Cmd request duplicate panels. - Public API:
window.AAVisionSim.simsexposes registry data,open(slug)opens a panel, andrestoreState(slug, state)reopens and restores a saved panel state.
4. Floating panel lifecycle
+- Manager:
panel-manager.jscreates the host and dock, enforces the five-panel cap, focuses panels, emitsaa-vd-panel-change, and persists sessions underaa_vd_session_v1. - Open flow: the page resolves the registry record and records recents; then
open()evicts an old unpinned panel if needed, creates a panel instance, mounts content, focuses it, and persists session data. - Panel actions: close, closeAll, focus, minimize, restore, minimizeAll, restoreAll, maximize, tileAll, cascadeAll, splitHorizontalAll, splitVerticalAll, stackAll, linkAll, and exportComparisonGrid are centralized on the manager; duplicate and pin are per-panel title bar actions.
- Panel DOM:
floating-panel.jsbuilds titlebar, body, resize handle, dock item, lazy module import, simulator template, and deferred initialization without iframes. - State:
panel-state.jspersists key controls underaa_vd_panel_states_v1and exposes read, write, collect, apply, and delayed save helpers. - Extensions:
panel-extensions.jsadds smart presets, CAM and illuminant controls, snapshots, recent changes, tooltips, and recommended parameters. - Control center:
control-center.jscreates the draggable Vision Control surface with bulk layout, sync, export, verify, and one focus tab per open panel. - Verification:
verification-panel.jsrenders a comparison grid, Delta E 2000 chart, refresh, export, and automatic sweep controls.
5. Simulator panel contract
+
Standard simulations are mounted through initializeSimulation(). Disease modules own
the math. The panel shell owns controls, output tabs, copy actions, state persistence, and image
rendering hooks.
- Config shape: a disease module exposes
diseaseConfigwith names, prefixes, defaults, sample image, model options,simulateColor(),processImageData(), optional CVD helpers, and optional post-filter controls. - Mount options: panel mode passes a scoped
root, per-panelprefix,disableUrl,disableSampleAutoload, anddisableWindowListenerswhere needed. - Generated controls: base color, HEX, random, severity, model, perceptual severity curve, deep pass, image input, copy HEX, copy CSS, advanced toggle, cone weights, export all CVD, and environment sections are created by the shared template.
- Output tabs: Chromaticity, Metrics, Image, Mindmap, and Model audit read the same panel state and update together.
- Render cadence: the core debounces color rendering and comparison rendering so slider movement and image changes stay responsive.
- Duplicate safety: IDs are generated with a panel-specific prefix, allowing two instances of the same simulation to coexist.
- Destroy: standard core instances return a destroyable controller so panel close can remove listeners and release image resources cleanly.
6. Models and disease modules
+- Engine registry:
tool/modules/core/engine.jsprovidesregisterModel(),getModel(),hasModel(),listModels(),listModelsByCategory(),simulateWithModel(),processImageWithModel(), andunregisterModel(). - Model bootstrap:
tool/modules/models/register-all.jsregisters matrix-based CVD models, cone isolation, grayscale, inversion, rod vision, tint, and spectral handlers. - CVD axes: protan, deutan, and tritan simulations can expose Brettel, Vienot, and Machado-like model choices.
- Condition modules: disease modules define disease-specific color transforms, image processing, sample assets, post filters, labels, and explanatory copy.
- Bespoke records: registry records can be marked bespoke when a condition does
not yet match the shared simulator contract. Keep the escape path through
legacyHref. - Risk: changing shared model math changes card previews, panel output, image processing, metrics, comparison exports, Library thumbnails, and saved restore expectations.
7. Metrics, appearance, and validation
+- Color metrics: panel helpers compute normalized HEX, RGB, HSL, LMS, CIE xy, Delta E 76, and Delta E 2000 for reference and simulated values.
- Charts: panel state helpers produce small canvas or DOM charts for RGB, HSL, LMS, chromaticity, and difference values.
- CAM controls: extension controls expose CAT16 adaptation, CAM16-UCS perceptual assumptions, CIECAM02 surround, Hunt-Stevens brightness, white point adaptation, illuminants, temperature, observer, surround, and viewing distance.
- Snapshots: snapshot data lives under
aa_vd_snapshots_v1and can restore named panel states. - History: recent change history tracks the last 10 panel changes and supports undo and clear.
- Verification panel: reads current panels through manager snapshots, charts Delta E 2000, and can export or sweep the active workspace for regression-style checks.
- Analytics: the catalog dashboard uses registry data plus severity metadata to render Matrix, Map, and Statistics views, with JSON and CSV export.
8. Library capture and restore
+- Binding:
js/library/tool-bindings.jsattaches/tool/vision-simulation/as tool idvision-simulationand asset typesimulation. - Focused capture: the capture path prefers the focused
.vd-panel.is-focusedpanel, then visible panels, then a workspace bookmark if no panels are open. - Canvas selection: capture looks for simulated output canvases by suffix and can fall back to the largest visible canvas.
- Asset payload: saved data includes simulation slug, category, the reference
color (the panel's base HEX), the simulated chip color, Delta E 76, Delta E 2000, settings,
panel_state(the panel's controls keyed by id suffix), and image preview data when available. - Settings fallback: if no canvas can be captured, the Library still saves a preset-style asset with semantic settings and restore data.
- Restore bridge: every panel gets a random instance prefix, so saved ids never
match a reopened panel. The binding therefore writes
panel_stateintoaa_vd_panel_states_v1under the slug, which the panel applies when it mounts, and then callswindow.AAVisionSim.restoreState(slug, state). That closes an existing same-slug panel, opens a fresh panel, waits two animation frames, applies saved input values, dispatches input and change events, and focuses the panel. Saves made beforepanel_statehave their suffixes recovered from the stored ids, and a panel asset waits (the restore returnsfalseand the Library retries) untilAAVisionSimexists. - Compatibility: when changing generated control IDs, update capture suffix matching, restore fallbacks, and stored state fields together.
9. Workbench view
+- Shell:
js/tool/vision-workbench.jsrunsmountShell()on load. It draws the five view buttons (Workbench, Catalogue, Compare, Palette audit, Analytics) into[data-vlab-navhost]and addsgoToView(),currentView()andtoWorkbench(slug)towindow.AAVisionLab. The other four views are still rendered byvision-deficiency.jsinto#vd-app: the router callsAAVisionLab.switchCategory()with__all__,__compare__,__audit__or__analytics__, and Catalogue returns to the category saved inaa_vd_active_category. - Start view: the last view is stored in
aa_vd_lab_view; a?vw=link always starts on the Workbench. - Data: the condition list comes from
CONDITION_FACTSand the ten reference swatches fromREFERENCE_STRIPintool/modules/registry/condition-facts.js. Until the engine has loaded, a color condition shows its baked preview, which is the engine's output at the clinical default. - Engine: after the first paint,
loadEngine()importstool/modules/models/register-all.jsandtool/modules/core/engine.js.simHex()callssimulateWithModel()with the condition's registry model, and a dropped image goes throughprocessImageWithModel()after it is scaled to at most 900 pixels on its longer side. Nothing is reimplemented, so the Workbench, the panels and the API use the same functions. - Model choice:
axisOf()recognizes the Brettel, Viénot and Machado protan, deutan and tritan model ids, so only those six conditions take the model buttons;modelIdFor()swaps the publication and keeps the axis. - Field conditions:
fieldKind()andfieldCss()fromjs/tool/vision-field-effects.jsmap each of the 61 spatial conditions to one of the six families inFIELD_LABEL. The catalog card uses the same map, so both paint the same loss. - What collapses:
collapsedPairs()checks the 45 pairs of reference swatches and keeps a pair whose Delta E 2000 was 12 or more before simulation and is under 8 after it, sorted by how far it fell. - State:
aa_vd_workbenchstores the condition, severity, model, specimen and base color, written 400 ms after the last change. The defaults are deuteranopia, 100, Brettel, the interface specimen and#E53E3E.readDeepLink()reads?vw=<slug>:<severity>:<model>. - Exports:
mountWorkbench(host),mountShell(),goToView(name)andhasDeepLink().
10. Palette audit view
+- Loading: when the page switches to
__audit__,vision-deficiency.jsimportsjs/tool/vision-audit.jsand callsrenderPaletteAudit(host). That first loadsregister-all.js,engine.jsandcore/color-math.js, which no other view needs. - The audit:
computeAudit(palette, threshold)takes the 17 conditions fromlistColorConditions(), simulates every color with each condition'stransform.modelat itstransform.severity, and compares every pair in CIELAB with Delta E 2000. Pairs under the threshold are kept with their Delta E before and after, and each color counts how many merges it is part of. Conditions are sorted by merges, then severity score, then name; the first is the worst if it merges anything. The Workbench's model and severity are not used. - Suggest a fix:
suggestFix(pair, condition, threshold)blends the second color of the pair toward white and toward black in 4% steps up to 80%, and returns the first step at which the simulated Delta E 2000 reaches 1.25 times the threshold, taking the smaller RGB change when both directions work, ornull. - Inputs and storage:
normalisePalette()keeps unique#RRGGBBvalues up toMAX_COLORS= 24;DEFAULT_THRESHOLDis 5. The palette and threshold are stored inaa_vd_audit_paletteandaa_vd_audit_threshold; search, the failing filter and suggested fixes live only in the session. - Exports:
renderPaletteAudit(host), andauditPalette(palette, threshold), the audit without any DOM, for tests. - API:
POST /v1/vision/auditinapi/lib/handlers/vision.jsanswers the same question on the same engine; neither wraps the other. - Tests:
tests/website/vision-audit.spec.js(run withnpm run test:website:browser) checks that the audit covers every color condition, finds a merging pair, gates on the threshold, that a suggested fix separates its pair, that the palette survives a reload and the three-column layout.npm run test:visionrunstests/vision/condition-facts.test.jsagainst the registry and the engine.
11. Extension checklist
+- Choose the existing category that best matches the simulation before adding a new category.
- Create or update a disease module in
tool/modules/diseases/that exports a completediseaseConfig. - Add a registry record with stable slug, name, category, prefix, complexity, and model options.
- Only mark a record bespoke when the standard simulator contract cannot support it yet.
- Register any reusable model math in
tool/modules/core/engine.jsthroughregister-all.js. - Check that opening the new simulation's card still counts toward the free daily simulation limit.
- Verify panel state fields, linked control keys, snapshot behavior, and recent-change behavior.
- Update Library capture and restore when new controls add important semantic state.
- Update user and developer documentation, documentation JSON, RSS, sitemaps, PWA cache manifest, and search index.
- Run catalog, panel, metrics, export, restore, and accessibility smoke tests before release.
12. Testing and risk notes
+- Catalog: verify All, scope menu categories, Favorites, Compare, Palette audit, Analytics, Open Panels, mode switch, search debounce, favorites, recents, keyboard shortcuts, and empty state.
- Gating: test the usage meter, daily limit behavior, and card click interception.
- Panels: open five panels, duplicate a panel, exceed the cap, pin every panel, drag, resize, minimize, restore, maximize, close, tile, cascade, split, and stack.
- Linked controls: link two or more panels and test base color, severity, model, perceptual curve, deep pass, cone weights, illuminant, CAM controls, and image-dependent controls.
- Metrics: smoke test Delta E 76, Delta E 2000, CIE xy, LMS, RGB, HSL, charts, model audit, and mindmap output.
- Image rendering: test upload, clear, multi-pass deep, comparison grid, high-DPI canvas sizing, and large image responsiveness.
- Workspace views: test Compare selection, Matrix, Map, Statistics, JSON export, CSV export, verification refresh, verification export, and automatic sweep.
- Library: save a focused panel, save multiple visible panels, save a workspace bookmark, restore each asset, and confirm values are applied after the two-frame restore pass.
- Risk: registry changes affect catalog UX, search, Analytics, Compare, Library saves, generated documentation feeds, and SEO pages. Shared model changes affect every panel using that model family.