ZeideI survived only to tell
Browse the Archives

Design avançado v0.2 — APROVADO (decisão 33) · contrato de implementação

Design avançado v0.2 — APROVADO (decisão 33) · contrato de implementação

This notebook is in Portuguese, as written during the research. Translation follows in stages, after the first published version.

File
site/docs/10-design-avancado.md
Updated
2026-09-02
Terms of use
Written by the family with AI assistance, August–September 2026. The site's source of truth.

Aprovado integralmente pelo Flavio em 01/09/2026 ("Aprovado - documentar tudo com detalhes!"). Estende — não substitui — o v0.1 congelado (07-design-system.md + tokens.css). Os tokens novos deste documento estão anexados ao tokens.css (bloco "v0.2"). Os comandos de geração de assets estão consolidados em 11-build-assets.md — este documento diz O QUÊ e POR QUÊ; o 11 diz COMO GERAR.


D-A · As ideias-assinatura#

A1 · O fio da vida — ESPECIFICAÇÃO COMPLETA#

O que é. Uma linha SVG contínua que atravessa toda a Jornada, sob as trilhas, cuja espessura em cada ponto é o número de pessoas vivas da família nuclear dele naquele momento. É o argumento do site em forma de linha: de 7 em Kalisz ao fio de 1 em 1945, ao leque de 23.

A métrica (regra fechada — não rediscutir). Contam no fio: o núcleo de origem (pais + os 5 filhos) até 1942; depois, o núcleo que ele formou (Clara + filhos + netos — descendentes diretos e Clara). Cônjuges de filhos/netos não engrossam o fio (manteria de fora a leitura "a família que saiu dele"); eles aparecem no leque do epílogo, onde a frase do slide 14 manda: "1 → 23".

A série de dados (todas as datas de fontes/dados-biograficos.md, a autoridade; o build gera fio-da-vida.json a partir dela — nunca hardcodar no front):

DataΔEspessuraEvento
12/12/1914+13nasce Mojsie (Hersz 1886 + Regina + ele)
03/02/1917+14nasce Frania
04/05/1919+15nasce Marjem "Marisha"
06/03/1922+16nasce Szyja
16/01/1929+17nasce Majer — o pico de Kalisz
ago/1930−16†Frania, aos 13 (doença) — o primeiro afinamento, antes da guerra
jul/1938·6a foto — marcador visual, sem mudança de espessura
dez/1939split1 ∥ 5a separação: o fio DELE se aparta do feixe da família (pais + Marisha + Szyja + Majer), que corre paralelo, acima, até 1942
mai–nov/19421o feixe da família termina em FADE (não em corte seco): a data exata é incerta; o desvanecimento de ~3 meses de largura é a incerteza desenhada. Legenda usa a fórmula de Majdanek ("segundo o próprio Mojsie, [55:43]")
exceção Marisha: o fio dela NÃO termina — vira pontilhado e desvanece até transparência, sem ponto final (destino jamais confirmado). Um fiapo pontilhado dela reaparece na seção "a busca continua"
1942–1950·1o vale — o fio mínimo; ancorar a citação "eu me senti no mundo sozinho" [119:22]
03/06/1950+12casamento com Clara
1952+131ª filha · 1953 +1=4 o filho · 1958 +1=5 2ª filha
1977+16Flavio · 1979 =7 · 1982 =8 · 1983 =9 · 1984 =10 · 1985 =11 · 1987 =12 (os sete netos)
18/10/2000split11+Clarao fio central termina num ponto marcado (a única terminação seca e digna do gráfico); os fios da descendência seguem até a borda direita
epílogoleque23o feixe abre no "quinto milagre": 23 vidas (slide 14) — aqui entram todos, bisnetos e cônjuges

