Zeideeu sobrevivi só para contar
Navegar nos Arquivos

Diário de implementação — v1 (página Entrevista)

Arquivos
site/docs/13-diario-v1.md
Atualizado
2026-09-01
Termos de uso
Escritos pela família com ajuda de IA, agosto–setembro de 2026. Fonte da verdade do site.

Documentação do processo de código, decisão a decisão, para quem mantiver o site. Iniciado em 01/09/2026. Contratos seguidos: 06-wireframes.md (W2) · 07-design-system.md · tokens.css (v0.1+v0.2) · 10-design-avancado.md (critérios v1) · 11-build-assets.md.

Estrutura criada#

site/
  build/build.mjs            ← gerador (Node puro, ZERO dependências — decisão 34)
  build/lib/*.mjs            ← parser das transcrições etc.
  src/css/site.css           ← estilos da página (tokens.css continua em docs/, é copiado)
  src/js/entrevista.js       ← player + sincronização (orçamento: <30 KB, meta ~15 KB)
  src/i18n/{pt,en}.json      ← strings de UI
  public/fonts/              ← woff2 variáveis self-hosted (commitados)
  public/media/              ← derivados PEQUENOS do vídeo (commitados: poster, sprites,
                                waveform.json, legendas VTT) — o MP4 nunca entra no git
  dist/                      ← saída do build (gitignored; regenerar: node build/build.mjs)

Registro cronológico#

01/09 · Etapa 1 — decisão de stack + parser#

  • Decisão 34 registrada (03): gerador próprio em Node, zero dependências. O motivo decisivo foi a perenidade (09): node build/build.mjs precisa funcionar igual em 2050.
  • Parser das transcrições (lib/parse-transcricao.mjs): lê os DOIS arquivos no formato **[MM:SS] FALANTE** — texto, extrai as 5 fitas com ranges, subseções da fita 5, o fecho *(fim da entrevista)*. Resultado: 487 turnos verbatim / 408 revisada, zero problemas.
  • Verificações embutidas (contrato 11 §12): timestamps não-decrescentes; falantes de conjunto conhecido (inclui "VOZ FEMININA (fora de quadro)" em [117:33] — aprendizado: rótulo com parênteses, o regex de falante não pode ser só maiúsculas); cada marcação [?] do fonte presente na saída (comparada turno a turno — comparar com o arquivo inteiro dava falso positivo: a seção "Notas" também contém [?]); sha256 dos fontes gravado no build.
  • Transformações inline (sobre texto já escapado, nesta ordem): âncoras internas **[134:47]** → botão de seek; [x?].z-unsure (pontilhado + tooltip "não foi chutado"); [palavra].z-insert (inserção editorial, tooltip); *(texto)*.z-stage. Nenhum caractere do texto dele é alterado.

01/09 · Etapa 2 — fontes e derivados de mídia#

  • Fontes variáveis self-hosted baixadas do fontsource (jsdelivr) para public/fonts/: Source Serif 4 (normal+italic, latin+latin-ext) e Source Sans 3 (normal, latin+latin-ext), 6 woff2, ~277 KB no total; preload só nos 2 latin principais. Itálico da sans: dispensado (o itálico é reservado à voz dele — serif).
  • Derivados do vídeo (build/gera-media.sh, contrato 11 §3–4), commitados em public/media/ (~3,5 MB — o MP4 continua fora do git): legendas-pt.vtt (conversão do SRT) · poster.jpg (frame de 01:30, validado a olho: ele na poltrona, plano estável) · sprite-00..08.jpg (824 miniaturas 160×120, 10×10 por página) · thumbnails.vtt · waveform.json (2.000 picos) · og.jpg (1200×630, recorte do poster).
  • Aprendizado ffmpeg: no tile, -frames:v 100 limita a SAÍDA (não a entrada) — o certo é -vf tile=10x10 -frames:v 1 -update 1 por página, com -start_number avançando de 100 em 100.
  • OG de momento (?t=) com template tipográfico (11 §7) fica para o v2 — o og.jpg do recorte é honesto e suficiente para o v1 (o título vem do og:title).

01/09 · Etapa 3 — gerador + página + player#

  • build/build.mjs: compila as duas trilhas para AMBOS os idiomas (tooltips localizados), gera / (PT), /en/, 404.html bilíngue, favicon "Z" (11 §6), robots, sitemap com hreflang, build-info.json (data + sha256 dos fontes + contagens). CSS = tokens.css + site.css concatenados sem comentários. Verificações que falham o build: problemas do parser, contagem de turnos < esperado, JS > 30 KB gzip, denylist ("pedidos-prontos") no dist.
  • Números: index.html 715 KB bruto / 94 KB gzip (é a entrevista INTEIRA, duas trilhas, 895 turnos server-rendered — legível sem JS) · CSS 19,7 KB · JS 14,5 KB (5,2 KB gzip) — orçamento de 30 KB com folga 6×.
  • build/serve.mjs (novo): servidor de dev com HTTP Range — descoberta importante: python3 -m http.server NÃO suporta Range, então o seek no MP4 de 1,25 GB congela (video.seekable = [0,0]). Na VPS o nginx faz Range nativo; no dev, usar SEMPRE node site/build/serve.mjs. Documentado também no README do site.
  • Player: waveform como barra de seek em linha própria (era estreita demais entre os botões — 143px; agora 100% da largura), preview de sprite no hover/arrasto (cálculo direto de página/célula, sem parsear o VTT no cliente), ±10s, CC ligado por padrão, fullscreen, atalhos (espaço; setas na waveform como slider ARIA), posição salva a cada 5s.

01/09 · Etapa 4 — verificação no navegador (todos os fluxos)#

TesteResultado
Clique em âncora interna [55:37] (passagem de Majdanek) seek + play + legenda certa + FITA 2 no "agora" + chip aceso
Sincronização vídeo→turno (binary search + follow) rola a página acompanhando; gesto do usuário suspende; botão religa
Busca "Majdanek" 9 turnos/2 fitas, Custom Highlight API ativa, singular/plural corrigido
Aba Verbatim↔Revisada URL ?trilha=, turno atual mapeado entre trilhas
Deep link /en/?trilha=verbatim#t=72m33s abre na frase-título, turno destacado, vídeo posicionado sem tocar
hashchange (mudar só o hash) salta e toca; .is-target agora migra para o novo turno
Tema ◐→ persiste entre páginas (script inline anti-FOUC)
EN completo · 404 com alma · mobile claro/escuro (tagline escondida no header mobile — transbordava)
Retomar de onde parou chip [MM:SS] com continuar/recomeçar
Copiar link do momento código ok; clipboard negado só no ambiente de teste sintético — re-testar num clique real
  • Formato do vídeo: 4:3 real (768×576) — o wireframe dizia 16:9; obedecido o vídeo.
  • Pendências conscientes do v1: OG por momento (v2, 11 §7) · apple-touch-icon PNG (precisa de rasterizador; SVG cobre os browsers modernos) · Lighthouse CI entra com o pipeline de deploy.