Files
gart/code/Engine/docs/02_MODULES.md
T
João HenriqueandClaude Opus 5 dcdd73edb5 docs: varredura geral, documentação por função e regra de atualização
A documentação descrevia um sistema que não existe mais: 62/73 ferramentas
(são 74), writer.py e models.py como arquivos (viraram pacotes), 1032 testes
(são 1454), models_api.py descrito como "API FastAPI" (é ponte JSON) e o app
SwiftUI ausente por completo — 5.500 linhas que o usuário opera todo dia sem
uma linha de documentação.

Cada arquivo passa a ter uma função específica, com cabeçalho de escopo
dizendo o que cobre e o que NÃO cobre (com a seta para quem cobre). O objetivo
é ler só o necessário: doc fora do assunto custa tempo e processamento sem
entregar nada.

    01 arquitetura   camadas, duas portas de entrada, regras transversais
    02 módulos       mapa do engine, incluindo o pipeline de voz
    03 server/tools  as 74 tools, helpers e como criar uma nova
    08 app macOS     NOVO — build por swiftc, telas, ponte, etapa 5
    09 manutenção    NOVO — por onde começar, o que está aberto, sintoma→arquivo

CLAUDE.md ganha a seção "Documentação (MANDATORY)": tabela de roteamento
(qual arquivo abrir para cada tarefa) e a regra de que toda alteração de
código atualiza a doc no mesmo commit, com o mapa de o-que-mexeu → o-que-
atualizar. Doc velha engana mais que doc ausente.

O índice do 05_EXPERIENCIAS subiu para o topo: consultar "isso já quebrou
antes?" custava carregar 1.281 linhas antes de chegar na tabela.

Dívidas levantadas na varredura e registradas em 09 §2: etapa 6 ainda ignora
o phrase_review.json, offset de ~400ms do Whisper, MacApp sem teste, admin/
fora do lint, confirmações visuais pendentes no FCP, submódulo WHISPERX sujo.

Também corrigidos dois links quebrados no Engine/README que apontavam um
nível acima do certo.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-19 22:51:33 -04:00

8.3 KiB
Raw Blame History

02 — Módulos do Engine (fcpxml/)

Escopo: Mapa do engine fcpxml/: qual módulo faz o quê e onde mexer. Não cobre: Camadas e regras gerais (→ 01) · handlers MCP (→ 03) · o que está aberto (→ 09)

Mapa módulo a módulo do núcleo Python: onde cada coisa mora e o que ela faz. A API pública é reexportada em fcpxml/__init__.py — essa é a fonte da verdade do __all__.

Versão: 0.6.35 · Última varredura: 2026-08-19

Por que existem pacotes aqui. writer.py tinha 4.199 linhas e models.py 1.091, cada um com muitos assuntos dentro. Viraram pacotes com um módulo por assunto. Do lado de fora nada mudou: from .writer import FCPXMLModifier e from .models import TimeValue seguem valendo, porque os __init__.py reexportam tudo — inclusive os nomes com underscore que a suíte usa.


Visão geral

Módulo / pacote Linhas Papel
writer/ 4.687 Edição e escrita de FCPXML — o coração
models/ 1.195 Data classes e enums
text_layout.py 901 Diagramação das legendas dinâmicas
rough_cut.py 798 Geração de timelines novas
model_manager.py 748 Modelos Whisper: catálogo, download, config
voice_timeline.py 594 O JSON de voz que a IA lê
phrase_review.py 547 Revisão de frases (etapa 5 do assistente)
collision.py 472 Colisão entre títulos na tela
font_metrics.py 445 Largura real de glifos por fonte
templates.py 387 Templates de timeline
parser.py 367 FCPXML → objetos Python
transcribe.py 300 Transcrição Whisper e corte por texto
live.py 273 Modo Live (push_to_fcp)
diff.py 269 Comparação de timelines
voice_actions.py 263 Decisões de edição (cut/zoom/text/marker)
export.py 226 Export Resolve v1.9 + FCP7 XMEML v5
voice_features.py 220 Pitch, energia, ritmo, pausas
diarize.py 180 Quem falou (pyannote)
media_intel.py 177 Silêncio (ffmpeg) e beats (librosa)
emphasis.py 133 Índice de ênfase por palavra
safe_xml.py 113 defusedxml + serialize_xml()
dtd.py 112 Validação contra os DTDs da Apple

writer/ — edição e escrita

O FCPXMLModifier é montado por composição de mixins: um mixin por assunto editorial, todos operando sobre o mesmo documento e os mesmos índices.

Módulo Linhas Conteúdo
core.py 723 ModifierCore: carga, índices, navegação na spine, save
titles.py 600 Títulos de texto e legendas dinâmicas
cut.py 333 Dividir, cortar faixas, apagar
speed.py 297 Velocidade e zoom (punch-in)
helpers.py 279 Sanitização, escalas, construtores de elemento
rapid.py 240 Flash frames, rapid trim, preencher buracos
validation.py 232 Verificações estruturais antes de salvar
compound.py 196 Compound clips: criar e achatar
silence.py 185 Detectar e remover silêncio
document.py 170 Assets de vídeo, timebases, write_fcpxml
markers.py 165 Marcadores: um, por timecode, em lote
audio.py 162 Clipes de áudio e cama musical
generator.py 147 FCPXMLWriter — cria documento do zero
reorder.py 126 Reordenar e recalcular offsets
trim.py 125 Aparar e propagar o ripple
transitions.py 94 Transições entre vizinhos
relink.py 94 Repontar mídia
insert.py 78 Inserir clipes na spine
modifier.py 64 Monta a classe a partir dos mixins
selection.py 57 Selecionar por palavra-chave
api.py 55 Atalhos de uma linha
connected.py 49 Clipes conectados (lanes)
roles.py 43 Atribuir roles
reformat.py 43 Reenquadrar resolução

