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 (
+
+ );
+}
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