2026-09-08 12:41:59 -03:00
2026-09-10 19:42:05 -03:00
2026-09-08 13:14:44 -03:00
2026-09-11 09:38:43 -03:00
2026-09-08 13:25:12 -03:00
2026-09-07 20:46:08 -03:00
2026-09-07 20:46:08 -03:00
2026-09-08 12:41:59 -03:00
2026-09-10 19:42:05 -03:00

Atlas 3D de Anatomia

Plataforma web dockerizada para estudo de anatomia com um visualizador 3D interativo, camadas por sistema, dissecção virtual (plano de corte), busca/navegação por região e um modo quiz com repetição espaçada (SM-2).

Conteúdo 3D: modelos reais do projeto Z-Anatomy

Os modelos 3D vêm do Z-Anatomy-Sample (github.com/LluisV/Z-Anatomy-Sample), um reempacotamento aberto do dataset BodyParts3D/FMA (Database Center for Life Science, Univ. de Tóquio) em malhas segmentadas e nomeadas por estrutura, organizadas por sistema. Ao contrário do site oficial do BodyParts3D (que só permite download manual, estrutura por estrutura, por uma aplicação legada), o Z-Anatomy-Sample publica os arquivos FBX diretamente no GitHub, permitindo baixar e converter tudo via script.

Licença: CC BY-SA 4.0. Isso significa: (1) é obrigatório dar crédito ao projeto original — já incluído no rodapé da aplicação e aqui; (2) qualquer redistribuição das malhas (mesmo modificadas, como as recolorizações que fazemos aqui) deve continuar sob a mesma licença CC BY-SA 4.0. Se for redistribuir este projeto publicamente, mantenha essa nota.

O pipeline (data-pipeline/) baixa os .fbx reais, converte para .glb via assimp, recolore cada malha por sistema (para um visual consistente, já que o FBX não carrega a paleta de cores usada no app Unity original do Z-Anatomy) e gera o manifesto do banco automaticamente a partir dos milhares de nomes de estrutura reais contidos nos arquivos — sem geometria placeholder, exceto pelo sistema tegumentar (veja abaixo).

Tradução dos nomes: como isso é uma ferramenta de estudo para prova, uma tradução errada de termo médico é pior do que nenhuma tradução — por isso só traduzimos para PT-BR quando o nome bate exatamente com um dicionário curado (data-pipeline/scripts/translate-pt.mjs, ~120 termos comuns). Estruturas fora desse dicionário aparecem com o nome original em inglês/latim, que também é nomenclatura anatômica padrão usada no ensino de anatomia.

O que não veio do Z-Anatomy-Sample: a amostra pública não inclui camadas de pele (confirmado consultando a listagem completa do repositório). Duas tentativas de bloco 3D esquemático (geometria procedural) pro sistema tegumentar não ficaram boas o bastante pra estudo, então ele agora é um diagrama 2D clássico com pontos clicáveis (imagem de domínio público, NCI/SEER Training Modules) — ver data-pipeline/seed/build-manifest.mjs (dados das estruturas), frontend/src/data/skinHotspots.ts (posição dos marcadores sobre a imagem) e frontend/src/components/SkinDiagram.tsx.

Arquitetura

