tegumentar3

This commit is contained in:
Rodrigo Bertoldo de Sousa Martins committed 2026-09-10 19:42:05 -03:00
1 parent 063bd629c2
commit 9f2fe75ff6
11 files changed
+221 -537

No files matched your search

+105 -268
View File
@@ -1,24 +1,28 @@
// Gera manifest-tegumentar.json: o Z-Anatomy-Sample não inclui camadas de
// pele (epiderme/derme/hipoderme) nem seus anexos (folículo piloso, glândulas
// etc.) — confirmado consultando a listagem completa de
// Assets/Models/1.0 Models no repositório (só Skeletal, Muscular, Nervous,
// CardioVascular, Visceral, Joints, LymphoidOrgans, Regions e Reference
// lines) — são estruturas microscópicas, nenhum dataset de corpo inteiro as
// modela como malha. Por isso o sistema tegumentar (só ele — os demais
// sistemas continuam vindo de malhas reais via scripts/extract-manifest.mjs,
// sem nenhuma mudança) usa um "bloco" esquemático construído com geometria
// paramétrica simples (ver scripts/geometry.mjs e scripts/build-seed-models.mjs,
// também exclusivos do tegumentar — só o script "build:tegumentar" os chama).
// Gera manifest-tegumentar.json.
//
// MODELO "DIORAMA": uma caixa sólida (as 3 camadas empilhadas, cada uma uma
// openFrontBox — ver geometry.mjs) com a face da frente removida, como uma
// caixa de vidro sem uma parede, no estilo do desenho clássico de corte de
// pele (Netter/Sobotta): de cima dá pra ver a superfície da epiderme com os
// pelos saindo; do lado dá pra ver a "banda" de cor de cada camada; e pela
// frente aberta dá pra ver os componentes (folículos, glândulas, vasos,
// corpúsculos) soltos dentro do volume da derme/hipoderme, sem nada opaco
// na frente escondendo-os. Gire o modelo com o mouse pra explorar de vários
// ângulos.
// HISTÓRICO: tentamos duas vezes um bloco 3D esquemático (geometria
// procedural — caixas/esferas/cilindros) pro sistema tegumentar, já que o
// Z-Anatomy-Sample não tem nenhum dado de pele (confirmado consultando a
// listagem completa de Assets/Models/1.0 Models: só Skeletal, Muscular,
// Nervous, CardioVascular, Visceral, Joints, LymphoidOrgans, Regions e
// Reference lines). Nenhuma das duas ficou boa o suficiente pra estudo.
//
// DECISÃO ATUAL: em vez de insistir num modelo 3D (que exigiria ou uma
// malha real licenciada — ex: Sketchfab, mas isso pede conta/token de API,
// uma dependência externa nova — ou continuar no procedural, já reprovado),
// o tegumentar agora é um DIAGRAMA 2D com pontos clicáveis (hotspots), como
// a ilustração clássica de corte de pele. A imagem usada é de domínio
// público (obra do governo dos EUA — National Cancer Institute / SEER
// Training Modules, https://training.seer.cancer.gov/melanoma/anatomy/),
// salva em frontend/public/tegumentar/skin-cross-section.jpg. Sem
// restrição de uso — não precisa nem de atribuição, mas mantemos por boa
// prática (ver frontend/src/components/SkinDiagram.tsx).
//
// As posições dos hotspots (x/y em % da imagem) ficam em
// frontend/src/data/skinHotspots.ts, não aqui — são um detalhe de
// apresentação (onde desenhar o marcador em cima da figura), enquanto este
// arquivo só gera os DADOS da estrutura (nome, descrição) que entram no
// banco, do mesmo jeito que qualquer outra estrutura do atlas.
import { writeFileSync } from "node:fs";
import { fileURLToPath } from "node:url";
import path from "node:path";
@@ -27,288 +31,121 @@ const __dirname = path.dirname(fileURLToPath(import.meta.url));
const structures = [];
// Todo o desenho abaixo é escrito em "unidades de projeto" (a escala
// original, pensada peça por peça) e só na hora de gerar a estrutura final
// o add() aplica o fator SCALE — assim dá pra aumentar/diminuir o bloco
// inteiro mudando um único número, sem recalcular à mão a posição de cada
// uma das peças.
const SCALE = 3;
function scaleShape(shape) {
const scaled = { ...shape };
for (const key of ["w", "h", "d", "r", "rt", "rb"]) {
if (scaled[key] != null) scaled[key] *= SCALE;
}
return scaled;
}
// Escala a posição em torno da âncora do bloco (CX, CY, Z_TOP) — assim o
// bloco cresce a partir do ponto onde "gruda" no antebraço, em vez de só se
// afastar dele.
function scalePosition([x, y, z]) {
return [CX + (x - CX) * SCALE, CY + (y - CY) * SCALE, Z_TOP - (Z_TOP - z) * SCALE];
}
function add(system, slug, namePt, nameEn, region, shape, position, opts = {}) {
// modelFile/meshName são NOT NULL no schema mas não fazem sentido pro
// tegumentar (não há malha 3D) — o frontend nunca tenta carregar um glb
// pra esse sistema (ver o filtro em Scene.tsx), então usamos um valor-
// sentinela só pra satisfazer o schema.
function add(slug, namePt, nameEn, description, region = []) {
structures.push({
system,
system: "tegumentar",
slug,
namePt,
nameEn,
synonyms: opts.synonyms ?? [],
description: opts.description ?? "",
regionPath: region,
modelFile: `${system}.glb`,
synonyms: [],
description,
regionPath: ["Sistema Tegumentar", "Corte Transversal da Pele", ...region],
modelFile: "n/a",
meshName: slug,
shape: scaleShape(shape),
position: scalePosition(position),
rotation: opts.rotation ?? [0, 0, 0],
color: opts.color,
});
}
const TX = ["Sistema Tegumentar", "Corte Transversal da Pele (Diorama)"];
// Centro/âncora do bloco (coordenadas do mundo, mesma escala do corpo
// Z-Anatomy — colado na face do antebraço, como antes).
const CX = 0.24;
const CY = 0.85;
const BLOCK_W = 0.14; // extensão em X (largura do bloco)
const Y_DEPTH = 0.12; // profundidade em Y (frente-trás) — a mesma pras 3 camadas
const Y_FRONT = CY - Y_DEPTH / 2; // onde fica a abertura (face removida)
// Espessura (eixo Z) de cada camada e a profundidade onde cada uma começa/
// termina — definidas uma vez aqui pra tudo (camadas E componentes) usar os
// mesmos números e não desalinhar. Proporções exageradas (derme/hipoderme
// bem mais grossas que na realidade) de propósito, pra caber e destacar os
// componentes — como em qualquer diagrama didático de pele.
const Z_TOP = 0.038; // superfície da epiderme
const D_EPI = 0.012;
const D_DERME = 0.035;
const D_HIPO = 0.053;
const Z_EPI_BOTTOM = Z_TOP - D_EPI; // limite epiderme/derme
const Z_DERME_BOTTOM = Z_EPI_BOTTOM - D_DERME; // limite derme/hipoderme
const Z_HIPO_BOTTOM = Z_DERME_BOTTOM - D_HIPO; // base do bloco
const ROT_Z = [Math.PI / 2, 0, 0]; // deixa cilindros na vertical (eixo nasce em Y, isso gira pra Z)
// ---- As 3 camadas da pele, como uma caixa de diorama (frente aberta) ----
add(
"tegumentar", "epiderme", "Epiderme", "Epidermis", [...TX],
{ type: "openFrontBox", w: BLOCK_W, h: Y_DEPTH, d: D_EPI },
[CX, CY, Z_TOP - D_EPI / 2],
{
color: "#e0a96d",
description:
"Camada mais externa e avascular da pele, formada por epitélio pavimentoso estratificado queratinizado; sua função é a principal barreira contra perda de água, atrito, micro-organismos e raios UV (com a ajuda da melanina). É a face de cima do bloco, de onde saem os pelos.",
},
"epiderme", "Epiderme", "Epidermis",
"Camada mais externa e avascular da pele, formada por epitélio pavimentoso estratificado queratinizado; principal barreira contra perda de água, atrito, micro-organismos e raios UV.",
);
add(
"tegumentar", "derme", "Derme", "Dermis", [...TX],
{ type: "openFrontBox", w: BLOCK_W, h: Y_DEPTH, d: D_DERME },
[CX, CY, Z_EPI_BOTTOM - D_DERME / 2],
{
color: "#c97b4a",
description:
"Camada de tecido conjuntivo rica em colágeno e elastina, vasos sanguíneos, terminações nervosas e os anexos cutâneos (folículos pilosos, glândulas); sustenta a epiderme e dá à pele resistência e elasticidade. Visível como a faixa do meio no lado do bloco.",
},
"derme", "Derme", "Dermis",
"Camada de tecido conjuntivo abaixo da epiderme, rica em colágeno e elastina, vasos sanguíneos, nervos e os anexos cutâneos (folículos pilosos, glândulas); dá à pele resistência e elasticidade.",
);
add(
"tegumentar", "hipoderme", "Hipoderme (Tecido Subcutâneo)", "Hypodermis (Subcutaneous Tissue)", [...TX],
{ type: "openFrontBox", w: BLOCK_W, h: Y_DEPTH, d: D_HIPO },
[CX, CY, Z_DERME_BOTTOM - D_HIPO / 2],
{
color: "#f2d4a3",
description:
"Camada mais profunda, rica em tecido adiposo; isola termicamente, absorve impactos e serve de reserva de energia — não é tecnicamente parte da pele, mas a conecta aos músculos e ossos subjacentes. É a faixa mais grossa, na base do bloco.",
},
);
// ---- 6 "colunas" de componentes, cada uma numa posição X própria, dentro
// do volume aberto do bloco — a altura (Z) de cada peça já indica em qual
// camada ela vive; um leve desvio em Y dá sensação de profundidade. ----
const COL = (i) => CX - 0.06 + i * 0.024; // 6 colunas igualmente espaçadas
// ---- Coluna 1: complexo pilossebáceo (pelo + folículo + músculo eretor + glândula sebácea) ----
const HX = COL(0);
const HY = CY - 0.02;
const HAIR_TILT = [Math.PI / 2 + 0.3, 0.2, 0];
add(
"tegumentar", "pelo", "Pelo (Haste Capilar)", "Hair Shaft", [...TX, "Complexo Pilossebáceo"],
{ type: "cylinder", rt: 0.0006, rb: 0.001, h: 0.02 }, [HX, HY, Z_TOP + 0.01],
{
color: "#4a3527",
rotation: HAIR_TILT,
description:
"Porção do pelo visível acima da superfície da pele, formada por células queratinizadas mortas; sua cor vem da melanina produzida no bulbo piloso.",
},
"hipoderme", "Hipoderme (Subcútis)", "Subcutis (Hypodermis)",
"Camada mais profunda, rica em tecido adiposo; isola termicamente, absorve impactos e serve de reserva de energia — não é tecnicamente parte da pele, mas a conecta aos músculos e ossos subjacentes.",
);
add(
"tegumentar", "foliculo-piloso", "Folículo Piloso", "Hair Follicle", [...TX, "Complexo Pilossebáceo"],
{ type: "cylinder", rt: 0.0022, rb: 0.0022, h: 0.058 }, [HX, HY, 0.009],
{
color: "#8a6a52",
rotation: HAIR_TILT,
description:
"Invaginação da epiderme para dentro da derme/hipoderme que envolve e forma a raiz do pelo; suas células-tronco também participam da regeneração da epiderme após lesões.",
},
"estrato-corneo", "Estrato Córneo", "Stratum Corneum",
"Camada mais superficial da epiderme, formada por células mortas cheias de queratina que se descamam continuamente; é a barreira física final contra o ambiente.",
["Epiderme"],
);
add(
"tegumentar", "bulbo-piloso", "Bulbo Piloso", "Hair Bulb", [...TX, "Complexo Pilossebáceo"],
{ type: "sphere", r: 0.004 }, [HX - 0.005, HY, -0.02],
{
color: "#6b4c38",
description:
"Base dilatada do folículo, na hipoderme; contém a papila dérmica (com vasos que nutrem o pelo) e a matriz germinativa, onde o pelo é produzido por divisão celular.",
},
"camada-pigmentar", "Camada Pigmentar", "Pigment Layer",
"Região da epiderme onde os melanócitos depositam melanina nas células vizinhas, dando à pele sua cor e protegendo o DNA celular da radiação UV.",
["Epiderme"],
);
add(
"tegumentar", "musculo-eretor-do-pelo", "Músculo Eretor do Pelo", "Arrector Pili Muscle", [...TX, "Complexo Pilossebáceo"],
{ type: "box", w: 0.0012, h: 0.014, d: 0.003 }, [HX + 0.005, HY, 0.017],
{
color: "#b5433a",
rotation: [1.05, 0, 0],
description:
"Pequeno músculo liso ligado obliquamente ao folículo; ao se contrair (frio, medo), eleva o pelo e comprime a glândula sebácea — é o responsável pela pele arrepiada (piloereção).",
},
"estrato-germinativo", "Estrato Germinativo (Basal + Espinhoso)", "Stratum Germinativum (Basale + Spinosum)",
"Camadas mais profundas da epiderme (estrato basal + estrato espinhoso), onde as células-tronco se dividem continuamente para repor as células que se perdem na superfície.",
["Epiderme"],
);
add(
"tegumentar", "glandula-sebacea", "Glândula Sebácea", "Sebaceous Gland", [...TX, "Complexo Pilossebáceo"],
{ type: "sphere", r: 0.005 }, [HX + 0.008, HY, 0.022],
{
color: "#f2c14e",
description:
"Glândula anexa ao folículo piloso que secreta sebo — mistura oleosa que lubrifica o pelo e a pele e ajuda a impermeabilizá-la; sua obstrução está por trás da acne.",
},
);
// ---- Fios de pelo extras, só decorativos (mesma descrição do "pelo"), pra
// a superfície do bloco não ficar com um pelo solitário — no desenho de
// referência vários pelos saem da epiderme ao mesmo tempo. ----
const EXTRA_HAIRS = [
[COL(1) + 0.01, CY - 0.03],
[COL(2) - 0.008, CY - 0.015],
[COL(4) + 0.006, CY - 0.025],
];
EXTRA_HAIRS.forEach(([x, y], i) => {
add(
"tegumentar", `pelo-extra-${i + 1}`, "Pelo (Haste Capilar)", "Hair Shaft",
[...TX, "Complexo Pilossebáceo"],
{ type: "cylinder", rt: 0.0006, rb: 0.001, h: 0.02 }, [x, y, Z_TOP + 0.01],
{
color: "#4a3527",
rotation: [Math.PI / 2 + (i - 1) * 0.15, 0.15, 0],
description:
"Porção do pelo visível acima da superfície da pele, formada por células queratinizadas mortas; sua cor vem da melanina produzida no bulbo piloso.",
},
);
});
// ---- Coluna 2: glândula sudorípara (écrina) + ducto + poro ----
const SX = COL(1);
const SY = CY;
add(
"tegumentar", "glandula-sudoripara", "Glândula Sudorípara (Écrina)", "Eccrine Sweat Gland", [...TX, "Glândula Sudorípara"],
{ type: "sphere", r: 0.006 }, [SX, SY, -0.045],
{
color: "#4f7cff",
description:
"Porção secretora enovelada, na derme profunda/hipoderme; produz o suor (água + eletrólitos), principal mecanismo de termorregulação do corpo por evaporação.",
},
"papila-dermica", "Papila Dérmica", "Dermal Papilla",
"Projeção da derme para dentro da epiderme, aumentando a área de contato entre as duas camadas e alojando as alças capilares que nutrem a epiderme (que não tem vasos próprios).",
["Derme"],
);
add(
"tegumentar", "ducto-sudoriparo", "Ducto Sudoríparo", "Sweat Duct", [...TX, "Glândula Sudorípara"],
{ type: "cylinder", rt: 0.0012, rb: 0.0012, h: 0.083 }, [SX, SY, -0.0035],
{
color: "#7ba6ff",
rotation: ROT_Z,
description:
"Canal que conduz o suor da glândula, atravessando a derme e a epiderme, até a superfície da pele.",
},
"pelo", "Pelo (Haste Capilar)", "Hair Shaft",
"Porção do pelo visível acima da superfície da pele, formada por células queratinizadas mortas; sua cor vem da melanina produzida na papila do pelo.",
["Complexo Pilossebáceo"],
);
add(
"tegumentar", "poro-sudoriparo", "Poro Sudoríparo", "Sweat Pore", [...TX, "Glândula Sudorípara"],
{ type: "sphere", r: 0.0012 }, [SX, SY, Z_TOP + 0.0005],
{
color: "#a9c6ff",
description: "Abertura do ducto sudoríparo na superfície da epiderme, por onde o suor é liberado.",
},
);
// ---- Coluna 3: plexo vascular dérmico ----
const VX = COL(2);
const VY = CY - 0.01;
add(
"tegumentar", "arteriola-dermica", "Arteríola Dérmica", "Dermal Arteriole", [...TX, "Plexo Vascular Dérmico"],
{ type: "cylinder", rt: 0.0012, rb: 0.0012, h: 0.02 }, [VX - 0.005, VY, 0.008],
{
color: "#c1121f",
rotation: ROT_Z,
description: "Ramo arterial que leva sangue oxigenado ao plexo de capilares da derme, nutrindo a pele (a epiderme em si não tem vasos).",
},
"foliculo-piloso", "Folículo Piloso", "Hair Follicle",
"Invaginação da epiderme para dentro da derme/hipoderme que envolve e forma a raiz do pelo; suas células-tronco também participam da regeneração da epiderme após lesões.",
["Complexo Pilossebáceo"],
);
add(
"tegumentar", "venula-dermica", "Vênula Dérmica", "Dermal Venule", [...TX, "Plexo Vascular Dérmico"],
{ type: "cylinder", rt: 0.0012, rb: 0.0012, h: 0.02 }, [VX + 0.005, VY, 0.008],
{
color: "#3457d5",
rotation: ROT_Z,
description: "Ramo venoso que drena o sangue do plexo capilar dérmico de volta à circulação.",
},
"papila-do-pelo", "Papila do Pelo", "Papilla of Hair",
"Estrutura na base do folículo, rica em vasos sanguíneos, que nutre a matriz germinativa responsável por produzir o pelo.",
["Complexo Pilossebáceo"],
);
add(
"tegumentar", "alca-capilar-dermica", "Alça Capilar Dérmica", "Dermal Capillary Loop", [...TX, "Plexo Vascular Dérmico"],
{ type: "cylinder", rt: 0.0006, rb: 0.0006, h: 0.012 }, [VX, VY, 0.024],
{
color: "#e0464f",
rotation: ROT_Z,
description: "Alça de capilares que sobe até as papilas dérmicas, logo abaixo da epiderme, levando nutrientes e oxigênio para a base da epiderme por difusão.",
},
"musculo-eretor-do-pelo", "Músculo Eretor do Pelo", "Arrector Pili Muscle",
"Pequeno músculo liso ligado obliquamente ao folículo; ao se contrair (frio, medo), eleva o pelo e comprime a glândula sebácea — é o responsável pela pele arrepiada (piloereção).",
["Complexo Pilossebáceo"],
);
// ---- Coluna 4: corpúsculo de Meissner (toque leve) ----
add(
"tegumentar", "corpusculo-de-meissner", "Corpúsculo de Meissner", "Meissner's Corpuscle", [...TX, "Receptores Sensoriais"],
{ type: "sphere", r: 0.003 }, [COL(3), CY - 0.015, 0.024],
{
color: "#34d399",
description:
"Receptor sensorial encapsulado logo abaixo da epiderme; detecta toque leve e vibrações de baixa frequência — muito numeroso na ponta dos dedos e nos lábios.",
},
"glandula-sebacea", "Glândula Sebácea", "Sebaceous Gland",
"Glândula anexa ao folículo piloso que secreta sebo — mistura oleosa que lubrifica o pelo e a pele e ajuda a impermeabilizá-la; sua obstrução está por trás da acne.",
["Complexo Pilossebáceo"],
);
// ---- Coluna 5: corpúsculo de Pacini (pressão profunda) ----
add(
"tegumentar", "corpusculo-de-pacini", "Corpúsculo de Pacini", "Pacinian Corpuscle", [...TX, "Receptores Sensoriais"],
{ type: "sphere", r: 0.008 }, [COL(4), CY + 0.02, -0.045],
{
color: "#22d3ee",
description:
"Grande receptor sensorial encapsulado em camadas (como uma cebola), na hipoderme; detecta pressão profunda e vibrações de alta frequência.",
},
"glandula-sudoripara", "Glândula Sudorípara (Écrina)", "Eccrine Sweat Gland",
"Porção secretora enovelada, na derme profunda/hipoderme; produz o suor (água + eletrólitos), principal mecanismo de termorregulação do corpo por evaporação.",
["Glândula Sudorípara"],
);
add(
"poro-sudoriparo", "Poro Sudoríparo", "Sweat Pore",
"Abertura do ducto da glândula sudorípara na superfície da epiderme, por onde o suor é liberado.",
["Glândula Sudorípara"],
);
add(
"fibra-nervosa", "Fibra Nervosa", "Nerve Fiber",
"Prolongamento de neurônio que percorre a derme levando informação sensorial (toque, dor, temperatura) captada na pele até o sistema nervoso central.",
["Inervação da Pele"],
);
add(
"terminacao-nervosa-tato", "Terminação Nervosa Sensorial (Tato)", "Sensory Nerve Ending for Touch",
"Receptor sensorial na junção derme-epiderme que detecta toque leve — muito numeroso na ponta dos dedos e nos lábios (tipo Meissner).",
["Inervação da Pele"],
);
add(
"corpusculo-de-pacini", "Corpúsculo de Pacini", "Pacinian Corpuscle",
"Grande receptor sensorial encapsulado em camadas (como uma cebola), na hipoderme; detecta pressão profunda e vibrações de alta frequência.",
["Inervação da Pele"],
);
add(
"vasos-sanguineos-linfaticos", "Vasos Sanguíneos e Linfáticos", "Blood and Lymph Vessels",
"Rede de vasos na derme que nutre a pele (a epiderme em si não tem vasos), participa da termorregulação e drena o excesso de líquido tecidual.",
["Vascularização da Pele"],
);
add(
"arteria", "Artéria (Ramo Cutâneo)", "Artery (Cutaneous Branch)",
"Ramo arterial que entra na derme profunda e alimenta o plexo de vasos que nutre a pele.",
["Vascularização da Pele"],
);
add(
"veia", "Veia (Ramo Cutâneo)", "Vein (Cutaneous Branch)",
"Ramo venoso que drena o sangue do plexo vascular da pele de volta à circulação.",
["Vascularização da Pele"],
);
// ---- Coluna 6: lóbulos de tecido adiposo, espalhados pela hipoderme ----
const FX = COL(5);
const FY = CY + 0.01;
const FAT_OFFSETS = [
[0, -0.02], [0.012, -0.03], [-0.01, -0.025],
[0.005, -0.04], [-0.008, -0.045], [0.01, -0.052],
];
FAT_OFFSETS.forEach(([dx, dz], i) => {
add(
"tegumentar", `adipocito-${i + 1}`, `Lóbulo de Tecido Adiposo ${i + 1}`, `Adipose Tissue Lobule ${i + 1}`,
[...TX, "Tecido Adiposo"],
{ type: "sphere", r: 0.007 }, [FX + dx, FY, dz],
{
color: "#f7e08c",
description:
"Grupo de adipócitos (células de gordura) da hipoderme; armazena energia, isola termicamente e amortece impactos mecânicos.",
},
);
});
writeFileSync(
path.resolve(__dirname, "manifest-tegumentar.json"),