
793 pares confundíveis ausentes do Unicode TR39, conjunto de dados cross-script inédito no mundo, pontuação SSIM com consciência de fonte em 230 fontes e mais de 22.000 caracteres
Pontuação empírica de similaridade de glifos usando raycasting de contorno vetorial. Renderiza pares de caracteres confusáveis Unicode em 245 fontes do sistema, mede a similaridade estrutural diretamente dos contornos das fontes (sem rasterização) e produz artefatos JSON com pontuações de distância contínua por fonte.
Resultados principais de 52,6 milhões de comparações de caracteres únicos e 190 milhões de comparações de múltiplos caracteres em 22.581 caracteres e 12 sistemas de escrita:
A saída alimenta diretamente namespace-guard para deteção de confusáveis em tempo de execução em nomes de pacotes, nomes de domínio e identificadores.
O RaySpace emite raios paralelos através de contornos de fontes em 36 ângulos e captura cinco camadas de informação por glifo: contagens de cruzamento, posições de cruzamento, ângulos de cruzamento, distâncias ping (largura do traço em cada cruzamento) e ping max (largura do contador entre cruzamentos). Isso produz uma assinatura compacta por caractere por fonte. Duas assinaturas são comparadas com uma distância L1 ponderada em todas as cinco camadas.
Um filtro em cascata de três estágios torna a comparação exaustiva tratável:
O banco de assinaturas (294.646+ entradas em 245 fontes; mais com --include-uppercase) é pré-calculado uma vez. A descoberta então é executada como aritmética single-threaded no banco, completando 52,6 milhões de comparações de pares em 31 minutos sem threads de trabalho ou GPU.
npm install
# 1. Construir o banco de assinaturas de raios (pré-requisito, ~24 min)
npx tsx scripts/build-signature-bank.ts
# 1b. Incluir maiúsculas Latin A-Z (opcional)
# Por padrão, o banco inclui apenas codepoints IDNA PVALID (minúsculas,
# dígitos, símbolos). Use --include-uppercase para adicionar maiúsculas A-Z,
# útil para identificação de fontes e comparação visual de marcas registadas
# onde as formas de glifos maiúsculos importam. O construtor é retomável,
# então isto apenas calcula os codepoints adicionais.
npx tsx scripts/build-signature-bank.ts --include-uppercase
# 1c. Incluir intervalos arbitrários de codepoints (opcional)
npx tsx scripts/build-signature-bank.ts --extra-range=0041-005A
# 2. Descoberta de caractere único (22.581 chars, 12 scripts, ~36 min)
npx tsx scripts/discover-singlechar-sdf.ts --scorer=ray
# 3. Descoberta de múltiplos caracteres (bigramas) (676 bigramas, ~63 min)
npx tsx scripts/discover-multichar-sdf.ts --scorer=ray
# 4. Pontuar confusáveis multi-char conhecidos do TR39 (~5 min)
npx tsx scripts/score-multichar-sdf.ts --scorer=ray
O pipeline original baseado em SSIM pontuou 26,5 milhões de comparações em 230 fontes. Permanece funcional, mas é substituído pelo RaySpace para todas as tarefas de descoberta e pontuação.
# Pontuação de pares confusáveis do TR39
npx tsx scripts/build-index.ts # Índice de renderização (~160s, 11.370 PNGs)
npx tsx scripts/score-all-pairs.ts # Pontuar todos os pares (~65s, 235K comparações)
# Descoberta de confusáveis inéditos
npx tsx scripts/build-candidates.ts # Conjunto de candidatos (~23K chars)
npx tsx scripts/build-index.ts --candidates # Renderizar candidatos (~40min, 89K PNGs)
npx tsx scripts/score-candidates.ts # Pontuar contra alvos Latinos (~15min, 2,9M comparações)
# Extrair descobertas de alta pontuação de ambos os pipelines
npx tsx scripts/extract-discoveries.ts
"Zeros" = fontes onde os contornos produzem assinaturas de raio bit-identicas (distância 0.000). Latino w/Cirílico ԝ é idêntico em todas as 19 fontes que contêm ambos os glifos.
O Georgiano Coda (U+10FF) forma um anel confusável de quatro vias com o Latino o, o Cirílico o e o Grego omicron, todos abaixo da distância 0.08.
A descoberta oy/uk Cirílico é o destaque inédito: o bigrama Latino "oy" é visualmente idêntico à letra digráfica Cirílica uk (ѹ) a uma distância de 0.000 em Helvetica e 0.0005 em Arial Unicode MS.
Três níveis operacionais recomendados:
Consulte quais pares confusáveis existem para uma fonte específica. Útil para designers de fontes a lançar um novo tipo de letra, fornecedores de navegadores a avaliar uma alteração de fonte do sistema, ou qualquer pessoa a escolher uma fonte de exibição para contextos sensíveis à segurança, como domínios IDN.
npx tsx scripts/query-font.ts --list-fonts # 218 fontes nos dados de descoberta
npx tsx scripts/query-font.ts "Arial" # Todos os pares para Arial (SSIM >= 0.7)
npx tsx scripts/query-font.ts "Arial" --threshold 0.8 # Apenas alta confiança
npx tsx scripts/query-font.ts "Arial" --compare "Georgia" # Diferenciar duas fontes pelo delta SSIM
npx tsx scripts/query-font.ts "Arial" --json # JSON para processamento downstream
A correspondência de nomes de fontes é insensível a maiúsculas/minúsculas e substring, então "arial" corresponde a Arial, Arial Black e Arial Unicode MS. O modo de comparação ordena pelas maiores diferenças de SSIM primeiro, revelando exatamente quais pares melhoram ou pioram ao trocar de fontes.
Requer os ficheiros de descoberta do pipeline de pontuação (gitignored, regenerar localmente).
| Ficheiro | Descrição |
|---|---|
data/output/render-index/ |
confusable-weights-v2.json com registos distribucionais por par: média, p50, p90, contagem de fontes, contagem de distância zero, fração zero e nível recomendado (estrito/padrão/exploratório). Distâncias RaySpace substituem SSIM. 4.174 pares no limiar padrão.confusable-weights.json para pontuação de risco visual medida via confusableDistance({ weights })Artigos em paultendo.github.io cobrindo as descobertas e a metodologia por detrás deste projeto:
Metodologia e descobertas do RaySpace:
Descobertas do pipeline SSIM:
Artigos cobrindo o espaço de problema mais amplo que motivou este projeto:
| Fonte | Alvo | Scripts | Média | Fontes | Zeros |
|---|
| w U+0077 | ԝ U+051D | Latino-Cirílico | 0.000 | 19 | 19 |
| j U+006A | ϳ U+03F3 | Latino-Grego | 0.013 | 21 | 18 |
| i U+0069 | і U+0456 | Latino-Cirílico | 0.018 | 62 | 50 |
| s U+0073 | ѕ U+0455 | Latino-Cirílico | 0.018 | 62 | 46 |
| c U+0063 | с U+0441 | Latino-Cirílico | 0.019 | 61 | 45 |
| o U+006F | о U+043E | Latino-Cirílico | 0.020 | 61 | 44 |
| j U+006A | ј U+0458 | Latino-Cirílico | 0.021 | 60 | 48 |
| x U+0078 | х U+0445 | Latino-Cirílico | 0.023 | 59 | 50 |
| p U+0070 | р U+0440 | Latino-Cirílico | 0.024 | 61 | 46 |
| e U+0065 | е U+0435 | Latino-Cirílico | 0.032 | 61 | 44 |
| a U+0061 | а U+0430 | Latino-Cirílico | 0.042 | 61 | 45 |
| Fonte | Alvo | Scripts | Média | Fontes |
|---|
| ο U+03BF | ჿ U+10FF | Grego-Georgiano | 0.057 | 2 |
| ヘ U+30D8 | へ U+3078 | Katakana-Hiragana | 0.122 | 11 |
| 丶 U+4E36 | ヽ U+30FD | Han-Katakana | 0.125 | 9 |
| 二 U+4E8C | ニ U+30CB | Han-Katakana | 0.249 | 11 |
| 口 U+53E3 | ロ U+30ED | Han-Katakana | 0.268 | 11 |
| Bigrama | Alvo | Média | Fontes | Notas |
|---|
| ll | ॥ U+0965 (danda dupla Devanágari) | 0.176 | 8 | Entre scripts |
| oy | ѹ U+0479 (uk Cirílico) | 0.322 | 16 | Novo bigrama confusável entre scripts |
| rn | m U+006D | 0.531 | 95 | 33 fontes abaixo de 0.40 |
| bl | ы U+044B (yeru Cirílico) | 0.797 | 49 | Entre scripts |
| Limiar médio | Pares únicos de caractere único | Pares únicos de múltiplos caracteres |
|---|
| < 0.50 | 138 | 13 |
| < 1.00 | 4.174 | 1.631 |
| < 1.50 | 59.700 | (ruído) |
| < 2.00 | 249.976 | 2.524.275 |
| Ficheiro | Descrição |
|---|
data/output/confusable-discoveries.json | 110 pares TR39 com SSIM alta (>= 0.7) ou pixel-idênticos |
data/output/candidate-discoveries.json | 793 pares inéditos não no TR39, SSIM média >= 0.7 |
data/output/confusable-weights.json | 1.397 arestas ponderadas para integração com namespace-guard |
data/output/cross-script-discoveries.json | 563 pares confusáveis entre scripts |
data/output/cross-script-summary.json | Resumo entre scripts por par de scripts |
data/output/multichar-discoveries.json | Descobertas confusáveis de múltiplos caracteres |
| PNGs de renderização + índice (pipeline SSIM) |
data/output/singlechar-sdf-scores.jsonl | Pontuações RaySpace de caractere único |
data/output/multichar-rayspace-scores.jsonl | Pontuações RaySpace de múltiplos caracteres |
data/output/signature-bank/ | Banco de assinaturas de raios (294.646 entradas, 7,9GB comprimidos) |