Este compose foi adaptado para rodar como um stack separado dentro da infraestrutura existente do host cloud-lua-net, que já tem uma rede Docker externa dockernet e um container nginx central (com HTTP/3) que lê vhosts manuais em docker/nginx/sites/*.conf, mais um par nginx-gen + acme-companion que emite certificados Let's Encrypt via LETSENCRYPT_HOST.

container "nginx" (proxy principal do host, HTTP/3, já existente)
        │  vhost manual: docker/nginx/sites/30-atlas.conf
        │  proxy_pass → IP fixo do container anatomia-web em dockernet
        ▼
container "anatomia-web" (nginx interno deste projeto)
        ├─ serve o build estático do frontend (SPA)
        ├─ /api/*    → proxy → container "anatomia-api"
        └─ /models/* → proxy → container "anatomia-api"
container "anatomia-api" (Fastify + Prisma) ──▶ container "anatomia-db" (Postgres)

Não é publicada nenhuma porta no host — anatomia-web só é alcançável dentro da rede dockernet, no mesmo padrão já usado para outros apps desse compose (ex: frontend/backend do ticketz, nextcloud). Isso significa que este projeto roda como um docker compose próprio, independente do compose gigante do host — ele só precisa se conectar à mesma rede externa dockernet, o que já é suportado nativamente pelo Docker (containers de projetos Compose diferentes na mesma rede se enxergam normalmente).

Como rodar

# no host cloud-lua-net, dentro da pasta deste projeto (ex: /home/docker/anatomia)
cp .env.example .env
# Confirme que o IP escolhido está livre antes de subir:
docker network inspect dockernet | grep -A2 IPv4Address
# ajuste ANATOMIA_WEB_IP no .env se 10.15.0.93 já estiver em uso

docker compose up -d --build anatomia-db anatomia-api anatomia-web
docker compose build anatomia-pipeline
docker compose run --rm anatomia-pipeline   # baixa+converte os modelos reais e popula o banco

O anatomia-pipeline baixa ~230MB de arquivos FBX do GitHub e os converte com assimp — a primeira execução pode levar alguns minutos. Acompanhe com docker compose run --rm anatomia-pipeline mesmo (ele já roda em foreground) ou olhe os logs se rodar em background.

Depois, no host, copie deploy/nginx-vhost-atlas.conf para /home/docker/docker/nginx/sites/30-atlas.conf (ajustando o nome do arquivo para não colidir com os já existentes) e garanta que o DNS de atlas.martinsevieira.adv.br aponte para este servidor. O container anatomia-web já sobe com LETSENCRYPT_HOST=atlas.martinsevieira.adv.br, então o acme-companion existente no host emite o certificado automaticamente assim que o vhost estiver ativo e respondendo ao desafio ACME (veja os comentários no próprio arquivo deploy/nginx-vhost-atlas.conf para os detalhes/pré-requisitos).

Para reprocessar o dataset depois de mudar data-pipeline/scripts/sources.mjs, translate-pt.mjs ou seed/build-manifest.mjs (tegumentar), rode docker compose run --rm anatomia-pipeline novamente — ele reaproveita os .fbx/.glb já baixados/convertidos se ainda existirem no container (perdidos ao término do --rm, então uma nova execução sempre rebaixa/reconverte do zero; isso é intencional para manter o serviço fora do stack "sempre ligado", mas significa que cada execução leva alguns minutos).

Rodando fora desse host (dev local, sem "dockernet")

O docker-compose.yml deste projeto depende da rede externa dockernet e de um IP fixo, então para testar localmente em outra máquina crie a rede primeiro e ajuste/remova o ipv4_address, ou publique uma porta temporária no serviço anatomia-web, por exemplo:

docker network create dockernet   # numa máquina onde ela ainda não existe

E adicione temporariamente ao serviço anatomia-web no docker-compose.yml:

    ports:
      - "8080:80"

Depois docker compose up -d --build anatomia-db anatomia-api anatomia-web && docker compose run --rm anatomia-pipeline e acesse http://localhost:8080.

Estrutura do projeto

  • frontend/ — React + TypeScript + Vite + react-three-fiber (visualizador 3D), Zustand, Tailwind.
  • backend/ — Fastify + TypeScript + Prisma (API REST + arquivos .glb estáticos).
  • data-pipeline/ — scripts que geram os modelos 3D semente e populam o banco (roda como serviço Docker one-off, não fica sempre ligado).
  • nginx/nginx.conf — nginx interno que serve o frontend e faz proxy para a API.

Funcionalidades

  • Camadas por sistema: esquelético, muscular, nervoso, cardiovascular, respiratório, órgãos viscerais (digestório/urinário/endócrino/reprodutor), articulações, linfático, tegumentar — ligar/desligar independentemente.
  • Labels clicáveis: clique em qualquer estrutura no modelo 3D para ver nome, sistema, região e descrição.
  • Busca e navegação: busca fuzzy + árvore por sistema/região; selecionar uma estrutura move a câmera até ela.
  • Dissecção virtual: plano de corte deslizante nos três planos anatômicos (sagital, coronal, transversal).
  • Módulo de planos e eixos anatômicos (/planos-anatomicos): manequim simples com os três planos de secção, eixos de direção rotulados e glossário de termos (anterior/posterior, medial/lateral, proximal/distal etc.).
  • Quiz com repetição espaçada (/quiz): pede para localizar a estrutura no modelo 3D; usa o algoritmo SM-2 para agendar revisões.

Expandindo o dataset

  1. Mais arquivos do Z-Anatomy-Sample: adicione a entrada em data-pipeline/scripts/sources.mjs (SOURCES + SOURCE_TARGETS), rode o pipeline de novo.
  2. Melhorar a tradução PT-BR: acrescente entradas em data-pipeline/scripts/translate-pt.mjs (EXACT_PT) — é correspondência exata de propósito, para não arriscar tradução errada de termo médico.
  3. Sistema tegumentar com malha 3D real: se aparecer uma fonte aberta (sem exigir conta/token pra baixar) com camadas de pele, dá pra trocar o diagrama 2D atual (SkinDiagram.tsx) por um modelo real seguindo o mesmo padrão de extração usado em scripts/extract-manifest.mjs.
  4. Novos sistemas anatômicos: adicione em data-pipeline/seed/systems.mjs — o schema (backend/prisma/schema.prisma) já suporta qualquer sistema sem mudar código.

Créditos

Modelos 3D derivados do projeto Z-Anatomy (github.com/LluisV/Z-Anatomy-Sample), com base no dataset BodyParts3D/FMA (Database Center for Life Science, Universidade de Tóquio) — licença CC BY-SA 4.0. As malhas foram convertidas de FBX para glTF e recoloridas por sistema anatômico para este atlas.

Diagrama do sistema tegumentar (corte de pele): National Cancer Institute / SEER Training Modules (training.seer.cancer.gov) — obra do governo dos EUA, domínio público.

Desenvolvimento local (sem Docker)

# Backend
cd backend && npm install
export DATABASE_URL=postgresql://anatomia:anatomia@localhost:5432/anatomia
npx prisma migrate deploy
npm run dev

# Frontend (em outro terminal)
cd frontend && npm install
npm run dev   # http://localhost:5173, faz proxy de /api e /models para :3333

# Dataset (em outro terminal, com DATABASE_URL exportada)
# Requer o binário "assimp" instalado localmente (ex: apt/brew install assimp).
cd data-pipeline && npm install
npm run run:all
S
Description
No description provided
Readme
9.4 MiB
0 Stars 1 Watchers 0 Forks
Languages
TypeScript 51.6%
JavaScript 46.9%
Python 1.1%
Dockerfile 0.3%