Onde mexer: ache o assunto na tabela e abra só aquele arquivo. Se a sua mudança precisa de dois mixins ao mesmo tempo, provavelmente o que você quer é um método novo no core.py que os dois chamem.

Cuidado: os mixins compartilham self. Um método novo que colida de nome com outro mixin sobrescreve em silêncio — a ordem em modifier.py decide quem ganha. Hoje nenhum colide; mantenha assim.


models/ — dados e enums

Fonte única da estrutura de dados. Nunca mexa aqui sem rodar test_models.py.

Módulo Linhas Conteúdo
timing.py 304 TimeValue (fração racional), Timecode
timeline.py 217 Clip, ConnectedClip, CompoundClip, Timeline, Project, Marker
enums.py 183 MarkerType, MarkerColor, TransitionType, PacingStyle…
subtitles.py 157 WordLook, WordStyle, DynamicSubtitleConfig, paleta
qc.py 121 FlashFrame, GapInfo, DuplicateGroup, ValidationIssue
planning.py 93 SegmentSpec, PacingConfig, RoughCutResult, MontageConfig

MarkerType é o dono da serialização de marcador (from_string, from_xml_element, xml_attrs) — não reimplemente isso em outro lugar.


O caminho da voz (do áudio à decisão)

Estes seis módulos formam um pipeline. É o fluxo mais novo e o menos óbvio do projeto, então vale ler nesta ordem:

transcribe.py     áudio → palavras com tempo
      +
diarize.py        quem falou cada trecho
      +
voice_features.py pitch, energia, ritmo, pausas
      ▼
emphasis.py       combina tudo num índice 0–1 por palavra
      ▼
voice_timeline.py monta o _voice_timeline.json  ◄── é isto que a IA lê
      ▼
       [decisão: skill "editar-por-voz", ou a mão do usuário]
      ▼
voice_actions.py  valida a lista de cut/zoom/text/marker
      ▼
phrase_review.py  funde tudo em frases revisáveis (etapa 5 do app)
      ▼
writer/           aplica no FCPXML

Regra de ouro do pipeline: toda ação carrega tempo da mídia original, nunca pós-corte. Cortes deslocam tudo depois deles; resolver o deslocamento só na hora de aplicar (shift_after_cuts) elimina uma classe inteira de bug.

voice_timeline.py — o contrato com a IA

Saída em camadas, para um modelo raciocinar do topo e descer só onde importa:

{version, source, language,
 layers:  {transcript, acoustics, speakers, emotion}   ← o que rodou de verdade
 scales:  {…}                                          ← como ler cada número
 summary: {…}
 speakers: [...]
 segments: [{start, end, speaker, text, gap_before, take_boundary,
             avg_energy, peak_emphasis, emotion, emotion_confidence,
             words: [{text, start, end, energy, pitch_delta, rate_delta,
                      pause_before, emphasis}]}]}

layers existe para separar "a fala é monótona" de "a análise acústica nunca carregou" — os dois deixam os mesmos zeros nos dados.

phrase_review.py — a revisão humana

Junta o timeline de voz com as ações da IA numa lista de frases editáveis, e converte de volta. Frase inativa vira cut; ênfase ≥ 1 vira zoom mais um emphasis_spans que a etapa de legendas usa. O trim de cada frase anda em fronteira de palavra — cortar é apontar para uma palavra, nunca caçar frame.


Legendas dinâmicas (três módulos que andam juntos)

Módulo Papel
text_layout.py Quebra a frase em linhas e posiciona cada palavra
font_metrics.py Largura real de cada glifo na fonte escolhida
collision.py Detecta título saindo do quadro ou colidindo com outro

Estes três não estão divididos porque cada um já é um assunto só. O text_layout.py tem 901 linhas de um problema coeso: diagramação.


Armadilhas do FCPXML (custaram sessões de depuração)

  • Tempo é fração: "3600/2400s" = 1,5 s.
  • offset é posição na timeline; start é o in-point da mídia.
  • <asset-clip> (biblioteca) é diferente de <clip> (timeline).
  • Marcadores são filhos do clipe, não irmãos.
  • .fcpxmld é um diretório — sidecars precisam ser copiados no save, ou dados de object tracking e Cinematic são destruídos.
  • Negrito no FCP é bold="1" (atributo); itálico é fontFace + italic="1".
  • id de <text-style-def> precisa ser XML Name válido — acento, espaço ou dígito inicial fazem o FCP recusar o arquivo inteiro.
  • code/examples/sample.fcpxml não é DTD-conformante. Não use como fixture de validade.