Geometria e comportamento.

  • Path SVG por capítulo (a Jornada tem escala distorcida — decisão 7; o fio respeita a régua de cada capítulo), vector-effect: non-scaling-stroke desligado (a espessura É o dado).
  • Espessura: stroke-width = contagem × var(--thread-unit) (token: 1.2px), interpolada em rampas de ~90 dias entre degraus (nascimentos/mortes não são degraus de pixel, são curvas curtas).
  • Cor var(--thread); o feixe 1939–42 são linhas paralelas com 2px de vão (legível que são pessoas); o fade de 1942 = stroke para gradiente com stop-opacity 1→0 em ~3 meses de eixo.
  • Desenho progressivo pelo scroll horizontal: stroke-dasharray/dashoffset via scroll-driven animation (B2); com prefers-reduced-motion, o fio já aparece desenhado.
  • Acessibilidade: o SVG leva role="img" + aria-label narrando a série ("A família dele: sete pessoas em 1929; ele só, de 1942 a 1950; doze em 1987; vinte e três hoje"); os dados também existem como tabela na página "Pessoas" (mesma fonte JSON).
  • Interação: hover/focus em qualquer ponto do fio → tooltip com contagem + quem ("1945: ele só"); clique → evento mais próximo na timeline.
  • Nas telas de morte do capítulo Shoá o fio está presente mas estático (regra congelada: sem motion lúdico ali).

Formato fio-da-vida.json (gerado no build):

{ "unit_px": 1.2,
  "points": [
    {"date":"1914-12-12","count":3,"event":"nasce-mojsie"},
    {"date":"1942-08-15","count":1,"fade_months":3,"event":"familia-majdanek","formula":"majdanek"},
    {"date":"2000-10-18","count":12,"terminus":"mojsie","event":"falecimento"}
  ],
  "marisha": {"from":"1939-12-01","style":"dotted-fadeout","never_confirmed":true} }

A2 · O site feito da fita — ESPECIFICAÇÃO#

O vídeo (768×576, 4:3, 25fps, 2h17min14s = 8.237s) é a fonte visual de tudo. Quatro derivados, todos gerados no build (comandos prontos no 11-build-assets.md §3):

  1. Fundos de capítulo — 1 frame representativo por capítulo (timestamp no campo bgFrame do timeline.json), blur pesado + dessaturação parcial no ffmpeg; o duotone é CSS (overlay --bg com mix-blend-mode), para respeitar tema claro/escuro sem gerar 2× assets.
  2. Posters de evento — para todo evento com timestamp: frame exato, 640×480, mostrado no hover/focus do dot e como imagem OG do deep-link daquele momento.
  3. Sprite de scrubbing — 1 frame/10s = 824 miniaturas 160×120, paginadas em sprites 10×10 (9 arquivos JPG ~150–250 KB cada) + thumbnails.vtt com xywh. O player mostra a miniatura sob o cursor ao arrastar a barra — o gesto de "folhear a fita".
  4. Waveform da vozwaveform.json (2.000 picos normalizados 0–1 do áudio inteiro). Usos: (a) progresso do player desenhado como onda (o trecho já visto em --accent, o resto em --line-strong); (b) mini-onda estática nos z-audio-chip (o trecho A1–A12 correspondente); (c) ornamento do Memorial: a onda da frase-título [72:33] como linha divisória. Regra: a onda é sempre DELE falando — nunca decoração genérica; cada uso aponta um trecho real com timestamp.

D-B · Técnicas modernas (nativas, zero lib)#

B1 · View Transitions — ESPECIFICAÇÃO#

O site é MPA estático → usar cross-document View Transitions, declarativas:

@view-transition { navigation: auto; }            /* crossfade padrão entre páginas */

Elementos com continuidade nomeada (view-transition-name):

NomeElementoEfeito
vt-pipo playero vídeo "viaja" entre páginas sem piscar, do PiP ao player cheio
vt-photo-{eventId}foto do evento"voa" do dot da timeline ao topo do painel
vt-doc-{docId}scan no Arquivodo card à visualização grande
vt-person-{personId}retrato em Pessoasdo card à página da pessoa
vt-heroa foto de 1938 na homeda home ao capítulo Kalisz

Duração/easing dos tokens (--t-base, --ease). Progressive enhancement: sem suporte, navegação normal (nada quebra). Com prefers-reduced-motion: só crossfade, sem movimento.

