// 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). // // 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. import { writeFileSync } from "node:fs"; import { fileURLToPath } from "node:url"; import path from "node:path"; 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 = {}) { structures.push({ system, slug, namePt, nameEn, synonyms: opts.synonyms ?? [], description: opts.description ?? "", regionPath: region, modelFile: `${system}.glb`, 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.", }, ); 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.", }, ); 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.", }, ); 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.", }, ); 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.", }, ); 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).", }, ); 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.", }, ); 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.", }, ); 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).", }, ); 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.", }, ); 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.", }, ); // ---- 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.", }, ); // ---- 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.", }, ); // ---- 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"), JSON.stringify({ structures }, null, 2), ); console.log(`manifest-tegumentar.json gerado com ${structures.length} estruturas.`);