96.5% score low on visual similarity. But 82 pairs are pixel-identical in at least one font.
The gap
In an earlier post, I listed font-rendering attacks as an explicit limitation:
Two characters might have identical Unicode skeletons but render differently in specific fonts, or have different skeletons but render identically in a particular typeface. Detecting this requires rendering glyphs and comparing pixel output. No purely Unicode-data-based approach handles it, and UTS #39 does not attempt to.
That was the gap. confusable-vision is the tool I built to close it: render every confusable pair, measure the pixels, and put a number on what “visually confusable” actually means.
What confusable-vision does
confusable-vision takes the 1,418 TR39 confusable pairs that map a non-Latin character to a Latin target (a-z, 0-9), renders both characters across every available system font, and computes SSIM for each pairing. The output is a scored JSON artifact: one continuous similarity score per pair, per font.
SSIM (Structural Similarity Index Measure) compares two images by evaluating luminance, contrast, and structural patterns across local windows. It returns a score from -1 to 1: 1.0 means the images are pixel-identical, 0 means no structural correlation, and negative values mean the images are anti-correlated (less alike than random noise). For glyph comparison, it answers the question: do these two rendered characters share the same visual structure?
The pipeline has two stages:
build-index renders all 1,418 source characters and 34 target characters as 48x48 greyscale PNGs, one per font that natively contains the character. Fontconfig is queried per-character to avoid brute-force rendering across all 230 fonts (97% reduction: 8,881 targeted renders vs 326,140 brute-force). score-all-pairs loads the render index and computes SSIM for every valid source/target combination. 235,625 comparisons, two modes: same-font (both characters in the same font) and cross-font (source in a supplemental font, target in a standard font).
... continue reading