B2 · Scroll-driven animations (CSS animation-timeline) — ESPECIFICAÇÃO#

Sempre dentro de @supports (animation-timeline: view()); fallback = estado final estático.

  • Reveal de fotos/cartões: animation-timeline: view(); animation-range: entry 0% entry 60%; — opacidade 0→1 + translateY 12px→0. NUNCA em documentos de morte (seletor exclui .z-cw).
  • Parallax do Memorial: 3 camadas (scroll(root) vertical), deslocamentos 0.9×/1×/1.06× — sutil; o teto de deslocamento é 6% da viewport.
  • Régua da Jornada + fio da vida: timeline do scroll HORIZONTAL do container (scroll(nearest inline)) — a régua avança e o fio se desenha conforme se navega.
  • Anos-fantasma: parallax horizontal leve (0.85×) atrás das trilhas — profundidade.

B3 · Micro-interações — TABELA NORMATIVA#

GatilhoEfeitoDuração
vídeo cruza timestamp de um dotdot pulsa 1× (scale 1→1.35→1, --c-entrevista)450ms
turno ativo na transcrição sincronizadafundo --accent-soft acende e apaga suave250ms
chip de filtro on/offfundo desliza, ícone confirma150ms
painel de evento abredesliza da direita + sombra "assenta" (--shadow-2--shadow-3)250ms
hover em z-audio-chipa mini-onda "respira" (opacity .7→1)150ms
copiar link de momentotoast discreto "link copiado · [12:34]"2s visível

Regras: nada em loop infinito; nada com som; tudo morre sob prefers-reduced-motion (o reset global do tokens.css já garante).


D-C · Imagem e tipografia#

C1 · Estética do arquivo — ESPECIFICAÇÃO#

  • Grão: SVG feTurbulence inline (data-URI no CSS, ~600 bytes), opacity: var(--grain-opacity) (token: .025), aplicado ao body::after com pointer-events:none e position:fixed. No tema escuro, --grain-opacity: .035 (grão lê mais no escuro).
  • Duotone/sépia nos heroes: filtro CSS (sepia(.35) contrast(1.05)) + overlay de gradiente --accent a 8% — nunca gravado no asset (tema-dependente).
  • Vinheta nas fotos de época: box-shadow: inset 0 0 48px rgba(0,0,0,.18) via wrapper.
  • Blur-up (LQIP): cada imagem do build ganha placeholder 24px inline (base64 no JSON, ~300 bytes), exibido com filter: blur(12px) até o carregamento; transição 250ms.
  • Formatos: AVIF + WebP + JPEG fallback via <picture>; larguras 480/960/1600; width/ height sempre declarados (CLS 0); loading="lazy" exceto o LCP da página.
  • LINHA ÉTICA (inegociável): documentos e fotos históricas nunca passam por IA generativa, "restauração", colorização ou upscale além do interpolador do browser. O grão, o amarelado e o desfoque são evidência da jornada do documento — tratá-los como linguagem. Único retoque permitido: recorte, rotação de alinhamento e ajuste global de níveis, sempre com o original intocado no repositório.

