Comece aqui¶
O EdgePy Viewer foi organizado em pacotes com responsabilidades distintas. A aplicação reúne esses pacotes e conecta a interface, os dados clínicos e o renderizador por contratos TypeScript. Para acrescentar uma ferramenta, começamos pelo ponto de extensão que atende à sua necessidade.
Na trilha Criando seu componente, vamos conhecer a arquitetura, escolher uma extensão e colocá-la em funcionamento:
| Etapa | O que você vai aprender |
|---|---|
| Comece aqui | Como o viewer funciona, o papel dos pacotes e onde uma extensão entra |
| Tipos de componente | Escolher entre painéis, renderizadores, resolvedores de assets e outras extensões |
| Meu primeiro componente | Criar e experimentar um painel com uma mensagem e um botão |
| Histograma | Evoluir para uma ferramenta que lê pixels, seleciona uma região e calcula uma distribuição |
| Utilizando agentes de código | Instalar a skill do EdgePy e usá-la no OpenCode para criar uma extensão |
Conheça o viewer¶
O EdgePy Viewer combina a imagem principal com navegação de estudos, seleção de séries, controle de camadas e ferramentas adicionais. A imagem abaixo mostra a aplicação clínica. Nos exercícios, você poderá experimentar esses mesmos componentes em um laboratório com dados sintéticos.
Você pode abrir a aplicação atual ou seguir direto para o primeiro exemplo interativo.
Arquitetura limpa: regras separadas das tecnologias¶
Arquitetura limpa (Clean Architecture) é a organização que mantém as regras da aplicação independentes dos detalhes de interface, armazenamento e bibliotecas externas. A regra de dependência aponta para as partes mais estáveis: o modelo clínico não precisa importar a tecnologia usada para desenhá-lo.
No EdgePy, essa ideia aparece em três decisões:
- Separar responsabilidades: o modelo clínico fica em
core. Leitura DICOM, interface, renderização e execução Python têm pacotes próprios. - Programar por contratos: a interface usa uma porta de renderização, implementada pelo Cornerstone. A aplicação pode conectar outro renderer que atenda ao mesmo contrato.
- Compor na borda:
App.tsxescolhe as implementações e registra ferramentas. O pacote de interface oferece pontos de extensão em vez de conhecer cada painel possível.
O mapa é conceitual: nem todos os contratos ficam no core. As portas de viewport vivem em react-viewer, porque descrevem a integração com a apresentação. A regra preservada é que core não dependa da UI, do browser ou dos runtimes externos. O fluxo de dados pode ir e voltar pelos callbacks, sem inverter essa dependência de código.
Como o EdgePy Viewer funciona¶
Pense no viewer como três partes conectadas pela aplicação:
- Modelo clínico: representa estudos, aquisições, séries e camadas sobrepostas. Descreve o que está sendo visualizado.
- Interface: apresenta navegação, controles e painéis. Mantém a seleção do usuário e comunica o contexto ativo.
- Renderizador: apresenta as imagens no viewport, a área principal de visualização. A implementação atual utiliza Cornerstone.
Em apps/viewer-demo/src/App.tsx, a aplicação recebe os dados preparados pela importação e os entrega ao componente PycomClinicalViewerNext. Também fornece o renderizador e o resolvedor de assets, responsável por obter os arquivos de cada série ou camada.
Arquivos locais ou assets fornecidos pelo host
↓
Importação na aplicação
↓
App.tsx reúne estudo + resolvedor de assets + renderizador
↓
PycomClinicalViewerNext
├── Navegação e controles
├── Viewport → renderizador Cornerstone
└── customPanels → seus componentes React
Ao mudar a série ou o corte, o viewer atualiza seu contexto. Uma extensão pode receber esse contexto por callback e, quando necessário, solicitar os pixels ao renderizador. Um painel simples pode funcionar apenas com seu próprio conteúdo e estado React.
Conheça os pacotes¶
O repositório usa workspaces npm: vários pacotes e aplicações são desenvolvidos juntos, com dependências declaradas entre eles. Os nomes históricos pycom permanecem nos imports, como @pycom-next/core e @pycom-next/react-viewer.
Modelo, interface e imagens¶
| Pacote | Responsabilidade | Exemplo de uso |
|---|---|---|
packages/core |
Modelo clínico, casos de uso e tipos do contexto do viewer | Representar estudos e séries e descrever o snapshot da seleção atual |
packages/react-viewer |
Componentes React, navegação, painéis e contratos do viewport | Registrar um painel em customPanels |
packages/dicom |
Portas e adaptadores de leitura DICOM | Ler informações dos arquivos para organizar as séries |
packages/renderer-cornerstone |
Implementação do renderizador usando Cornerstone | Exibir o corte e fornecer uma cópia de seus pixels |
packages/design-system |
Tokens visuais compartilhados, como cores e raios de borda | Manter a identidade visual da interface |
Integrações e execução¶
| Pacote | Responsabilidade | Exemplo de uso |
|---|---|---|
packages/host-integration |
Contratos e utilitários de integração com o sistema hospedeiro | Receber manifestos de assets e pacotes de estudo do host |
packages/worker-runtime |
Comunicação com Web Workers, incluindo requisições, progresso e erros | Executar tarefas fora da thread da interface |
packages/pyodide-agents |
Integração dos agentes Python executados no navegador | Oferecer ferramentas de processamento pelo editor PyScript |
Aplicações que usam esses pacotes¶
| Diretório | Papel |
|---|---|
apps/viewer-demo |
Aplicação Vite/React que conecta importação, viewer, renderizador e agentes. É onde faremos os exercícios. |
apps/docs-site |
Documentação que acompanha o repositório público. O laboratório desta trilha é distribuído por este site. |
A regra central é manter core independente de React, DOM, Cornerstone e Pyodide. Assim, as regras e os tipos clínicos não precisam conhecer os detalhes da interface ou da biblioteca de renderização.
Como essa separação permite extensões¶
Um contrato descreve o que uma parte oferece. Um adaptador implementa esse contrato com uma tecnologia concreta. A composição conecta essas partes na aplicação.
Por exemplo, ClinicalViewportRenderer é o contrato de renderização. O adaptador Cornerstone o implementa, e App.tsx entrega a implementação ao viewer pela propriedade viewportRenderer. O painel de histograma, por sua vez, solicita pixels pela interface pública, sem acessar objetos internos do Cornerstone.
Para criar um painel, usamos um contrato ainda menor: ViewerCustomPanel. Ele descreve a chave do painel, seu rótulo e o conteúdo React que será apresentado. A propriedade customPanels recebe essa lista. A partir dela, o viewer cria as ações de abertura e mostra o painel selecionado.
| Necessidade da extensão | Ponto de integração |
|---|---|
| Acrescentar um painel React | customPanels e ViewerCustomPanel |
| Usar outro renderizador | viewportRenderer e ClinicalViewportRenderer |
| Resolver assets de outra fonte | assetResolver e ClinicalViewportAssetResolver |
| Acrescentar ações em áreas existentes | toolbarActions, railActions, studyPanelActions e inspectorPanelActions |
| Acompanhar estudo, série e corte ativos | onControlPlaneSnapshotChange |
| Receber as operações disponíveis do renderizador | onViewportRendererHandleChange |
| Obter os pixels do corte, quando o renderizador oferecer essa operação | handle.getCurrentImageData() |
O snapshot descreve o contexto atual. O handle dá acesso às operações do renderizador ativo. Vamos usar os dois no histograma. Por enquanto, o primeiro componente precisa apenas de customPanels.
A extensão é importada no código da aplicação e incluída no build. Você pode começar uma ferramenta em apps/viewer-demo/src/ e, se precisar reutilizá-la em outras aplicações, movê-la para um pacote próprio.
Prepare o ambiente¶
Você precisará de Git, npm e Node.js compatível com Vite 7, por exemplo Node 22.12 ou superior da linha 22. Para os exercícios, basta conhecer funções, imports e componentes React básicos.
Os exercícios usam o repositório público do EdgePy Viewer. Clone o projeto e use a revisão abaixo para acompanhar os mesmos contratos apresentados na trilha:
git clone https://github.com/guilhermeRey/ipen-edgepy-viewer.git
cd ipen-edgepy-viewer
git checkout v0.3.0
npm ci
npm run dev
A versão v0.3.0 contém a aplicação, o registro de painéis, a leitura de pixels e a seleção de ROI na imagem principal por beginRectangularRoi(). Abra o endereço mostrado pelo Vite e confira que a interface aparece. O primeiro componente funciona sem importar imagens.
De onde vem cada arquivo?¶
Todos os caminhos da trilha partem da pasta ipen-edgepy-viewer/ que você acabou de clonar.
| Arquivos | Como obter |
|---|---|
apps/viewer-demo/src/App.tsx e packages/ |
Já estão no repositório público |
HelloPanel.tsx, a pasta histogram/ e syntheticRenderer.ts |
Crie com o código das páginas ou use o ZIP de exemplos |
| Suporte à ROI nos pacotes do viewer e do Cornerstone | Já está incluído na tag v0.3.0 |
Skill edgepy-component |
Baixe na etapa Utilizando agentes de código |
Baixar os exemplos para o repositório público
Extraia o ZIP na raiz de ipen-edgepy-viewer/, preservando a estrutura apps/viewer-demo/src/. Ele fornece os arquivos novos. O registro em App.tsx continua sendo feito nos passos do tutorial, para preservar os painéis da sua aplicação.
Os exemplos usam os contratos já publicados na v0.3.0. As alterações do exercício ficam nos componentes da aplicação e no registro em App.tsx.
Os fontes completos do laboratório e seu manifesto de hashes também estão disponíveis para consulta. Você não precisa instalar ou compilar o site de documentação para fazer os exercícios.
O percurso de reprodução usa a tag v0.3.0, os exemplos e o registro dos painéis em App.tsx. As verificações incluem tipagem, testes numéricos, build e seleção na imagem principal. Os arquivos distribuídos têm seus hashes publicados para conferir a versão utilizada.
O que observar sobre extensibilidade¶
A organização dos pacotes explica onde uma mudança deve entrar. Os exercícios permitem conferir como essa mudança se integra ao viewer:
| Pergunta | O que observar |
|---|---|
| Onde foi necessário editar? | No primeiro exemplo, um componente novo e o registro em App.tsx |
| Qual contrato foi utilizado? | ViewerCustomPanel, recebido por customPanels |
| A extensão depende de detalhes internos? | Confira seus imports e se foi necessário editar os pacotes do viewer |
| O comportamento esperado foi obtido? | Abra o painel e interaja com o componente |
| Outra pessoa consegue repetir? | Registre a revisão usada, o tempo e as dúvidas durante a reprodução |
Essas observações ajudam a avaliar a extensibilidade para a tarefa proposta. A arquitetura indica onde conectar a ferramenta. Ao repetir o exercício, você verifica se os contratos atendem à necessidade e quanto esforço a integração exige.
Onde conferir no código¶
Na versão pública usada nesta trilha:
apps/viewer-demo/src/App.tsx: composição da aplicação e registro dos painéis.packages/react-viewer/src/index.tsx: propriedades públicas e callbacks do viewer.packages/react-viewer/src/components/ViewerDrawers.tsx: contrato e apresentação dos painéis personalizados.packages/react-viewer/src/ports/viewportRenderer.ts: contratos do renderizador e dos pixels.packages/core/src/index.ts: modelo clínico e snapshot.
Próximo passo: conheça os tipos de componente.
