From a972670b7dc2dd84b435457d76b7863198659b78 Mon Sep 17 00:00:00 2001 From: Rodrigo Bertoldo de Sousa Martins Date: Wed, 16 Sep 2026 11:53:14 -0300 Subject: [PATCH] cores nas regioes anatomicas --- data-pipeline/scripts/extract-manifest.mjs | 44 +++++++++++++++++++++- 1 file changed, 42 insertions(+), 2 deletions(-) diff --git a/data-pipeline/scripts/extract-manifest.mjs b/data-pipeline/scripts/extract-manifest.mjs index 7079c56..f51d241 100644 --- a/data-pipeline/scripts/extract-manifest.mjs +++ b/data-pipeline/scripts/extract-manifest.mjs @@ -106,6 +106,42 @@ function muscleColorVariant(baseHex, variantKey) { return hslToHex(h + hueShift, s, Math.min(0.85, Math.max(0.25, l + lightShift))); } +// Regiões de superfície (epigástrica, mesogástrica/umbilical, hipogástrica +// etc.) são o oposto do caso muscular: em vez de estruturas ANATOMICAMENTE +// relacionadas que precisam parecer "da mesma família" (uma leve variação +// em torno da cor-base do sistema já resolve), aqui são divisões +// TOPOGRÁFICAS lado a lado (as 9 regiões do abdome, por exemplo) que +// precisam ser claramente distinguíveis umas das outras à primeira vista — +// como num diagrama didático de livro-texto. +// +// Sortear o matiz por hash (`hash % 360`) parece razoável, mas com ~170 +// nomes de região caindo aleatoriamente num círculo de 360°, é comum dois +// nomes vizinhos (ex: "umbilical region" e "hypogastric region", que ficam +// EMPILHADOS no abdome) calharem de cair perto um do outro por pura +// coincidência de hash — testamos e foi exatamente o que aconteceu. +// Em vez disso, distribuímos os matizes pelo "ângulo dourado" (~137.5°) na +// ordem alfabética de TODOS os nomes de região conhecidos (as chaves de +// REGION_DESCRIPTIONS): esse incremento é a técnica clássica pra espalhar +// N categorias por um círculo de cores sem duas vizinhas na lista saírem +// vizinhas na cor. Saturação/luminosidade ficam fixas numa faixa pastel, +// pra toda região continuar parecendo parte do mesmo sistema visual. +// Esquerda/direita da MESMA região (mesmo variantKey, já sem sufixo de +// lado) sempre saem com a cor igual. +const REGION_HUE_ORDER = Object.keys(REGION_DESCRIPTIONS).sort(); +const REGION_HUE_INDEX = new Map(REGION_HUE_ORDER.map((k, i) => [k, i])); +const GOLDEN_ANGLE_DEG = 137.50776; + +function regionColorVariant(variantKey) { + const index = REGION_HUE_INDEX.has(variantKey) + ? REGION_HUE_INDEX.get(variantKey) + : REGION_HUE_ORDER.length + (stringHash(variantKey) % 360); // nomes fora da lista (raro): ainda determinístico + const hue = ((index * GOLDEN_ANGLE_DEG) % 360) / 360; + const hash = stringHash(variantKey); + const sat = 0.5 + ((hash >> 8) % 16) / 100; // 0.50–0.65 + const light = 0.6 + ((hash >> 16) % 14) / 100; // 0.60–0.73 + return hslToHex(hue, sat, light); +} + // Tom mais escuro da MESMA cor do músculo — usado nos sulcos cosméticos // (ver MUSCULAR_COSMETIC_GROOVES), pra parecer uma "dobra"/sombra na // própria superfície do músculo em vez de um elemento estranho. @@ -736,7 +772,11 @@ for (const { fbx, key } of SOURCES) { if (materialCache.has(cacheKey)) return materialCache.get(cacheKey); const sys = systemBySlug.get(systemSlug); const baseHex = sys?.colorHex ?? "#cccccc"; - const colorHex = variantKey ? muscleColorVariant(baseHex, variantKey) : baseHex; + const colorHex = !variantKey + ? baseHex + : systemSlug === "regioes" + ? regionColorVariant(variantKey) + : muscleColorVariant(baseHex, variantKey); const mat = doc .createMaterial(cacheKey) .setBaseColorFactor(hexToRgb(colorHex)) @@ -818,7 +858,7 @@ for (const { fbx, key } of SOURCES) { : key === "nervous" ? NERVE_DESCRIPTIONS[base.toLowerCase()] ?? "" : ""; - if (key === "muscular") muscleColorKey = base.toLowerCase(); + if (key === "muscular" || key === "regions") muscleColorKey = base.toLowerCase(); } const material = materialFor(systemSlug, muscleColorKey);