diff --git a/data-pipeline/seed/build-manifest-cell.mjs b/data-pipeline/seed/build-manifest-cell.mjs index b86e02c..57075ed 100644 --- a/data-pipeline/seed/build-manifest-cell.mjs +++ b/data-pipeline/seed/build-manifest-cell.mjs @@ -16,7 +16,7 @@ import path from "node:path"; const __dirname = path.dirname(fileURLToPath(import.meta.url)); -function structure(slug, namePt, nameEn, description) { +function structure(slug, namePt, nameEn, description, regionPath = ["Citologia", "Célula (modelo ilustrativo)"]) { return { system: "citologia", slug, @@ -24,12 +24,20 @@ function structure(slug, namePt, nameEn, description) { nameEn, synonyms: [], description, - regionPath: ["Citologia", "Célula (modelo ilustrativo)"], + regionPath, modelFile: "n/a", meshName: slug, }; } +// Galeria de tipos celulares especializados — cada um ilustrativo (mesmo +// princípio da célula genérica acima: sem malha 3D real disponível pra +// isso), mostrando o que torna aquele tipo reconhecível/diferente de uma +// célula genérica. Ver frontend/src/routes/CellTypesPage.tsx. +function cellType(group, slug, namePt, nameEn, description) { + return structure(slug, namePt, nameEn, description, ["Citologia", "Tipos Celulares", group]); +} + const structures = [ structure( "celula-membrana-plasmatica", @@ -85,6 +93,132 @@ const structures = [ "Lysosomes", "Vesículas com enzimas digestivas (hidrolases ácidas) que degradam material vindo de dentro ou de fora da célula — o \"sistema de reciclagem e digestão\" celular.", ), + structure( + "celula-centriolos", + "Centríolos", + "Centrioles", + "Par de estruturas cilíndricas (feitas de microtúbulos dispostos em 9 trincas) perto do núcleo, formando o centrossomo. Se duplicam na interfase e migram para os polos opostos antes da divisão celular, organizando as fibras do fuso mitótico/meiótico — ver o módulo de Mitose e Meiose.", + ), + structure( + "celula-citoesqueleto", + "Citoesqueleto", + "Cytoskeleton", + "Rede de filamentos proteicos (microtúbulos, filamentos de actina e filamentos intermediários) que dá forma e sustentação interna à célula, organiza o posicionamento das organelas e serve de \"trilho\" para o transporte intracelular e para o movimento da própria célula.", + ), + structure( + "celula-peroxissomos", + "Peroxissomos", + "Peroxisomes", + "Vesículas menores que os lisossomos, com enzimas oxidativas que degradam ácidos graxos de cadeia longa e neutralizam peróxido de hidrogênio (um subproduto tóxico dessas reações) usando a enzima catalase.", + ), + + // ---- Neurônio ---- + cellType( + "Neurônio", + "neuronio-corpo-celular", + "Corpo Celular (Soma)", + "Cell Body (Soma)", + "Contém o núcleo e a maior parte das organelas do neurônio (retículo endoplasmático rugoso aqui é chamado de corpúsculo de Nissl); é onde a maior parte das proteínas e neurotransmissores é sintetizada.", + ), + cellType( + "Neurônio", + "neuronio-dendritos", + "Dendritos", + "Dendrites", + "Prolongamentos curtos e ramificados que recebem sinais de outros neurônios (nas sinapses) e os conduzem em direção ao corpo celular.", + ), + cellType( + "Neurônio", + "neuronio-axonio", + "Axônio", + "Axon", + "Prolongamento único, longo (pode chegar a mais de 1 metro nos maiores neurônios do corpo), que conduz o impulso nervoso do corpo celular até o terminal sináptico.", + ), + cellType( + "Neurônio", + "neuronio-bainha-mielina", + "Bainha de Mielina", + "Myelin Sheath", + "Camada isolante (produzida por células de Schwann no sistema nervoso periférico, ou oligodendrócitos no central) que envolve o axônio em segmentos, aumentando MUITO a velocidade de condução do impulso. Os intervalos sem mielina entre os segmentos são os nódulos de Ranvier — é ali que o impulso \"salta\" de um nódulo a outro (condução saltatória).", + ), + cellType( + "Neurônio", + "neuronio-terminal-sinaptico", + "Terminal Sináptico", + "Synaptic Terminal", + "Extremidade do axônio, dilatada em botões sinápticos cheios de vesículas com neurotransmissor — é aqui que o sinal elétrico vira sinal químico, liberado na fenda sináptica para o próximo neurônio (ou célula-alvo).", + ), + + // ---- Hemácia (eritrócito) ---- + cellType( + "Hemácia (Eritrócito)", + "hemacia-eritrocito", + "Hemácia (Eritrócito)", + "Red Blood Cell (Erythrocyte)", + "Célula mais numerosa do sangue, especializada em transportar oxigênio (ligado à hemoglobina). Formato de disco bicôncavo (aumenta a área de superfície para troca de gases) e, diferente de quase toda célula humana, NÃO TEM NÚCLEO nem a maioria das organelas na fase madura — são expelidos durante a formação, abrindo mais espaço pra hemoglobina.", + ), + + // ---- Célula Muscular Esquelética ---- + cellType( + "Célula Muscular Esquelética", + "musculo-fibra", + "Fibra Muscular Esquelética", + "Skeletal Muscle Fiber", + "Célula longa e cilíndrica (uma \"fibra\"), formada pela fusão de várias células precursoras durante o desenvolvimento — por isso é MULTINUCLEADA. Contém miofibrilas (feixes de filamentos de actina e miosina) que se contraem sob comando do sistema nervoso.", + ), + cellType( + "Célula Muscular Esquelética", + "musculo-nucleos-perifericos", + "Núcleos Periféricos", + "Peripheral Nuclei", + "Vários núcleos (um resquício da fusão das células precursoras) posicionados na periferia da fibra, logo abaixo da membrana — diferente da maioria das células, que tem só 1 núcleo central.", + ), + cellType( + "Célula Muscular Esquelética", + "musculo-estriacoes", + "Estriações Transversais", + "Cross Striations", + "Padrão de faixas claras e escuras alternadas, visível ao microscópio, formado pela organização regular dos filamentos de actina e miosina em sarcômeros — é o que dá o nome \"músculo estriado\" (esquelético e cardíaco; o liso não tem essas faixas).", + ), + + // ---- Espermatozoide ---- + cellType( + "Espermatozoide", + "espermatozoide-cabeca", + "Cabeça", + "Head", + "Contém o núcleo com o DNA extremamente condensado, coberto na metade anterior pelo acrossomo — uma vesícula com enzimas que digerem a camada externa do óvulo na fecundação.", + ), + cellType( + "Espermatozoide", + "espermatozoide-peca-intermediaria", + "Peça Intermediária", + "Midpiece", + "Repleta de mitocôndrias organizadas em espiral ao redor do flagelo — fornecem o ATP necessário para o batimento do flagelo durante toda a jornada até o óvulo.", + ), + cellType( + "Espermatozoide", + "espermatozoide-flagelo", + "Flagelo (Cauda)", + "Flagellum (Tail)", + "Longo prolongamento que bate em movimento ondulatório, impulsionando o espermatozoide — a única célula humana com flagelo verdadeiro.", + ), + + // ---- Leucócito (neutrófilo como representante) ---- + cellType( + "Leucócito (Neutrófilo)", + "leucocito-nucleo-lobulado", + "Núcleo Lobulado (Polimorfonuclear)", + "Lobulated Nucleus (Polymorphonuclear)", + "Núcleo dividido em 2 a 5 lóbulos conectados por filamentos finos de cromatina — a característica que dá ao neutrófilo (e a outros granulócitos) o nome \"polimorfonuclear\".", + ), + cellType( + "Leucócito (Neutrófilo)", + "leucocito-granulos", + "Grânulos Citoplasmáticos", + "Cytoplasmic Granules", + "Pequenas vesículas espalhadas pelo citoplasma, cheias de enzimas antimicrobianas — são liberadas sobre bactérias fagocitadas (ou na área da infecção) como parte da resposta imune inata.", + ), ]; writeFileSync( diff --git a/data-pipeline/seed/build-manifest-microscopy.mjs b/data-pipeline/seed/build-manifest-microscopy.mjs index a14ce20..9fcf605 100644 --- a/data-pipeline/seed/build-manifest-microscopy.mjs +++ b/data-pipeline/seed/build-manifest-microscopy.mjs @@ -40,6 +40,36 @@ // Medula espinhal de coelho. Autor: John Alan Elson. CC BY-SA 4.0. // https://commons.wikimedia.org/wiki/File:Rabbitspinalcord100x1.jpg // +// histologia/epitelio-simples-pavimentoso.jpg +// Montagem total (whole mount), padrão "pedra de calçamento" típico do +// epitélio pavimentoso visto de cima. Berkshire Community College +// Bioscience Image Library (BCCB). CC0. +// https://commons.wikimedia.org/wiki/File:Epithelial_Tissues_Simple_Squamous_Epithelium_(40823230315).jpg +// histologia/epitelio-simples-cuboidal.jpg +// Túbulos renais em corte transversal, H&E. BCCB. CC0. +// https://commons.wikimedia.org/wiki/File:Epithelial_Tissues_Simple_Cuboidal_Epithelium_(41681552432).jpg +// histologia/epitelio-pseudoestratificado.jpg +// Traqueia de mamífero em corte transversal, H&E, mostrando o epitélio +// pseudoestratificado ciliado. Autor: Magscope. CC BY-SA 4.0. +// https://commons.wikimedia.org/wiki/File:Trachea_(mammal)_histology_cross-section.png +// histologia/tecido-conjuntivo-frouxo.jpg +// Montagem total (whole mount) de tecido conjuntivo frouxo/areolar, +// mostrando a rede de fibras colágenas onduladas. BCCB. CC0. +// https://commons.wikimedia.org/wiki/File:Connective_Tissue_Loose_Aerolar_(41743649782).jpg +// histologia/cartilagem-elastica.jpg +// Corte transversal de cartilagem elástica de mamífero (coloração +// especial pra fibras elásticas). BCCB. CC0. +// https://commons.wikimedia.org/wiki/File:Connective_Tissue_Elastic_Cartilage_(41812803082).jpg +// histologia/fibrocartilagem.jpg +// Fibrocartilagem de mamífero, tricrômico (colágeno em vermelho, +// matriz cartilaginosa em azul). Autora: Magda Yurchishin +// (fotografada numa aula de biologia do ensino médio). CC BY 4.0. +// https://commons.wikimedia.org/wiki/File:Microscopic_Image_of_Mammal_Fibrocartilage_Tissue.jpg +// histologia/esfregaco-sanguineo.jpg +// Esfregaço sanguíneo periférico corado (Wright), neutrófilo ao centro +// entre hemácias e plaquetas. Autor: Ajay Kumar Chaurasiya. CC BY-SA 4.0. +// https://commons.wikimedia.org/wiki/File:WBC_(neutrophil)_at_centre,_numerous_erythrocytes_and_platelets_(dot_like_bodies)_in_Wright's_stained_peripheral_blood_smear_(PBS)_microscopy.jpg +// // As posições dos hotspots (x/y em % de cada imagem) ficam em // frontend/src/data/microscopyHotspots.ts — só apresentação, como no // tegumentar. Este arquivo só gera os DADOS da estrutura (nome, descrição). @@ -178,6 +208,86 @@ add("histologia", NERV, "corpo-neuronal-histologia", "Corpo do Neurônio (Soma)" "Região do neurônio que contém o núcleo e a maquinaria de síntese proteica; a partir dela partem os prolongamentos (dendritos e axônio) que fazem a célula se comunicar com outras.", ["Tecido Nervoso"]); +// --------------------------------------------------------------------- +// HISTOLOGIA — Epitélio simples pavimentoso +// --------------------------------------------------------------------- +const EP_PAV = "/histologia/epitelio-simples-pavimentoso.jpg"; +add("histologia", EP_PAV, "epitelio-simples-pavimentoso", "Epitélio Simples Pavimentoso", "Simple Squamous Epithelium", + "Uma única camada de células achatadas (finas, largas), com núcleo também achatado — forma ideal pra difusão rápida de gases e líquidos. Reveste alvéolos pulmonares, cápsula de Bowman no rim, e forma o mesotélio e o endotélio dos vasos sanguíneos.", + ["Tecido Epitelial"]); +add("histologia", EP_PAV, "nucleo-pavimentoso", "Núcleo da Célula Pavimentosa", "Squamous Cell Nucleus", + "Núcleo achatado, acompanhando o formato baixo e largo da própria célula — diferente do núcleo arredondado típico de células cúbicas ou colunares.", + ["Tecido Epitelial"]); + +// --------------------------------------------------------------------- +// HISTOLOGIA — Epitélio simples cuboidal (túbulos renais) +// --------------------------------------------------------------------- +const EP_CUB = "/histologia/epitelio-simples-cuboidal.jpg"; +add("histologia", EP_CUB, "epitelio-simples-cuboidal", "Epitélio Simples Cuboidal", "Simple Cuboidal Epithelium", + "Uma única camada de células com altura e largura parecidas ('cúbicas'), núcleo arredondado e central. Reveste túbulos renais, folículos da tireoide e ductos de várias glândulas — funções de absorção e secreção.", + ["Tecido Epitelial"]); +add("histologia", EP_CUB, "lumen-tubular-renal", "Luz do Túbulo Renal", "Renal Tubule Lumen", + "Espaço central e oco de cada túbulo, por onde passa o filtrado/urina em formação — delimitado ao redor por todo o anel de células cuboidais.", + ["Tecido Epitelial"]); + +// --------------------------------------------------------------------- +// HISTOLOGIA — Epitélio pseudoestratificado ciliado (traqueia) +// --------------------------------------------------------------------- +const EP_PSEUDO = "/histologia/epitelio-pseudoestratificado.jpg"; +add("histologia", EP_PSEUDO, "epitelio-pseudoestratificado", "Epitélio Pseudoestratificado Ciliado", "Pseudostratified Ciliated Epithelium", + "Parece ter várias camadas (\"pseudo\"-estratificado), mas é uma ÚNICA camada de células — só que de alturas diferentes, com nem todas alcançando a superfície, o que dá essa falsa impressão. As células que chegam à superfície têm cílios, que varrem o muco (com partículas presas) pra fora das vias respiratórias.", + ["Tecido Epitelial"]); +add("histologia", EP_PSEUDO, "lamina-propria-traqueia", "Lâmina Própria", "Lamina Propria", + "Camada de tecido conjuntivo logo abaixo do epitélio, dando sustentação e contendo vasos sanguíneos, glândulas mucosas e fibras elásticas.", + ["Tecido Epitelial"]); + +// --------------------------------------------------------------------- +// HISTOLOGIA — Tecido conjuntivo frouxo (areolar) +// --------------------------------------------------------------------- +const CONJ_FROUXO = "/histologia/tecido-conjuntivo-frouxo.jpg"; +add("histologia", CONJ_FROUXO, "tecido-conjuntivo-frouxo", "Tecido Conjuntivo Frouxo (Areolar)", "Loose (Areolar) Connective Tissue", + "Tecido conjuntivo mais comum do corpo: poucas fibras (colágenas e elásticas), dispostas de forma solta e desorganizada numa matriz com bastante substância fundamental — preenche espaços entre órgãos e sob a pele, com boa flexibilidade e vascularização.", + ["Tecido Conjuntivo"]); +add("histologia", CONJ_FROUXO, "fibroblasto-frouxo", "Fibroblasto", "Fibroblast", + "Célula mais numerosa do tecido conjuntivo, responsável por produzir e manter as fibras (colágeno, elastina) e a substância fundamental da matriz extracelular.", + ["Tecido Conjuntivo"]); + +// --------------------------------------------------------------------- +// HISTOLOGIA — Cartilagem elástica +// --------------------------------------------------------------------- +const CART_ELAST = "/histologia/cartilagem-elastica.jpg"; +add("histologia", CART_ELAST, "cartilagem-elastica", "Cartilagem Elástica", "Elastic Cartilage", + "Tipo de cartilagem com uma densa rede de fibras ELÁSTICAS na matriz (além do colágeno), o que dá flexibilidade extra, voltando à forma original depois de dobrada — encontrada na orelha externa (pavilhão auricular) e na epiglote.", + ["Tecido Cartilaginoso"]); +add("histologia", CART_ELAST, "condrocito-elastica", "Condrócito", "Chondrocyte", + "Célula madura da cartilagem, alojada numa lacuna dentro da matriz que ela mesma produziu e mantém — ao contrário do osso, a cartilagem não tem vasos sanguíneos, então os condrócitos dependem de difusão pra se nutrir.", + ["Tecido Cartilaginoso"]); + +// --------------------------------------------------------------------- +// HISTOLOGIA — Fibrocartilagem +// --------------------------------------------------------------------- +const FIBROCART = "/histologia/fibrocartilagem.jpg"; +add("histologia", FIBROCART, "fibrocartilagem", "Fibrocartilagem", "Fibrocartilage", + "Tipo de cartilagem mais resistente à tração, com grossos feixes de colágeno tipo I visíveis na matriz (ao lado dos condrócitos) — diferente da hialina e da elástica, não tem pericôndrio. Encontrada nos discos intervertebrais e na sínfise púbica, onde precisa suportar bastante carga mecânica.", + ["Tecido Cartilaginoso"]); +add("histologia", FIBROCART, "fibras-colagenas-fibrocartilagem", "Feixes de Colágeno", "Collagen Bundles", + "Feixes grossos e densos de colágeno tipo I, organizados em paralelo — dão à fibrocartilagem a resistência à tração que a hialina e a elástica não têm.", + ["Tecido Cartilaginoso"]); + +// --------------------------------------------------------------------- +// HISTOLOGIA — Esfregaço sanguíneo periférico +// --------------------------------------------------------------------- +const SANGUE = "/histologia/esfregaco-sanguineo.jpg"; +add("histologia", SANGUE, "neutrofilo-esfregaco", "Neutrófilo", "Neutrophil", + "Leucócito mais comum do sangue, com núcleo polimorfonuclear (2 a 5 lóbulos) — primeira linha de defesa celular contra infecções bacterianas, fagocitando os micro-organismos.", + ["Sangue"]); +add("histologia", SANGUE, "hemacias-esfregaco", "Hemácias", "Red Blood Cells", + "Células mais numerosas do esfregaço, sem núcleo, com uma área mais clara no centro (o reflexo do formato bicôncavo visto de cima) — transportam oxigênio ligado à hemoglobina.", + ["Sangue"]); +add("histologia", SANGUE, "plaquetas-esfregaco", "Plaquetas", "Platelets", + "Fragmentos celulares pequenos (bem menores que uma hemácia), vistos como pontinhos escuros espalhados pelo esfregaço — essenciais pra coagulação sanguínea, se agregando no local de uma lesão vascular.", + ["Sangue"]); + writeFileSync( path.resolve(__dirname, "manifest-microscopy.json"), JSON.stringify({ structures }, null, 2), diff --git a/frontend/public/histologia/cartilagem-elastica.jpg b/frontend/public/histologia/cartilagem-elastica.jpg new file mode 100644 index 0000000..899eea0 Binary files /dev/null and b/frontend/public/histologia/cartilagem-elastica.jpg differ diff --git a/frontend/public/histologia/epitelio-pseudoestratificado.jpg b/frontend/public/histologia/epitelio-pseudoestratificado.jpg new file mode 100644 index 0000000..7aec6c3 Binary files /dev/null and b/frontend/public/histologia/epitelio-pseudoestratificado.jpg differ diff --git a/frontend/public/histologia/epitelio-simples-cuboidal.jpg b/frontend/public/histologia/epitelio-simples-cuboidal.jpg new file mode 100644 index 0000000..a79cb1e Binary files /dev/null and b/frontend/public/histologia/epitelio-simples-cuboidal.jpg differ diff --git a/frontend/public/histologia/epitelio-simples-pavimentoso.jpg b/frontend/public/histologia/epitelio-simples-pavimentoso.jpg new file mode 100644 index 0000000..d69b79c Binary files /dev/null and b/frontend/public/histologia/epitelio-simples-pavimentoso.jpg differ diff --git a/frontend/public/histologia/esfregaco-sanguineo.jpg b/frontend/public/histologia/esfregaco-sanguineo.jpg new file mode 100644 index 0000000..cdf6e29 Binary files /dev/null and b/frontend/public/histologia/esfregaco-sanguineo.jpg differ diff --git a/frontend/public/histologia/fibrocartilagem.jpg b/frontend/public/histologia/fibrocartilagem.jpg new file mode 100644 index 0000000..d0ff7e9 Binary files /dev/null and b/frontend/public/histologia/fibrocartilagem.jpg differ diff --git a/frontend/public/histologia/tecido-conjuntivo-frouxo.jpg b/frontend/public/histologia/tecido-conjuntivo-frouxo.jpg new file mode 100644 index 0000000..139190e Binary files /dev/null and b/frontend/public/histologia/tecido-conjuntivo-frouxo.jpg differ diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index c387634..44be024 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -10,6 +10,7 @@ import AtlasPage from "./routes/AtlasPage.js"; const PlanesPage = lazy(() => import("./routes/PlanesPage.js")); const PhysicalExamPage = lazy(() => import("./routes/PhysicalExamPage.js")); const CellDivisionPage = lazy(() => import("./routes/CellDivisionPage.js")); +const CellTypesPage = lazy(() => import("./routes/CellTypesPage.js")); const QuizPage = lazy(() => import("./routes/QuizPage.js")); const AdminStatsPage = lazy(() => import("./routes/AdminStatsPage.js")); @@ -22,6 +23,7 @@ export default function App() { } /> } /> } /> + } /> } /> {/* Fora do Layout: painel interno, sem o menu/nav do atlas. */} diff --git a/frontend/src/components/CellDiagram3D.tsx b/frontend/src/components/CellDiagram3D.tsx index a0a9bdd..2e1faab 100644 --- a/frontend/src/components/CellDiagram3D.tsx +++ b/frontend/src/components/CellDiagram3D.tsx @@ -1,9 +1,10 @@ -import { useMemo, type ReactNode } from "react"; +import { useMemo } from "react"; import { Canvas } from "@react-three/fiber"; import { CameraControls } from "@react-three/drei"; import * as THREE from "three"; import { useAtlasStore } from "../store/useAtlasStore.js"; import type { Structure } from "../lib/api.js"; +import { materialProps, cylinderBetween, Organelle, HIGHLIGHT, BLACK } from "./cell/cellShared.js"; // Não existe (ver discussão com o usuário) uma malha 3D real e aberta de // célula com todas as organelas prontas pra estudo — chegamos a integrar @@ -14,23 +15,9 @@ import type { Structure } from "../lib/api.js"; // pedido do usuário, citologia agora é um modelo 3D ILUSTRATIVO — desenhado // à mão com primitivas do Three.js, mesmo princípio já usado no boneco // esquemático de Planos Anatômicos (ver Mannequin.tsx) — mais reconhecível -// pra quem está estudando, mesmo não vindo de dado real. -const HIGHLIGHT = new THREE.Color("#22d3ee"); -const BLACK = new THREE.Color(0x000000); - -// Função comum (NÃO hook) de propósito — é chamada dentro de .map() e de -// callbacks de render-prop abaixo, onde um hook (useMemo/useState) violaria -// as Regras de Hooks do React (número de chamadas por render precisa ser -// sempre igual e não pode depender de laços/condicionais). -function materialProps(baseColor: string, selected: boolean, opacity = 1) { - return { - color: baseColor, - transparent: opacity < 1, - opacity, - emissive: selected ? HIGHLIGHT : BLACK, - emissiveIntensity: selected ? 0.7 : 0, - }; -} +// pra quem está estudando, mesmo não vindo de dado real. `materialProps`, +// `cylinderBetween` e `Organelle` são compartilhados com +// routes/CellTypesPage.tsx — ver cell/cellShared.tsx. // Corte transversal ampliado da bicamada fosfolipídica (cabeça+cauda, as // duas camadas com as caudas hidrofóbicas viradas pra dentro, uma pra @@ -92,33 +79,6 @@ function MembraneCrossSection({ selected }: { selected: boolean }) { ); } -function Organelle({ - slug, - bySlug, - onSelect, - children, -}: { - slug: string; - bySlug: Map; - onSelect: (id: string) => void; - children: (isSelected: boolean) => ReactNode; -}) { - const selectedStructureId = useAtlasStore((s) => s.selectedStructureId); - const structure = bySlug.get(slug); - const isSelected = !!structure && structure.id === selectedStructureId; - - return ( - { - e.stopPropagation(); - if (structure) onSelect(structure.id); - }} - > - {children(isSelected)} - - ); -} - // Pontos de mitocôndrias/lisossomos espalhados pelo citoplasma — fixos // (não aleatórios a cada render) pra não "pular" toda vez que o componente // atualiza. @@ -135,6 +95,17 @@ const RIBOSOME_SPOTS: [number, number, number][] = [ [-0.5, -0.2, -0.5], [0.55, -0.35, 0.1], [-0.2, 0.6, -0.3], [0.4, 0.1, -0.55], [-0.55, 0.3, 0.25], [0.1, -0.6, -0.25], ]; +const PEROXISSOMO_SPOTS: [number, number, number][] = [ + [0.45, 0.45, -0.3], [-0.2, -0.4, 0.5], [0.15, -0.55, -0.35], [-0.55, 0.1, 0.4], +]; +// "Raios" do citoesqueleto saindo de perto do núcleo até perto da +// membrana, em direções fixas (não aleatórias) — só pra dar a ideia de +// rede de filamentos preenchendo o citoplasma, sem tentar reproduzir +// microtúbulo/actina/filamento intermediário individualmente. +const CYTOSKELETON_RAYS: [number, number, number][] = [ + [0.7, 0.5, -0.1], [-0.65, 0.4, 0.35], [0.5, -0.55, 0.4], [-0.5, -0.5, -0.45], + [0.75, -0.1, -0.5], [-0.75, 0.05, 0.2], [0.15, 0.7, 0.45], [-0.2, -0.75, 0.1], +]; export function CellDiagram3D({ bySlug: bySlugAll }: { bySlug: Map }) { const toggleSystem = useAtlasStore((s) => s.toggleSystem); @@ -272,6 +243,64 @@ export function CellDiagram3D({ bySlug: bySlugAll }: { bySlug: Map + {/* Centríolos — par perpendicular perto do núcleo (centrossomo). + Mesma posição conceitual de onde os centrossomos aparecem + no módulo de Mitose e Meiose: organizam o fuso quando a + célula se divide. */} + + {(sel) => ( + + + + + + + + + + + )} + + + {/* Peroxissomos — vesículas pequenas, cor própria (não + confundir com os lisossomos amarelos) */} + + {(sel) => ( + <> + {PEROXISSOMO_SPOTS.map(([x, y, z], i) => ( + + + + + ))} + + )} + + + {/* Citoesqueleto — rede de filamentos finos saindo de perto do + núcleo até perto da membrana, preenchendo o citoplasma */} + + {(sel) => { + const center = new THREE.Vector3(0.1, 0, 0); + return ( + <> + {CYTOSKELETON_RAYS.map((target, i) => { + const { position, quaternion, length } = cylinderBetween( + center, + new THREE.Vector3(...target), + ); + return ( + + + + + ); + })} + + ); + }} + + {/* Membrana plasmática — um RECORTE da casca (não a esfera inteira) num canto de trás, tipo uma "janela" mostrando onde ela fica. Uma esfera fechada ao redor de tudo (como diff --git a/frontend/src/components/Layout.tsx b/frontend/src/components/Layout.tsx index a7d8d44..eae05c4 100644 --- a/frontend/src/components/Layout.tsx +++ b/frontend/src/components/Layout.tsx @@ -35,6 +35,9 @@ export function Layout() { Mitose e Meiose + + Tipos Celulares + Quiz diff --git a/frontend/src/components/cell/CellTypeModels.tsx b/frontend/src/components/cell/CellTypeModels.tsx new file mode 100644 index 0000000..40d9eed --- /dev/null +++ b/frontend/src/components/cell/CellTypeModels.tsx @@ -0,0 +1,368 @@ +import * as THREE from "three"; +import type { Structure } from "../../lib/api.js"; +import { materialProps, cylinderBetween, Organelle } from "./cellShared.js"; + +// Cada função abaixo desenha UM tipo celular — todas ilustrativas (sem +// malha 3D real disponível, mesmo princípio de CellDiagram3D.tsx), +// pensadas pra destacar o que torna aquele tipo reconhecível/diferente de +// uma célula genérica. `bySlug`/`onSelect` seguem o mesmo contrato de +// Organelle usado na célula genérica — clicar numa parte abre a descrição +// real (ver build-manifest-cell.mjs). + +interface CellTypeProps { + bySlug: Map; + onSelect: (id: string) => void; +} + +// --------------------------------------------------------------------- +// Neurônio +// --------------------------------------------------------------------- +const DENDRITE_DIRECTIONS: [number, number, number][] = [ + [-0.55, 0.35, 0.1], [-0.5, -0.1, 0.4], [-0.35, 0.5, -0.3], + [-0.6, -0.3, -0.2], [-0.2, 0.55, 0.35], [-0.45, 0.05, -0.5], +]; +const AXON_DIRECTION = new THREE.Vector3(1.4, -0.15, 0.1); +const MYELIN_SEGMENTS = [0.25, 0.42, 0.59, 0.76, 0.93]; // posições ao longo do axônio (fração 0-1), com lacunas = nódulos de Ranvier + +export function NeuronModel({ bySlug, onSelect }: CellTypeProps) { + const soma = new THREE.Vector3(0, 0, 0); + const axonEnd = soma.clone().add(AXON_DIRECTION); + + return ( + <> + + {(sel) => ( + <> + + + + + + + + + + )} + + + + {(sel) => ( + <> + {DENDRITE_DIRECTIONS.map((dir, i) => { + const to = new THREE.Vector3(...dir); + const { position, quaternion, length } = cylinderBetween(soma, to); + return ( + + + + + + {/* sub-ramo curto, só pra sugerir ramificação */} + {(() => { + const mid = soma.clone().lerp(to, 0.6); + const branchTo = mid.clone().add(new THREE.Vector3(dir[2] * 0.2, dir[0] * 0.15, -dir[1] * 0.2)); + const branch = cylinderBetween(mid, branchTo); + return ( + + + + + ); + })()} + + ); + })} + + )} + + + + {(sel) => { + const { position, quaternion, length } = cylinderBetween(soma, axonEnd); + return ( + + + + + ); + }} + + + + {(sel) => ( + <> + {MYELIN_SEGMENTS.map((t, i) => { + const center = soma.clone().lerp(axonEnd, t); + return ( + + + + + ); + })} + + )} + + + + {(sel) => ( + <> + {[ + [0.08, 0.06, 0], + [0.1, -0.05, 0.06], + [0.07, -0.02, -0.07], + ].map(([dx, dy, dz], i) => ( + + + + + ))} + + )} + + + ); +} + +// --------------------------------------------------------------------- +// Hemácia (eritrócito) — disco bicôncavo de verdade, via perfil revolvido +// (mesma técnica usada no torso do Mannequin.tsx: LatheGeometry) +// --------------------------------------------------------------------- +function useBiconcaveProfile() { + // A primeira versão traçava só UMA superfície (centro->borda), o que o + // Lathe revolve numa tigela/pires de um lado só, não um disco de + // verdade — parecia uma lasca fina vista de qualquer ângulo mais de + // lado. Um disco de verdade precisa de um contorno FECHADO no corte + // transversal: sobe pela face de CIMA (centro->borda) e desce pela face + // de BAIXO (borda->centro), com a borda fina unindo as duas — só assim + // o Lathe fecha um sólido com as duas faces côncavas. + const halfThicknessByRadius: [radius: number, halfThickness: number][] = [ + [0.0, 0.015], // centro: bem fino (a concavidade de verdade) + [0.1, 0.045], + [0.24, 0.1], // anel bem mais grosso que o centro + [0.35, 0.065], + [0.4, 0.0], // borda fina, as duas faces se encontram aqui + ]; + const top = halfThicknessByRadius.map(([r, h]) => new THREE.Vector2(r, h)); + const bottom = [...halfThicknessByRadius] + .reverse() + .slice(1) // não repete o ponto da borda (já é o último do "top") + .map(([r, h]) => new THREE.Vector2(r, -h)); + const geo = new THREE.LatheGeometry([...top, ...bottom], 40); + geo.computeVertexNormals(); + return geo; +} + +export function ErythrocyteModel({ bySlug, onSelect }: CellTypeProps) { + const geometry = useBiconcaveProfile(); + return ( + + {(sel) => ( + + + + )} + + ); +} + +// --------------------------------------------------------------------- +// Célula Muscular Esquelética — fibra longa, núcleos periféricos, +// estriações transversais +// --------------------------------------------------------------------- +const FIBER_LENGTH = 1.7; +const FIBER_RADIUS = 0.22; +const PERIPHERAL_NUCLEI: [number, number][] = [ + [-0.55, 0.9], [-0.1, -0.95], [0.4, 0.88], [0.75, -0.85], [-0.8, -0.3], +]; +const STRIATION_COUNT = 14; + +export function MuscleFiberModel({ bySlug, onSelect }: CellTypeProps) { + return ( + <> + + {(sel) => ( + + + + + )} + + + + {(sel) => ( + <> + {Array.from({ length: STRIATION_COUNT }, (_, i) => { + const x = -FIBER_LENGTH / 2 + 0.15 + (i / (STRIATION_COUNT - 1)) * (FIBER_LENGTH - 0.3); + const dark = i % 2 === 0; + return ( + + + + + ); + })} + + )} + + + + {(sel) => ( + <> + {PERIPHERAL_NUCLEI.map(([x, angleFrac], i) => { + const angle = angleFrac * Math.PI; + const y = Math.cos(angle) * (FIBER_RADIUS - 0.03); + const z = Math.sin(angle) * (FIBER_RADIUS - 0.03); + return ( + + + + + ); + })} + + )} + + + ); +} + +// --------------------------------------------------------------------- +// Espermatozoide — cabeça (+ acrossomo), peça intermediária (+ +// mitocôndrias em espiral), flagelo +// --------------------------------------------------------------------- +const HEAD_CENTER = new THREE.Vector3(-0.6, 0, 0); +const HEAD_RADIUS = 0.22; +// A peça intermediária começa na BORDA da cabeça, não no centro dela — +// começar no centro fazia a peça intermediária e as mitocôndrias nascerem +// "dentro" da cabeça, virando uma bola confusa de formas sobrepostas. +const MIDPIECE_START = new THREE.Vector3(HEAD_CENTER.x + HEAD_RADIUS, 0, 0); +const MIDPIECE_END = new THREE.Vector3(0.05, 0, 0); +const TAIL_END = new THREE.Vector3(1.3, 0.05, 0); + +export function SpermModel({ bySlug, onSelect }: CellTypeProps) { + return ( + <> + + {(sel) => ( + <> + + + + + {/* acrossomo — capuz na metade anterior (frente) da cabeça */} + + + + + + )} + + + + {(sel) => { + const { position, quaternion, length } = cylinderBetween(MIDPIECE_START, MIDPIECE_END); + return ( + <> + + + + + {/* mitocôndrias em espiral ao redor */} + {Array.from({ length: 8 }, (_, i) => { + const t = i / 7; + const x = THREE.MathUtils.lerp(MIDPIECE_START.x, MIDPIECE_END.x, t); + const angle = t * Math.PI * 4; + const y = Math.cos(angle) * 0.055; + const z = Math.sin(angle) * 0.055; + return ( + + + + + ); + })} + + ); + }} + + + + {(sel) => { + const { position, quaternion, length } = cylinderBetween(MIDPIECE_END, TAIL_END); + return ( + + + + + ); + }} + + + ); +} + +// --------------------------------------------------------------------- +// Leucócito (neutrófilo) — núcleo polimorfonuclear + grânulos +// --------------------------------------------------------------------- +const NUCLEUS_LOBES: [number, number, number][] = [ + [-0.12, 0.1, 0], [0.08, 0.14, 0.05], [0.14, -0.08, -0.06], [-0.05, -0.14, 0.08], +]; +const GRANULE_SPOTS: [number, number, number][] = [ + [0.3, 0.25, 0.1], [-0.3, 0.2, -0.15], [0.25, -0.3, 0.2], [-0.25, -0.25, -0.1], + [0.05, 0.35, -0.25], [-0.1, -0.35, 0.2], [0.35, 0.0, -0.1], [-0.35, 0.05, 0.15], +]; + +export function LeukocyteModel({ bySlug, onSelect }: CellTypeProps) { + return ( + <> + {/* citoplasma — só contexto visual, sem clique (mesma razão da + membrana da célula genérica: é a casca que envolve tudo) */} + null}> + + + + + + {(sel) => ( + <> + {NUCLEUS_LOBES.map(([x, y, z], i) => ( + + + + + ))} + {/* filamentos finos de cromatina conectando os lóbulos */} + {NUCLEUS_LOBES.slice(1).map(([x, y, z], i) => { + const from = new THREE.Vector3(...NUCLEUS_LOBES[i]); + const to = new THREE.Vector3(x, y, z); + const { position, quaternion, length } = cylinderBetween(from, to); + return ( + + + + + ); + })} + + )} + + + + {(sel) => ( + <> + {GRANULE_SPOTS.map(([x, y, z], i) => ( + + + + + ))} + + )} + + + ); +} diff --git a/frontend/src/components/cell/cellShared.tsx b/frontend/src/components/cell/cellShared.tsx new file mode 100644 index 0000000..462a813 --- /dev/null +++ b/frontend/src/components/cell/cellShared.tsx @@ -0,0 +1,67 @@ +import type { ReactNode } from "react"; +import * as THREE from "three"; +import { useAtlasStore } from "../../store/useAtlasStore.js"; +import type { Structure } from "../../lib/api.js"; + +// Utilitários compartilhados entre CellDiagram3D.tsx (a célula genérica) +// e CellTypesPage.tsx (galeria de tipos celulares especializados) — os +// dois são diagramas 3D ILUSTRATIVOS (sem malha real disponível pra isso), +// desenhados à mão com primitivas do Three.js, mesmo princípio do boneco +// esquemático de Planos Anatômicos (ver Mannequin.tsx). +export const HIGHLIGHT = new THREE.Color("#22d3ee"); +export const BLACK = new THREE.Color(0x000000); + +// Função comum (NÃO hook) de propósito — é chamada dentro de .map() e de +// callbacks de render-prop, onde um hook (useMemo/useState) violaria as +// Regras de Hooks do React (número de chamadas por render precisa ser +// sempre igual e não pode depender de laços/condicionais). +export function materialProps(baseColor: string, selected: boolean, opacity = 1) { + return { + color: baseColor, + transparent: opacity < 1, + opacity, + emissive: selected ? HIGHLIGHT : BLACK, + emissiveIntensity: selected ? 0.7 : 0, + }; +} + +// Posiciona/orienta um cilindro pra ir de verdade do ponto A ao ponto B +// (não só "perto" com um ângulo aproximado) — usado em qualquer prolongamento +// fino (filamento do citoesqueleto, axônio, flagelo...). +export function cylinderBetween(from: THREE.Vector3, to: THREE.Vector3) { + const direction = new THREE.Vector3().subVectors(to, from); + const length = direction.length(); + const position = new THREE.Vector3().addVectors(from, to).multiplyScalar(0.5); + const quaternion = new THREE.Quaternion().setFromUnitVectors( + new THREE.Vector3(0, 1, 0), + direction.clone().normalize(), + ); + return { position, quaternion, length }; +} + +export function Organelle({ + slug, + bySlug, + onSelect, + children, +}: { + slug: string; + bySlug: Map; + onSelect: (id: string) => void; + children: (isSelected: boolean) => ReactNode; +}) { + const selectedStructureId = useAtlasStore((s) => s.selectedStructureId); + const structure = bySlug.get(slug); + const isSelected = !!structure && structure.id === selectedStructureId; + + return ( + { + e.stopPropagation(); + if (structure) onSelect(structure.id); + }} + > + {children(isSelected)} + + ); +} diff --git a/frontend/src/data/microscopyCredits.ts b/frontend/src/data/microscopyCredits.ts index 0319e4e..a9e46b5 100644 --- a/frontend/src/data/microscopyCredits.ts +++ b/frontend/src/data/microscopyCredits.ts @@ -18,4 +18,18 @@ export const MICROSCOPY_CREDITS: Record = { "OpenStax College, CC BY 4.0 (Wikimedia Commons).", "/histologia/tecido-nervoso.jpg": "Medula espinhal de coelho. John Alan Elson, CC BY-SA 4.0 (Wikimedia Commons).", + "/histologia/epitelio-simples-pavimentoso.jpg": + "Berkshire Community College Bioscience Image Library (BCCB), CC0 (Wikimedia Commons).", + "/histologia/epitelio-simples-cuboidal.jpg": + "Túbulos renais. BCCB, CC0 (Wikimedia Commons).", + "/histologia/epitelio-pseudoestratificado.jpg": + "Traqueia de mamífero. Magscope, CC BY-SA 4.0 (Wikimedia Commons).", + "/histologia/tecido-conjuntivo-frouxo.jpg": + "BCCB, CC0 (Wikimedia Commons).", + "/histologia/cartilagem-elastica.jpg": + "BCCB, CC0 (Wikimedia Commons).", + "/histologia/fibrocartilagem.jpg": + "Magda Yurchishin, CC BY 4.0 (Wikimedia Commons).", + "/histologia/esfregaco-sanguineo.jpg": + "Ajay Kumar Chaurasiya, CC BY-SA 4.0 (Wikimedia Commons).", }; diff --git a/frontend/src/data/microscopyHotspots.ts b/frontend/src/data/microscopyHotspots.ts index 05eb65b..4902e11 100644 --- a/frontend/src/data/microscopyHotspots.ts +++ b/frontend/src/data/microscopyHotspots.ts @@ -44,4 +44,33 @@ export const MICROSCOPY_HOTSPOTS: Record = { "substancia-branca-histologia": { x: 20, y: 25 }, "substancia-cinzenta-histologia": { x: 65, y: 35 }, "corpo-neuronal-histologia": { x: 66, y: 30 }, + + // Histologia — /histologia/epitelio-simples-pavimentoso.jpg + "epitelio-simples-pavimentoso": { x: 50, y: 50 }, + "nucleo-pavimentoso": { x: 22, y: 22 }, + + // Histologia — /histologia/epitelio-simples-cuboidal.jpg + "epitelio-simples-cuboidal": { x: 30, y: 65 }, + "lumen-tubular-renal": { x: 48, y: 22 }, + + // Histologia — /histologia/epitelio-pseudoestratificado.jpg + "epitelio-pseudoestratificado": { x: 15, y: 12 }, + "lamina-propria-traqueia": { x: 40, y: 60 }, + + // Histologia — /histologia/tecido-conjuntivo-frouxo.jpg + "tecido-conjuntivo-frouxo": { x: 40, y: 55 }, + "fibroblasto-frouxo": { x: 58, y: 43 }, + + // Histologia — /histologia/cartilagem-elastica.jpg + "cartilagem-elastica": { x: 50, y: 45 }, + "condrocito-elastica": { x: 30, y: 43 }, + + // Histologia — /histologia/fibrocartilagem.jpg + "fibrocartilagem": { x: 35, y: 55 }, + "fibras-colagenas-fibrocartilagem": { x: 70, y: 15 }, + + // Histologia — /histologia/esfregaco-sanguineo.jpg + "neutrofilo-esfregaco": { x: 48, y: 42 }, + "hemacias-esfregaco": { x: 20, y: 20 }, + "plaquetas-esfregaco": { x: 10, y: 8 }, }; diff --git a/frontend/src/routes/CellTypesPage.tsx b/frontend/src/routes/CellTypesPage.tsx new file mode 100644 index 0000000..38de3e4 --- /dev/null +++ b/frontend/src/routes/CellTypesPage.tsx @@ -0,0 +1,189 @@ +import { useMemo, useState } from "react"; +import { Canvas } from "@react-three/fiber"; +import { CameraControls } from "@react-three/drei"; +import { useSystemStructures } from "../hooks/useSystemStructures.js"; +import { useAtlasStore } from "../store/useAtlasStore.js"; +import { + NeuronModel, + ErythrocyteModel, + MuscleFiberModel, + SpermModel, + LeukocyteModel, +} from "../components/cell/CellTypeModels.js"; + +// Galeria de tipos celulares especializados — complementa a célula +// genérica (ver CellDiagram3D.tsx, aberta a partir do Atlas) com modelos +// 3D ilustrativos de células que têm uma forma/organela bem diferente do +// "padrão", pensados pra reconhecer cada tipo pelas suas características. +// Mesmo princípio de todo diagrama ilustrativo deste app: sem malha 3D +// real disponível pra isso, desenhado à mão com primitivas do Three.js. + +type CellTypeKey = "neuronio" | "hemacia" | "musculo" | "espermatozoide" | "leucocito"; + +interface CellTypeDef { + key: CellTypeKey; + label: string; + hint: string; + camera: [number, number, number]; + Model: typeof NeuronModel; +} + +const CELL_TYPES: CellTypeDef[] = [ + { + key: "neuronio", + label: "Neurônio", + hint: "Transmite impulsos nervosos — repare nos prolongamentos (dendritos/axônio) e na bainha de mielina.", + camera: [1.2, 0.8, 1.6], + Model: NeuronModel, + }, + { + key: "hemacia", + label: "Hemácia (Eritrócito)", + hint: "Transporta oxigênio — a única célula sem núcleo, com o formato de disco bicôncavo característico.", + camera: [0.35, 0.55, 0.95], + Model: ErythrocyteModel, + }, + { + key: "musculo", + label: "Célula Muscular Esquelética", + hint: "Fibra longa, multinucleada, com estriações — repare nos núcleos na periferia, não no centro.", + camera: [1.6, 0.6, 1.6], + Model: MuscleFiberModel, + }, + { + key: "espermatozoide", + label: "Espermatozoide", + hint: "A única célula humana com flagelo verdadeiro — cabeça, peça intermediária e cauda.", + camera: [0.3, 0.6, 1.3], + Model: SpermModel, + }, + { + key: "leucocito", + label: "Leucócito (Neutrófilo)", + hint: "Núcleo polimorfonuclear (vários lóbulos) e grânulos citoplasmáticos com enzimas antimicrobianas.", + camera: [0.9, 0.7, 0.9], + Model: LeukocyteModel, + }, +]; + +const VISIBLE_SYSTEMS = new Set(["citologia"]); + +export default function CellTypesPage() { + const [typeKey, setTypeKey] = useState("neuronio"); + const [leftOpen, setLeftOpen] = useState(false); + const [rightOpen, setRightOpen] = useState(false); + const selectedStructureId = useAtlasStore((s) => s.selectedStructureId); + const selectStructure = useAtlasStore((s) => s.selectStructure); + + const { bySlug: bySlugAll } = useSystemStructures(VISIBLE_SYSTEMS); + const bySlug = useMemo( + () => new Map([...bySlugAll.values()].filter((s) => s.regionPath[1] === "Tipos Celulares").map((s) => [s.slug, s])), + [bySlugAll], + ); + + const current = CELL_TYPES.find((c) => c.key === typeKey)!; + const selected = selectedStructureId + ? [...bySlug.values()].find((s) => s.id === selectedStructureId) + : null; + + function changeType(key: CellTypeKey) { + setTypeKey(key); + selectStructure(null); + } + + return ( +
+ + + {(leftOpen || rightOpen) && ( +
{ + setLeftOpen(false); + setRightOpen(false); + }} + /> + )} + +
+ + + + + + + + + + + + +
+ {current.hint} +
+
+ + +
+ ); +} diff --git a/frontend/tsconfig.tsbuildinfo b/frontend/tsconfig.tsbuildinfo index 04039d7..49ed99e 100644 --- a/frontend/tsconfig.tsbuildinfo +++ b/frontend/tsconfig.tsbuildinfo @@ -1 +1 @@ -{"root":["./src/app.tsx","./src/main.tsx","./src/vite-env.d.ts","./src/components/celldiagram3d.tsx","./src/components/clippingcontrols.tsx","./src/components/cookieconsent.tsx","./src/components/feedbackwidget.tsx","./src/components/layertoggle.tsx","./src/components/layout.tsx","./src/components/microscopydiagram.tsx","./src/components/onlinecounter.tsx","./src/components/quickregionnav.tsx","./src/components/searchnav.tsx","./src/components/skindiagram3d.tsx","./src/components/structureinfopanel.tsx","./src/components/celldivision/celldivisionscene.tsx","./src/components/viewer/exammarkers.tsx","./src/components/viewer/intercostallabels.tsx","./src/components/viewer/mannequin.tsx","./src/components/viewer/scene.tsx","./src/components/viewer/systemmodel.tsx","./src/data/celldivisioncomponents.ts","./src/data/celldivisionstages.ts","./src/data/geneticsyndromes.ts","./src/data/microscopycredits.ts","./src/data/microscopyhotspots.ts","./src/data/musclereferenceimages.ts","./src/data/physicalexam.ts","./src/hooks/usestructures.ts","./src/hooks/usesystemstructures.ts","./src/lib/analytics.ts","./src/lib/api.ts","./src/lib/bodyregionbox.ts","./src/routes/adminstatspage.tsx","./src/routes/atlaspage.tsx","./src/routes/celldivisionpage.tsx","./src/routes/physicalexampage.tsx","./src/routes/planespage.tsx","./src/routes/quizpage.tsx","./src/store/useatlasstore.ts"],"version":"5.9.3"} \ No newline at end of file +{"root":["./src/app.tsx","./src/main.tsx","./src/vite-env.d.ts","./src/components/celldiagram3d.tsx","./src/components/clippingcontrols.tsx","./src/components/cookieconsent.tsx","./src/components/feedbackwidget.tsx","./src/components/layertoggle.tsx","./src/components/layout.tsx","./src/components/microscopydiagram.tsx","./src/components/onlinecounter.tsx","./src/components/quickregionnav.tsx","./src/components/searchnav.tsx","./src/components/skindiagram3d.tsx","./src/components/structureinfopanel.tsx","./src/components/cell/celltypemodels.tsx","./src/components/cell/cellshared.tsx","./src/components/celldivision/celldivisionscene.tsx","./src/components/viewer/exammarkers.tsx","./src/components/viewer/intercostallabels.tsx","./src/components/viewer/mannequin.tsx","./src/components/viewer/scene.tsx","./src/components/viewer/systemmodel.tsx","./src/data/celldivisioncomponents.ts","./src/data/celldivisionstages.ts","./src/data/geneticsyndromes.ts","./src/data/microscopycredits.ts","./src/data/microscopyhotspots.ts","./src/data/musclereferenceimages.ts","./src/data/physicalexam.ts","./src/hooks/usestructures.ts","./src/hooks/usesystemstructures.ts","./src/lib/analytics.ts","./src/lib/api.ts","./src/lib/bodyregionbox.ts","./src/routes/adminstatspage.tsx","./src/routes/atlaspage.tsx","./src/routes/celldivisionpage.tsx","./src/routes/celltypespage.tsx","./src/routes/physicalexampage.tsx","./src/routes/planespage.tsx","./src/routes/quizpage.tsx","./src/store/useatlasstore.ts"],"version":"5.9.3"} \ No newline at end of file