Skip to content

Facet Type Visual DNA

Ryan Shepherd edited this page May 21, 2026 · 4 revisions

Facet Type: Visual DNA

🎨 Shipped (experimental).

Drop an image, paste an image URL, or eyedrop any color visible on screen — the catalog filters to products in the closest matching color term.

what it is

A "view" facet that drives an existing color taxonomy or meta facet. Three input modalities collapse to the same pipeline:

image → 96×96 canvas → quantize → dominant hex → LAB ΔE → nearest term → store.set(target, [slug])

No new resolver path, no per-product image processing at index time. The match runs entirely on the values that already live in the target color facet's index, so it's instant and deterministic.

when to use it

  • Storefronts where shoppers come in with a color in mind ("find me something this color")
  • Inspiration-driven shopping — drop a Pinterest image, find catalog matches
  • Visual-first product categories: apparel, home goods, art, paint, furniture
  • Mobile, where typing the right color name is the wrong UX

when not to use it

  • Stores without color attributes — there's nothing to match against
  • Catalogs where "color" isn't the primary visual axis (pattern, texture, shape matter more) — Visual DNA only matches on dominant color
  • Catalogs that need true visual similarity (not just nearest color) — that's Visual DNA v2 → indexed ΔE, still on the roadmap

configuration

{
  "name": "visual_dna",
  "kind": "view",
  "display": "visual_dna",
  "label": "Visual DNA",
  "settings": {
    "target_facet": "color"
  }
}

options

Field Values What
kind "view" Required
display "visual_dna" Required
settings.target_facet facet name The color-bearing facet to drive. Must have display in {checkbox, radio, dropdown, swatch, swiper}.
source Not used

the three modalities

Modality How
Drop a file Drag an image onto the drop zone, or click it to open a file picker. Works for any browser.
Paste a URL Type / paste an image URL into the field and press Enter. The image host must send permissive CORS — otherwise the browser blocks the canvas read and the user sees a friendly fallback message.
EyeDropper Click the 🎨 Pick button to enter the browser's native EyeDropper, then click any pixel anywhere on screen. Chromium-only (Chrome, Edge, Brave, Opera) as of late 2025. The button is feature-detected and hidden where unsupported.

color matching: how it works

The frontend extracts one dominant color from the input via canvas sampling:

  1. Downsample the source image to 96×96 (cheap, GPU-friendly, kills JPEG noise).
  2. Quantize each pixel to 4 bits per channel → 4096 buckets total.
  3. Pick the heaviest bucket that isn't near-white or near-black — unless those are a clear majority, in which case keep them.
  4. Return the bucket-averaged RGB as a hex.

That hex is then compared against the target facet's color terms in CIE LAB ΔE76 space. The smallest ΔE wins; that term's slug is applied as a filter via the normal store pathway.

where the color terms come from

The renderer builds the term-color map server-side and inlines it on the wrapper element so the JS has no extra network round-trip:

Target facet kind Source of hex per term
Taxonomy term_meta.swatch_color (same key the Color Swatch facet uses), falling back to a built-in CSS-name table.
Meta / field Distinct facet_value rows in the index, looked up against the built-in CSS-name table.

The built-in table covers ~35 common color words (red, navy, olive, burgundy, salmon, khaki, mint, etc.) — enough that a vanilla catalog with no per-term color meta still works. Terms that can't be resolved are silently dropped.

URL state

Visual DNA writes through to the underlying color facet — it has no URL key of its own.

?_hof_color=red

Identical wire format to a normal checkbox/radio/dropdown selection. Deep links survive a display swap; the chip in the active-filters bar reads the same.

limitations (what this isn't)

  • Color only. Pattern, shape, texture aren't factors. A burnt-orange leather couch and a burnt-orange paper coaster match equally.
  • Limited by your terms. "Burnt orange" gets snapped to "orange" if that's the closest term you carry. The granularity ceiling is whatever your catalog has.
  • No ranking, just filter. Either you match the chosen term or you don't — there's no "fade out by visual distance" sort.

All three of these become solvable in Visual DNA v2, when the indexer extracts a dominant LAB per product image and the resolver returns ranked products by ΔE.

browser support

Modality Support
Drop file Universal
Paste URL Universal — but cross-origin images require permissive CORS on the host
EyeDropper Chromium-only (~80% global usage). Gracefully hidden in Firefox/Safari.

planned PHP filters

apply_filters( 'hof_visual_dna_color_map',       $map,      $target_facet );
apply_filters( 'hof_visual_dna_css_name_map',    $fallback );
apply_filters( 'hof_visual_dna_match',           $term,     $hex, $map );

see also

  • Color Swatch — the visual-by-attribute alternative (shopper picks from a set of squares, not from arbitrary input)
  • Ask — natural-language alternative when "find me things this color" lives in a longer sentence
  • Architecture — how view facets fit

Clone this wiki locally