C2 · Tipografia editorial — ESPECIFICAÇÃO#

  • Fontes variáveis self-hosted: SourceSerif4Variable (eixos wght 200–900 + ital) e SourceSans3Variable (wght 200–900) — 1 arquivo WOFF2 por família+ital, subset latin+latin-ext (o polonês precisa: ą ć ę ł ń ó ś ź ż), font-display: swap, preload dos 2 principais.
  • Números: corpo de texto font-variant-numeric: oldstyle-nums proportional-nums; timestamps, régua e tabelas tabular-nums lining-nums (token utilitário .u-tabular).
  • Hifenização: hyphens: auto nos blocos longos, com lang="pt-BR"/lang="en" corretos por elemento (nomes/termos poloneses e iídiche marcados lang="pl"/lang="yi" — também é correto para leitores de tela).
  • Anos-fantasma: número do capítulo em --fs-ghost (clamp 6–12rem), font-weight: 200, cor var(--ghost-year-ink) (ink a 6%), font-variant-numeric: oldstyle-nums, atrás das trilhas (z-index abaixo, aria-hidden="true"), parallax leve (B2).
  • Aspas tipográficas reais nas citações („ " nos trechos poloneses; " " no português) e travessão — nunca hífen — nos diálogos.

D-D · Performance — METAS NORMATIVAS (medidas no CI do build)#

MétricaMetaComo medir
Lighthouse (4 colunas)100/100/100/100lighthouse-ci no build, budget falha o deploy
LCP (4G simulado)< 1,5sidem
JS por página< 30 KB gzipdu no build com limite
CLS0dimensões declaradas em toda mídia
Fontes2 preloads, subset, swapchecklist

Meios já decididos: site estático; prefetch de rotas on hover/viewport (<script> de 1 KB ou Speculation Rules API); vídeo preload="none" + poster; zero third-party no caminho crítico (GA async no fim, ausente na área família); sprites/waveform carregam sob demanda (primeira interação com a barra), nunca no load.


D-E · Alma nos detalhes — ESPECIFICAÇÃO#

  • ::selection { background: var(--accent-soft); } (token no v0.2).
  • Scrollbar fina nas áreas internas: scrollbar-width: thin; scrollbar-color: var(--line-strong) transparent;.
  • Favicon: monograma "Z" em Source Serif 4 peso 600 sobre fundo --bg, SVG com prefers-color-scheme embutido (o SVG pronto está no 11-build-assets.md §6) + PNG 180px para apple-touch-icon. É o mesmo "Z" do logotipo do header — uma identidade só.
  • OG images por template no build (1200×630): foto do contexto + título serif + a linha "Zeide — eu sobrevivi só para contar" no rodapé; template SVG→PNG no build (11 §7). Cada evento/pessoa/documento tem a sua; o link colado no WhatsApp da família mostra a foto certa (fecha B3 do backlog).
  • 404: "Esta página se perdeu — como quase se perdeu esta história. Volte ao começo." + busca + link para a home. Mesma arte da home (a foto de 1938, esmaecida).
  • Busca vazia: "nada com esse termo — tente: Kalisz, Groix, Majer, carroça, Majdanek…" (sugestões rotativas vindas do índice real).
  • Sem som de UI em lugar nenhum (decisão 11) — só a voz dele, sempre opt-in.

D-F · Ritual de qualidade antes de cada lançamento (v1, v2, v3)#

  1. Teste com a família real: a pessoa mais velha e a mais nova disponíveis usam o site sem ajuda; observar sem intervir; anotar onde travam; corrigir antes do ar.
  2. Device-lab mínimo: um iPhone antigo da família + um Android médio + desktop grande.
  3. Checklist de acessibilidade do 07 (teclado completo, leitor de tela na home/entrevista, contraste AA nos dois temas, prefers-reduced-motion de ponta a ponta).
  4. Os 3 fluxos sagrados, cronometrados: home → ouvir a voz dele (< 15s) · achar "Majdanek" na transcrição (< 20s) · abrir um documento do arquivo no celular (< 15s).
  5. Verificação de conteúdo: fórmula de Majdanek presente onde manda; nenhum dado de vivo na área pública; pedidos-prontos.md fora do build (o compilador tem denylist explícita).

Critérios de aceitação por versão#

v1 (Entrevista) — C2 completo · D-D no CI · B3 do player (dot-pulse não se aplica; turno ativo sim) · scrubbing com sprite+VTT · waveform no progresso · favicon+404+OG (páginas de momento ?t=) · grão+seleção+scrollbar · LQIP no que houver de imagem. v2 (Jornada) — A1 integral (fio com dados do JSON, split 1939, fade 1942, Marisha pontilhada, tooltip, tabela-espelho) · B1 (vt-pip, vt-photo, vt-hero) · B2 (régua, reveals, anos-fantasma) · A2 fundos+posters · B3 dot-pulse. v3 (Memorial/Mapa) — parallax B2 · waveform-ornamento com a frase [72:33] · leque do epílogo (A1) · D-F completo com a família antes do ar.