primocode 10.16.0 → 10.17.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (234) hide show
  1. package/LICENSES/edit-ia-pro.txt +32 -0
  2. package/LICENSES/fontes-OFL.txt +476 -0
  3. package/LICENSES/hyperframes-Apache-2.0.txt +205 -0
  4. package/LICENSES/permanent-marker-Apache-2.0.txt +204 -0
  5. package/LICENSES/selfie-multiclass-Apache-2.0.txt +227 -0
  6. package/LICENSES/three-MIT.txt +23 -0
  7. package/LICENSES/video-use-MIT.txt +24 -0
  8. package/LICENSES/woven-sfx-CC0.txt +16 -0
  9. package/LICENSES/yunet-MIT.txt +21 -0
  10. package/README.md +2 -2
  11. package/bin/primocode.js +11 -2
  12. package/editor/LICENSE.md +11 -0
  13. package/editor/README.md +321 -0
  14. package/editor/SKILL.md +307 -0
  15. package/editor/THIRD_PARTY_NOTICES.md +228 -0
  16. package/editor/assets/baixar.json +591 -0
  17. package/editor/assets/fonts/anton/OFL.txt +93 -0
  18. package/editor/assets/fonts/caveat/OFL.txt +93 -0
  19. package/editor/assets/fonts/figtree/OFL.txt +93 -0
  20. package/editor/assets/fonts/fonts.json +10 -0
  21. package/editor/assets/fonts/montserrat/OFL.txt +93 -0
  22. package/editor/assets/fonts/permanentmarker/LICENSE.txt +202 -0
  23. package/editor/assets/models/SELFIE_MULTICLASS_LICENSE.txt +227 -0
  24. package/editor/assets/models/YUNET_LICENSE.txt +21 -0
  25. package/editor/assets/sfx/licencas/bass_drop.txt +32 -0
  26. package/editor/assets/sfx/licencas/cash.txt +76 -0
  27. package/editor/assets/sfx/licencas/charge.txt +31 -0
  28. package/editor/assets/sfx/licencas/click.txt +46 -0
  29. package/editor/assets/sfx/licencas/coin.txt +50 -0
  30. package/editor/assets/sfx/licencas/count.txt +47 -0
  31. package/editor/assets/sfx/licencas/data.txt +31 -0
  32. package/editor/assets/sfx/licencas/error.txt +32 -0
  33. package/editor/assets/sfx/licencas/flash.txt +31 -0
  34. package/editor/assets/sfx/licencas/gears.txt +82 -0
  35. package/editor/assets/sfx/licencas/keyboard.txt +48 -0
  36. package/editor/assets/sfx/licencas/metal_hit.txt +62 -0
  37. package/editor/assets/sfx/licencas/metal_riser.txt +61 -0
  38. package/editor/assets/sfx/licencas/mouse_click.txt +50 -0
  39. package/editor/assets/sfx/licencas/notification.txt +54 -0
  40. package/editor/assets/sfx/licencas/pop.txt +38 -0
  41. package/editor/assets/sfx/licencas/rewind.txt +32 -0
  42. package/editor/assets/sfx/licencas/rise.txt +46 -0
  43. package/editor/assets/sfx/licencas/sinteticos.txt +21 -0
  44. package/editor/assets/sfx/licencas/snap.txt +50 -0
  45. package/editor/assets/sfx/licencas/success.txt +40 -0
  46. package/editor/assets/sfx/licencas/synth_hit.txt +32 -0
  47. package/editor/assets/sfx/licencas/tick.txt +14 -0
  48. package/editor/assets/sfx/licencas/whoosh.txt +47 -0
  49. package/editor/assets/sfx/licencas/wind.txt +31 -0
  50. package/editor/assets/sfx/sfx.json +832 -0
  51. package/editor/assets/sfx/sfx_sinteticos.json +317 -0
  52. package/editor/assets/sfx/sfx_woven.json +387 -0
  53. package/editor/assets/sfx/woven/LICENCA.md +16 -0
  54. package/editor/fichas/briefing-do-video.md +45 -0
  55. package/editor/fichas/conferencia-da-amostra.md +56 -0
  56. package/editor/fichas/matriz-de-ganchos.csv +3 -0
  57. package/editor/fichas/padrao.json +16 -0
  58. package/editor/fichas/planilha-de-cenas.csv +4 -0
  59. package/editor/fichas/planilha-de-versoes.csv +4 -0
  60. package/editor/fichas/plano-em-blocos.md +32 -0
  61. package/editor/fichas/registro-de-materiais.json +27 -0
  62. package/editor/helpers/assets_ocr/ocr_vision.swift +41 -0
  63. package/editor/helpers/bordas_precisas.py +272 -0
  64. package/editor/helpers/camera_viva.py +426 -0
  65. package/editor/helpers/captions.py +601 -0
  66. package/editor/helpers/common.py +308 -0
  67. package/editor/helpers/compose_final.py +3555 -0
  68. package/editor/helpers/conferir_corte.py +234 -0
  69. package/editor/helpers/conferir_dados.py +405 -0
  70. package/editor/helpers/contact_sheet.py +282 -0
  71. package/editor/helpers/corte_por_onda.py +433 -0
  72. package/editor/helpers/corte_seco.py +595 -0
  73. package/editor/helpers/denoise.py +971 -0
  74. package/editor/helpers/efeitos.py +408 -0
  75. package/editor/helpers/efeitos_gerar.py +159 -0
  76. package/editor/helpers/elevenlabs_api.py +442 -0
  77. package/editor/helpers/face_layout.py +570 -0
  78. package/editor/helpers/fetch_images.py +423 -0
  79. package/editor/helpers/ganho_por_trecho.py +214 -0
  80. package/editor/helpers/gen_image.py +312 -0
  81. package/editor/helpers/gen_music.py +316 -0
  82. package/editor/helpers/gen_sfx.py +148 -0
  83. package/editor/helpers/grade.py +307 -0
  84. package/editor/helpers/icloud.py +119 -0
  85. package/editor/helpers/make_sfx.py +940 -0
  86. package/editor/helpers/matte.py +1342 -0
  87. package/editor/helpers/medir_referencia.py +2232 -0
  88. package/editor/helpers/mixar_trilha.py +354 -0
  89. package/editor/helpers/montar_corte.py +295 -0
  90. package/editor/helpers/motion/__init__.py +13 -0
  91. package/editor/helpers/motion/engine.py +1915 -0
  92. package/editor/helpers/motion/registry.py +510 -0
  93. package/editor/helpers/motion/render.py +665 -0
  94. package/editor/helpers/motion/templates/barra_progresso.py +370 -0
  95. package/editor/helpers/motion/templates/carimbo.py +132 -0
  96. package/editor/helpers/motion/templates/checklist.py +271 -0
  97. package/editor/helpers/motion/templates/comentario_cta.py +380 -0
  98. package/editor/helpers/motion/templates/contador.py +222 -0
  99. package/editor/helpers/motion/templates/destaque.py +263 -0
  100. package/editor/helpers/motion/templates/etiqueta_preco.py +461 -0
  101. package/editor/helpers/motion/templates/grafico_barras.py +510 -0
  102. package/editor/helpers/motion/templates/grafico_linha.py +462 -0
  103. package/editor/helpers/motion/templates/notificacao.py +266 -0
  104. package/editor/helpers/motion/templates/palavra_impacto.py +410 -0
  105. package/editor/helpers/motion/templates/passos.py +321 -0
  106. package/editor/helpers/motion/templates/riscado.py +298 -0
  107. package/editor/helpers/motion/templates/selo_garantia.py +150 -0
  108. package/editor/helpers/motion_render.py +241 -0
  109. package/editor/helpers/motion_sugerir.py +961 -0
  110. package/editor/helpers/noise_check.py +134 -0
  111. package/editor/helpers/pack_transcripts.py +223 -0
  112. package/editor/helpers/palavras_na_onda.py +176 -0
  113. package/editor/helpers/plano_sfx.py +839 -0
  114. package/editor/helpers/portao.py +427 -0
  115. package/editor/helpers/preview_server.py +1177 -0
  116. package/editor/helpers/rastrear_rosto.py +298 -0
  117. package/editor/helpers/render_cut.py +1256 -0
  118. package/editor/helpers/respiros.py +89 -0
  119. package/editor/helpers/sincronizar_cameras.py +571 -0
  120. package/editor/helpers/speech_regions.py +423 -0
  121. package/editor/helpers/style_catalog.json +231 -0
  122. package/editor/helpers/style_samples.py +246 -0
  123. package/editor/helpers/tela_verde.py +2113 -0
  124. package/editor/helpers/text_render.py +2059 -0
  125. package/editor/helpers/texto_na_tela.py +366 -0
  126. package/editor/helpers/timeline_view.py +292 -0
  127. package/editor/helpers/tira_de_quadros.py +113 -0
  128. package/editor/helpers/transcribe.py +734 -0
  129. package/editor/helpers/transcribe_batch.py +129 -0
  130. package/editor/helpers/trilhas.py +1146 -0
  131. package/editor/helpers/trilhas_humores.json +66 -0
  132. package/editor/helpers/valores.py +187 -0
  133. package/editor/helpers/verify_cut.py +820 -0
  134. package/editor/helpers/voice_levels.py +233 -0
  135. package/editor/helpers/voz_check.py +386 -0
  136. package/editor/helpers/voz_limpa.py +81 -0
  137. package/editor/helpers/watch_preview.py +372 -0
  138. package/editor/modelo-projeto/LEIA.md +402 -0
  139. package/editor/modelo-projeto/assets/fontes/OFL-Caveat.txt +93 -0
  140. package/editor/modelo-projeto/assets/fontes/OFL-JetBrainsMono.txt +93 -0
  141. package/editor/modelo-projeto/assets/fontes/OFL-Montserrat.txt +93 -0
  142. package/editor/modelo-projeto/assets/fontes/larguras.json +1 -0
  143. package/editor/modelo-projeto/assets/three/BufferGeometryUtils.js +1438 -0
  144. package/editor/modelo-projeto/assets/three/GLTFLoader.js +4895 -0
  145. package/editor/modelo-projeto/assets/three/LICENSE +21 -0
  146. package/editor/modelo-projeto/assets/three/ORIGEM.txt +17 -0
  147. package/editor/modelo-projeto/assets/three/RoomEnvironment.js +185 -0
  148. package/editor/modelo-projeto/assets/three/three.core.min.js +6 -0
  149. package/editor/modelo-projeto/assets/three/three.module.min.js +6 -0
  150. package/editor/modelo-projeto/build.py +4828 -0
  151. package/editor/modelo-projeto/compositions/cenas/2d/k2d_antes_depois.html +199 -0
  152. package/editor/modelo-projeto/compositions/cenas/2d/k2d_arquivo.html +232 -0
  153. package/editor/modelo-projeto/compositions/cenas/2d/k2d_busca.html +315 -0
  154. package/editor/modelo-projeto/compositions/cenas/2d/k2d_comando.html +304 -0
  155. package/editor/modelo-projeto/compositions/cenas/2d/k2d_conversa.html +217 -0
  156. package/editor/modelo-projeto/compositions/cenas/2d/k2d_esquema.html +289 -0
  157. package/editor/modelo-projeto/compositions/cenas/2d/k2d_medidor.html +249 -0
  158. package/editor/modelo-projeto/compositions/cenas/2d/k2d_notas.html +233 -0
  159. package/editor/modelo-projeto/compositions/cenas/3d/k3d_caminho.html +197 -0
  160. package/editor/modelo-projeto/compositions/cenas/3d/k3d_explodida.html +152 -0
  161. package/editor/modelo-projeto/compositions/cenas/3d/k3d_tela.html +167 -0
  162. package/editor/modelo-projeto/compositions/cenas/3d/k3d_volume.html +124 -0
  163. package/editor/modelo-projeto/compositions/cenas/3d/motor-three.js +728 -0
  164. package/editor/modelo-projeto/compositions/cenas/LEIA.md +177 -0
  165. package/editor/modelo-projeto/ferramentas/medir_fontes.py +65 -0
  166. package/editor/modelo-projeto/ferramentas/pessoa_recortada.py +176 -0
  167. package/editor/modelo-projeto/ferramentas/rastrear_maos.py +189 -0
  168. package/editor/modelo-projeto/hyperframes.json +12 -0
  169. package/editor/modelo-projeto/package.json +11 -0
  170. package/editor/modelo-projeto/projeto.json +16 -0
  171. package/editor/preview/app.css +1009 -0
  172. package/editor/preview/app.js +2122 -0
  173. package/editor/preview/index.html +307 -0
  174. package/editor/pyproject.toml +23 -0
  175. package/editor/references/3d.md +236 -0
  176. package/editor/references/animacao-catalogo.md +672 -0
  177. package/editor/references/animacao.md +498 -0
  178. package/editor/references/comandos.md +92 -0
  179. package/editor/references/corte-seco-como-funciona.md +50 -0
  180. package/editor/references/corte-seco.md +88 -0
  181. package/editor/references/corte.md +290 -0
  182. package/editor/references/direcao-por-blocos.md +218 -0
  183. package/editor/references/enquadramento.md +654 -0
  184. package/editor/references/estilos-prontos.md +355 -0
  185. package/editor/references/estudio.md +100 -0
  186. package/editor/references/exemplo-eventos.json +67 -0
  187. package/editor/references/lettering.md +252 -0
  188. package/editor/references/modelos.md +494 -0
  189. package/editor/references/phase2.md +1007 -0
  190. package/editor/references/referencia-aplicar.md +203 -0
  191. package/editor/references/referencia-medir.md +375 -0
  192. package/editor/references/revisao.md +335 -0
  193. package/editor/references/som-e-trilha.md +146 -0
  194. package/editor/references/tabela-de-sons.md +130 -0
  195. package/editor/references/variacoes.md +234 -0
  196. package/editor/uv.lock +1141 -0
  197. package/lib/act.js +36 -8
  198. package/lib/catalogo.js +4 -0
  199. package/lib/chamada-torta.js +81 -0
  200. package/lib/editor-pro.js +786 -0
  201. package/lib/entrega.js +58 -0
  202. package/lib/estudio/conferencia-visual.js +76 -0
  203. package/lib/estudio/diretor.js +6 -1
  204. package/lib/estudio/exportar.js +3 -1
  205. package/lib/estudio/gosto.js +45 -4
  206. package/lib/estudio/index.js +8 -5
  207. package/lib/estudio/kit-ae/base.jsx +119 -13
  208. package/lib/estudio/kit-ae/cenas.jsx +47 -15
  209. package/lib/estudio/kit-ae/guarda.jsx +274 -0
  210. package/lib/estudio/kit-ae/primitivas.jsx +180 -24
  211. package/lib/estudio/maquina-diretor.js +61 -7
  212. package/lib/estudio/maquina-foto.js +177 -0
  213. package/lib/estudio/maquina-guarda.js +207 -0
  214. package/lib/estudio/maquina-layout.js +22 -1
  215. package/lib/estudio/maquina.js +60 -11
  216. package/lib/estudio/referencias.js +1 -1
  217. package/lib/estudio/visao/visao.swift +97 -0
  218. package/lib/estudio/visao.js +60 -0
  219. package/lib/local/cerebro.json +192 -6
  220. package/lib/local/motor.js +5 -2
  221. package/lib/nuvem.js +11 -1
  222. package/lib/passagem.js +50 -0
  223. package/lib/perigo.js +19 -11
  224. package/lib/protecao.js +134 -0
  225. package/lib/titulo-conversa.js +46 -0
  226. package/lib/tools.js +3 -0
  227. package/lib/ui.js +1 -1
  228. package/package.json +3 -2
  229. package/skills/editar-meu-video/SKILL.md +6 -2
  230. package/skills/editar-video/SKILL.md +113 -0
  231. package/studio/pessoa.py +52 -0
  232. package/voz/primo_voz/app.py +43 -4
  233. package/voz/primo_voz/chat.html +17 -6
  234. package/voz/primo_voz/painel_dados.py +134 -0
@@ -0,0 +1,654 @@
1
+ # Enquadramento: pessoa, moldura, tela verde e planos
2
+
3
+ Você decide, trecho por trecho, como a pessoa aparece e quanto espaço ela divide com o que está sendo
4
+ explicado. O `build.py` do projeto-modelo faz a conta do enquadramento pelo rosto medido, anima a troca e põe a
5
+ legenda e as peças fora do rosto. O vídeo continua sendo o `cut.mp4` do corte; a voz nunca para.
6
+
7
+ ## Como falar com a pessoa
8
+
9
+ - Português simples, frases curtas. Nada de código, JSON ou caminho comprido na conversa.
10
+ - Conte o plano em palavras do dia a dia, com o tempo em 00:12: "De 00:00 a 00:21 você em tela cheia. Em
11
+ 00:22 você vai para um quadrinho embaixo e a lista aparece em cima. Em 00:28 volta pra tela cheia."
12
+ - Autorização em camadas: se a pessoa já autorizou fazer tudo, conte e siga; se pediu para aprovar antes,
13
+ espere. O teste de recorte é a exceção (seção "Portão do recorte").
14
+ - Uma decisão por vez. Se ela disser "decide você", decida e conte em uma linha.
15
+
16
+ ## Antes de começar
17
+
18
+ Precisa existir, na pasta `edit` do corte (`<EDIT>`): `cut.mp4` aprovado, `cut_timeline.json`,
19
+ `transcripts/cut.json` (a transcrição do corte) e `face_layout.json`. Se faltar o `face_layout.json`:
20
+
21
+ `uv run --directory "<SKILL>" python helpers/face_layout.py --edit-dir '<EDIT>'`
22
+
23
+ (`<SKILL>` é a pasta desta skill.)
24
+
25
+ O projeto HyperFrames é uma cópia da pasta `modelo-projeto` desta skill (`<SKILL>/modelo-projeto`), feita
26
+ pelo próprio modelo, perto dos vídeos:
27
+
28
+ `python3 '<SKILL>/modelo-projeto/build.py' novo '<VIDEOS>/sala' --edit '<EDIT>'`
29
+
30
+ Ele anota no `projeto.json` a skill de onde o projeto veio (`"skill"`) e a pasta `edit`; as ferramentas do
31
+ projeto (recorte da pessoa, mãos) usam essa skill, e não outra instalada no computador. Nunca edite o modelo
32
+ original. O `LEIA.md` do modelo tem os campos.
33
+
34
+ ## Primeiro, assista o trecho tocando
35
+
36
+ Um quadro solto não diz se o enquadramento aguenta a fala inteira. Antes de decidir, toque o trecho e procure:
37
+
38
+ - o ponto em que a cabeça mais tomba ou mais se afasta do centro;
39
+ - o gesto mais largo (mão que sai para o lado, objeto levantado);
40
+ - as trocas de tomada (o rosto muda de lugar em cada uma).
41
+
42
+ Depois marque as **regiões obrigatórias** de cada trecho: a cabeça inteira e o rosto, sempre; as mãos, o
43
+ objeto mostrado ou a postura, quando carregam informação ("olha esse pote", mão contando nos dedos, o celular
44
+ virado para a câmera). Nenhum recorte, moldura ou peça pode cortar uma região obrigatória.
45
+
46
+ O build ajuda a conferir: nos blocos com `"acompanhar": true` ele avisa quando a cabeça sai do quadro; com o
47
+ `assets/maos.json` (`ferramentas/rastrear_maos.py` do projeto) ele avisa, com o intervalo, quando uma mão que a
48
+ gravação mostra sai do quadro da moldura ou da tela por 0,2 s ou mais. O aviso não sabe se a mão mostra algo:
49
+ decida você (se mostra, aumente o quadro, diminua o zoom, use tela cheia ou `contida`).
50
+
51
+ O meio do quadro não é, necessariamente, onde a pessoa está. Mire o rosto no centro da área disponível, sem
52
+ perseguir cada micromovimento.
53
+
54
+ ## Os jeitos de mostrar a pessoa
55
+
56
+ | cena | o que aparece | quando usar |
57
+ |---|---|---|
58
+ | `tela_cheia` | a pessoa ocupando a tela, zoom leve (1,08 a 1,12) com o rosto centralizado | gancho, opinião, história, desejo, chamada, demonstração feita com o corpo. O rosto vende. |
59
+ | `prova` | a prova em tela cheia: a própria gravação da tela (sem zoom) ou um print/vídeo (`arquivo`, a partir do segundo `inicio`), com rótulo em cima e zoom que anda até o que importa | tela do app, iPad, painel, página, print. É a prova real. |
60
+ | `moldura` | a pessoa num quadro arredondado embaixo e o papel quadriculado atrás (ou o próprio vídeo desfocado, `"fundo": "desfocado"`); a animação ocupa o alto | explicação que divide a tela: lista, passos, causa e efeito, diagrama, celular com notificação |
61
+ | `tela_verde` | a pessoa recortada num canto, com contorno branco, na frente de uma imagem ou vídeo (`fundo`) | comentário sobre algo que precisa ficar grande atrás dela: notícia, página, vídeo, produto |
62
+ | planos (2,5D) | a pessoa recortada no meio, uma palavra em parte atrás do corpo, um objeto à frente | palavra forte, lançamento, autoridade, explicação curta. Só com o teste de recorte aprovado. Seção "Composição em planos" |
63
+ | `contida` | a gravação inteira dentro da tela, com margem, sobre ela mesma desfocada (ou o papel, ou uma cor) | quando a região obrigatória não cabe no recorte (seção "Quando não cabe"), gravação em pé num 16:9, 4:5 ou 1:1 |
64
+ | `comparar` | dois arquivos (ou dois trechos) lado a lado ou alternando, na mesma escala e na mesma velocidade, com rótulos literais | antes e depois honesto, duas versões, duas soluções (seção "Comparar") |
65
+
66
+ ## Regras de decisão
67
+
68
+ Tiradas das edições aprovadas. Siga na ordem.
69
+
70
+ 1. **Comece em tela cheia.** Gancho e chamada ficam em tela cheia. O rosto prende e convence. Todo efeito
71
+ começa e termina com a gravação cheia na tela.
72
+ 2. **Prova real em tela cheia, com rótulo em cima.** Se a gravação mostra a tela do app ou o iPad, esse
73
+ trecho é `prova` sem zoom: a prova aparece inteira. Print ou vídeo de tela da pessoa entra como `prova` com
74
+ `arquivo`. O rótulo diz o que é ("Tela do app", "Pedido real"), curto. Painel pequeno e ilegível não
75
+ prova nada: se a prova não se lê no celular, ela precisa de mais área.
76
+ 3. **Moldura só quando a câmera volta pro rosto.** Moldura em cima da prova esconde a prova. Ela entra quando
77
+ a pessoa volta a falar para a câmera e a explicação precisa de espaço.
78
+ 4. **Quando encolher as duas coisas deixa tudo ilegível, a demonstração fica com a tela toda** e a voz conduz.
79
+ A pessoa volta depois.
80
+ 5. **A moldura entra e sai no corte.** O `build.py` encosta a borda do bloco no corte mais perto (até 0,35 s) e
81
+ avisa. A troca no corte some no salto da imagem. Se não tem corte perto, a saída volta animando em 0,55 s.
82
+ 6. **Moldura de 4 a 12 s.** Mais que isso cansa. Nada de moldura decorativa o vídeo inteiro, nem pessoa pequena
83
+ num canto por padrão. Divida com um trecho de tela cheia no meio.
84
+ 7. **Na moldura a legenda sai.** Quem explica ali é a animação. A legenda volta quando volta a tela cheia.
85
+ (Dá para ligar com `"legenda": {"na_moldura": true}`, mas só faça se a pessoa pedir.)
86
+ 8. **Tudo que está na moldura sai antes dela acabar.** O `build.py` corta a saída das peças 0,1 s antes do fim
87
+ do bloco e avisa.
88
+ 9. **Depois de cada inserção, volte à câmera com continuidade.** Mesmo lado, mesmo tamanho de rosto de antes.
89
+ 10. **Tela verde é para o assunto ficar grande.** Pessoa comentando uma notícia, uma página, um vídeo de outra
90
+ pessoa, um produto. Se a gravação já mostra a tela, não precisa. É uma coisa ou outra no mesmo trecho:
91
+ nunca moldura e tela verde juntas.
92
+ 11. **Dado privado não aparece.** Nome e telefone de cliente, e-mail, senha, chave, número de pedido de outra
93
+ pessoa, conversa, nome de projeto na barra lateral: vai com `borrar`, com o tempo de cada caixa. O borrão é
94
+ queimado no arquivo (seção "Borrão"), então nem quem recebe a pasta do projeto vê o dado.
95
+ 12. **Rosto livre.** Nada cobre olhos e boca. A legenda fica no peito, a peça pequena em cima da cabeça, a peça
96
+ grande na área livre da moldura. Legenda, informação e rosto em áreas separadas.
97
+ 13. **Zona segura do Reels.** No 9:16, texto entre y 230 e 1530 e entre x 140 e 940 (a barra do topo, o botão
98
+ do anúncio e a coluna de curtir cobrem o resto). O modelo já respeita.
99
+ 14. **Moldura separa, não deforma.** Contorno, sombra e uma leve inclinação separam planos. Nunca esticar,
100
+ espremer ou entortar a pessoa. Nada de zoom que não para nem reenquadramento agitado só para ocupar tempo.
101
+ 15. **Visual.** `papelaria` é o padrão do modelo (no modo automático a skill usa `laranja`): papel quadriculado lilás, cartões brancos com base lilás, Montserrat 900
102
+ e Caveat à mão. `noite` para marca escura (azul-marinho com pontinhos, cartões brancos). `laranja` para o visual escuro dos
103
+ vídeos do André (fundo quase preto com grade e brilho laranja, cartões escuros com fio laranja, texto claro).
104
+
105
+ Quando uma animação grande (lista, passo a passo, diagrama, celular, fotos) cair num trecho de tela cheia e o
106
+ `build.py` avisar que não coube sem encostar no rosto, transforme esse trecho em moldura.
107
+
108
+ ## No projeto.json
109
+
110
+ ```json
111
+ "blocos": [
112
+ {"cena": "tela_cheia", "de": 0, "ate": 14.4, "zoom": 1.1},
113
+ {"cena": "prova", "de": 14.4, "ate": 18.3, "rotulo": "Tela do *app*"},
114
+ {"cena": "moldura", "de": 18.3, "ate": 28.03},
115
+ {"cena": "tela_verde", "de": 28.03, "ate": 32.3, "fundo": "assets/pagina.png", "posicao": "direita"},
116
+ {"cena": "tela_cheia", "de": 32.3}
117
+ ]
118
+ ```
119
+
120
+ - `de` e `ate` em segundos do `cut.mp4` (ou a palavra, como nas animações). Buraco entre blocos vira tela cheia.
121
+ - `tela_cheia`: `zoom` (1,08 a 1,12), `zooms` (seção "Zoom na palavra"), `borrar`, `acompanhar` (seção
122
+ "Acompanhar a pessoa dentro da tomada").
123
+ - `prova`: `arquivo` (imagem ou vídeo em `assets/`), `inicio` (o segundo do vídeo em que a prova começa; sem
124
+ ele, do 0), `encaixe` (`cobrir` enche a tela; `inteiro` mostra tudo por cima de uma cópia borrada), `rotulo`,
125
+ `borrar` (seção "Borrão"), `zoom` (padrão 1, a prova inteira), `zooms`. A entrada da prova é um corte seco:
126
+ o `sons_sugeridos.json` pede um whoosh com o pico no quadro do corte, e o rótulo entra 0,62 s depois.
127
+ - `moldura`: `fundo` (`papel`, o padrão, ou `desfocado`: o próprio vídeo, desfocado e escurecido, atrás do
128
+ quadro). A caixa padrão é x 520, y 980, 400 x 540 no 9:16 e x 1080, y 120, 720 x 840 no 16:9.
129
+ Para mudar em todo o vídeo: `"moldura": {"caixa": [x, y, largura, altura]}` no topo do projeto. `acompanhar`
130
+ também vale aqui.
131
+ - `contida`: `fundo` (`desfocado`, o padrão; `papel`; ou uma cor, `"#1b1830"`), `margem` (px, padrão 6% do lado
132
+ menor), `raio`. Entra e sai no corte como a moldura.
133
+ - `comparar`: `a` e `b` (`arquivo`, `inicio`, `rotulo`), `modo`, `trocas`, `som` (seção "Comparar").
134
+ - `tela_verde`: `fundo` (imagem ou vídeo), `inicio` (do vídeo de fundo), `encaixe`, `posicao` (`direita`,
135
+ `esquerda`, `centro`), `altura` (0,62 no canto e 0,8 no centro, fração da tela), `contorno` (`true`).
136
+ - `legenda` (`true` ou `false`) em qualquer bloco força ligar ou desligar a legenda ali. Desligada num bloco, a
137
+ palavra que começa até 0,3 s antes dele também sai (não pisca antes da troca); a primeira palavra do bloco
138
+ seguinte tem legenda normal.
139
+ - Os campos da composição em planos e das cenas próprias estão no `LEIA.md` do modelo-projeto.
140
+
141
+ ## Zoom na palavra e zoom que anda até um ponto
142
+
143
+ Nos blocos `tela_cheia` e `prova`, `zooms` é uma lista; cada zoom entra numa palavra e volta no `ate`:
144
+
145
+ ```json
146
+ {"cena": "prova", "de": 12.3, "ate": 19.8,
147
+ "zooms": [{"em": "botão", "caixa": [0.52, 0.61, 0.30, 0.08], "ate": "clicou"},
148
+ {"em": "resultado", "caixa": [0.1, 0.3, 0.8, 0.3], "duracao": 0.6}]},
149
+ {"cena": "tela_cheia", "de": 19.8, "zooms": [{"em": "nunca", "escala": 1.3, "ate": "vendi"}]}
150
+ ```
151
+
152
+ - `caixa` `[x, y, largura, altura]` em fração do vídeo gravado (o `cut.mp4`, de 0 a 1; na prova com `arquivo`,
153
+ do arquivo): a câmera anda até ela e a enquadra com uma folga (o "zoom no botão" da tela gravada). Olhe um
154
+ quadro para achar a caixa. `escala` troca o quanto aproxima.
155
+ - Sem `caixa`: punch-in no rosto, com `escala` (padrão 1,3), em 0,2 s. Com `caixa`, o zoom anda em 0,45 s
156
+ (`duracao`). A volta leva `duracao_volta` (padrão igual, no mínimo 0,35 s).
157
+ - `em` e `ate` em segundos ou a palavra. Sem `ate`, o zoom fica até o fim do bloco. Um zoom que começa antes
158
+ do anterior voltar vai direto de um ponto ao outro.
159
+ - Corte no meio do zoom continua com o zoom (no rosto, o da tomada nova). As peças e a legenda desviam do rosto
160
+ do jeito que ele está na tela, já com o zoom.
161
+ - Cada zoom pede um som (whoosh, no meio do movimento) no `sons_sugeridos.json`; `"som": false` tira.
162
+
163
+ ## Borrão (dado privado)
164
+
165
+ `borrar` vale em qualquer bloco. Cada caixa é `[x, y, largura, altura]` (o bloco inteiro) ou tem o tempo
166
+ dela:
167
+
168
+ ```json
169
+ "borrar": [[0.02, 0.10, 0.18, 0.80],
170
+ {"caixa": [0.30, 0.05, 0.40, 0.04], "de": 14.2, "ate": "projeto"}]
171
+ ```
172
+
173
+ - A caixa é em fração do vídeo gravado (o `cut.mp4`; na prova com `arquivo`, do arquivo), de 0 a 1. Não é
174
+ fração da tela: por isso o borrão acompanha o zoom e a moldura sem conta nenhuma.
175
+ - O borrão é **queimado no arquivo**: o build grava o `assets/cut.mp4` do projeto com as caixas borradas (o
176
+ original sem borrão fica no `edit/`). A prévia, o render e quem receber a pasta do projeto só veem o borrão.
177
+ Na prova com `arquivo`, a página usa uma cópia borrada em `assets/gerado/` e o build avisa que o original
178
+ continua em `assets/`: tire o original da pasta antes de mandar o projeto para alguém.
179
+ - Cada caixa entra um quadro antes do `de` e sai um quadro depois do `ate`. Numa imagem, o borrão vale o bloco
180
+ todo.
181
+ - Coisas que aparecem e somem (um menu que abre, uma linha que muda de lugar) pedem uma caixa com o tempo de
182
+ cada uma. Confira no arquivo exportado, quadro a quadro nos trechos de tela, com a conferência de dado pessoal
183
+ de `references/revisao.md`: a folha de quadros sozinha deixa passar.
184
+
185
+ Detalhes da conta e do código: seção "Receitas", no fim desta página.
186
+
187
+ ## Acompanhar a pessoa dentro da tomada
188
+
189
+ O `face_layout.json` mede o rosto por tomada: dentro de uma tomada o enquadramento fica parado. Quase sempre
190
+ basta. Não basta quando a pessoa anda, se inclina muito ou muda de lugar no meio da tomada, e o trecho está com
191
+ zoom (moldura, tela cheia a 1,15 ou mais, um punch-in): aí o rosto escorrega para a borda ou a testa é cortada.
192
+
193
+ Nesse trecho, ponha `"acompanhar": true` no bloco (vale em `tela_cheia` e `moldura`):
194
+
195
+ ```json
196
+ {"cena": "moldura", "de": 7.07, "ate": 10.6, "acompanhar": true},
197
+ {"cena": "tela_cheia", "de": 14.0, "ate": 17.7, "zoom": 1.2, "acompanhar": true,
198
+ "zooms": [{"em": "ééé", "escala": 1.35, "ate": "cortou"}]}
199
+ ```
200
+
201
+ O que o build faz:
202
+
203
+ 1. **Mede o rosto 10 vezes por segundo** no `cut.mp4`, com o detector YuNet da skill (o mesmo do
204
+ `face_layout.py`), pelo `helpers/rastrear_rosto.py`, com o Python da skill. Grava `<EDIT>/rosto_trilha.json`,
205
+ preso ao tempo do `cut.mp4`: refez o corte, ele mede de novo sozinho. Uns segundos por minuto de vídeo. À mão:
206
+ `uv run --directory "<SKILL>" python helpers/rastrear_rosto.py '<EDIT>'`.
207
+ 2. **Suaviza.** Mediana de 5 medidas seguidas. Zona morta: o enquadramento só se mexe quando o centro anda mais de
208
+ 3% da largura (ou o rosto muda mais de 12% de tamanho). Cada mudança vira um movimento de 0,5 s em
209
+ `sine.inOut`, centrado nela: o caminho do rosto na tela é contínuo, sem pulo.
210
+ 3. **Perdeu o rosto** (mão na frente, virou de lado): segura o último ponto bom. Depois de uma perda de 0,3 s ou
211
+ mais, a medida nova só vale quando 2 das 3 seguintes também acham o rosto. Nunca salta para o meio da tela.
212
+ 4. **Recomeça em cada tomada** do `cut_timeline.json`. Tomada sem rosto nenhum fica com o enquadramento dela (o
213
+ build avisa).
214
+ 5. **Anima quadro a quadro**, com a conta da Receita 2 em cada quadro, fora das transições animadas (dados e laço:
215
+ o seek em qualquer ponto acerta). A pessoa recortada (`assets/pessoa.webm`) recebe a mesma transformação, e a
216
+ transição da moldura já termina no rosto acompanhado. Na moldura o tamanho do rosto é o mediano da tomada (o
217
+ quadro não "respira").
218
+ 6. **Confere a cabeça** (rosto e cabelo) dentro do quadro, 10 vezes por segundo. Quando a pessoa vai para a borda
219
+ da gravação e o enquadramento não tem mais para onde ir, o build avisa com o intervalo: não cabe. Diminua o
220
+ zoom, troque para tela cheia ou use `contida` nesse trecho.
221
+
222
+ Em tela cheia a 1,08 sobra só 8% de margem: o acompanhamento aparece com zoom maior ou num punch-in. Numa cena
223
+ própria, use o mesmo `rosto_trilha.json` (`tomadas[].pontos`: `[t, cx, cy, largura, altura, medido]`, frações do
224
+ `cut.mp4`) e anime a caixa em volta do vídeo, nunca o `<video>`.
225
+
226
+ **Quando a janela muda de tamanho, lugar ou proporção**, o enquadramento de dentro é recalculado junto com a caixa
227
+ de fora, na mesma curva. Se só a caixa anda, o rosto desliza para fora do lugar ou a testa some no meio da troca. O
228
+ modelo já faz isso na moldura e na contida; numa cena própria, faça igual.
229
+
230
+ ## Quando não cabe
231
+
232
+ Às vezes nenhuma posição mostra a região obrigatória inteira (gesto muito largo, pessoa filmada de lado, vídeo
233
+ horizontal indo para 9:16). Não force. Na ordem:
234
+
235
+ 1. Diminua o zoom (o mínimo é o que enche a tela sem borda).
236
+ 2. Mude o destino: tela cheia no lugar da moldura, moldura maior, outro lado.
237
+ 3. Mostre a imagem inteira contida, com margem e um fundo de apoio: o bloco `{"cena": "contida"}` (a própria
238
+ gravação desfocada atrás, o padrão; `"fundo": "papel"` ou uma cor).
239
+
240
+ **Vídeo gravado em pé que vai sair em 16:9** é o caso mais comum de "não cabe": o corte guarda só uma faixa da
241
+ altura (uns 32%) e amplia; a pessoa aparece em close, só a cabeça, e na moldura 16:9 ainda mais perto. O
242
+ `build.py` avisa. Antes de montar, proponha o 9:16; se o 16:9 for obrigatório, use a `contida` (item 3) nos
243
+ trechos em que o corpo ou as mãos importam. O build enquadra o rosto pelo retângulo que o vídeo ocupa de verdade
244
+ dentro da tela (um corte em pé num 16:9, 4:5 ou 1:1 passa da tela em cima e embaixo), então o rosto não se perde. Na moldura 16:9 a legenda (quando ligada com `na_moldura`) fica na
245
+ área livre ao lado do quadro, sem atravessar a borda dele.
246
+
247
+ Nunca esprema a largura da pessoa para caber. Nunca deixe faixa vazia ou preta fora da imagem.
248
+
249
+ A conta para encher a tela sem distorcer: fonte com W x H, alvo com w x h. O fator é
250
+ `k = max(w / W, h / H)`. Recorte na fonte uma janela de `w / k` por `h / k`, centrada na região obrigatória e sem
251
+ passar das bordas do vídeo original. Se a janela está se mexendo, faça a conta de novo em todo quadro.
252
+
253
+ ## Composição em planos (2,5D)
254
+
255
+ Dá presença a uma palavra ou a um objeto em volta da pessoa. É o efeito que mais parece "edição cara", e o que
256
+ mais fica feio quando o recorte não aguenta. Só entra com o teste de recorte aprovado (próxima seção).
257
+
258
+ A peça pronta do texto atrás da pessoa está no `references/animacao-catalogo.md`. Aqui ficam as decisões.
259
+
260
+ - **Três planos.** Fundo: o cenário original, ou um cenário calmo. Meio: a pessoa, que é o destaque. Frente: um
261
+ elemento de apoio, que só entra na hora em que serve.
262
+ - **A palavra atrás do corpo tem que ser lida.** Pode ficar em parte escondida pela pessoa, desde que sobrem
263
+ letras à vista para reconstruir a palavra sem esforço (a primeira letra sempre à vista e mais da metade das
264
+ letras inteiras). Se o corpo cobre demais quando ela se mexe, suba, desça ou troque o lado da palavra.
265
+ - **O objeto fica perto do que está sendo falado**, sem tampar olhos, boca e gestos: é o campo `frente` da peça
266
+ (`references/animacao-catalogo.md`, peça 10), num canto de baixo, do lado oposto ao rosto; o build avisa se ele
267
+ passar na frente do rosto.
268
+ - **Cada plano anda um pouco e numa medida diferente**, para revelar a profundidade: o de trás anda menos, o da
269
+ frente anda mais. A peça `atras_da_pessoa` já faz: o fundo (a gravação, com a pessoa junto, porque saem do mesmo
270
+ vídeo) se aproxima 1,5% e desliza 6 px, a palavra desliza 36 px e a `frente` (o objeto na frente da pessoa) 80 px,
271
+ crescendo 4%. Sombras coerentes com a luz da gravação.
272
+ - **Cada elemento entra numa palavra**, e só um por vez. Passada a ênfase, tudo sai e a câmera original volta.
273
+ Nada de pessoa recortada o vídeo inteiro.
274
+ - **Legenda numa faixa própria**, longe da palavra grande e da interface do Reels. Onde a palavra escreve a
275
+ fala, a legenda sai.
276
+ - **Sem recorte utilizável:** componha nas áreas livres ao lado da pessoa e não prometa texto atrás do corpo.
277
+ - **Nome certo na entrega:** "composição 2,5D em camadas". Não é 3D.
278
+
279
+ Na amostra, mostre o efeito entrando, a pessoa se movendo com ele na tela e o efeito saindo. No arquivo exportado,
280
+ confira a borda do recorte, o sincronismo com a fala e se a pessoa continua no centro.
281
+
282
+ ## Portão do recorte (teste de uns 5 s)
283
+
284
+ Recortar a pessoa do fundo é caro e pode falhar no cabelo, nos dedos e no movimento. Antes de rodar o recorte
285
+ num trecho longo, de trocar o cenário sem contorno ou de pôr qualquer coisa atrás da pessoa, faça um teste curto
286
+ e mostre. Este é um ponto em que você para e espera o ok mesmo com o resto autorizado. Só siga sem mostrar se a
287
+ pessoa disse com todas as letras que não quer ver o teste; mesmo assim ele roda e você confere pelos critérios.
288
+
289
+ Tela verde curta com o contorno branco aprovado: o próprio trecho é o teste. Confira pelos critérios e siga.
290
+
291
+ 1. **Confira se o recorte roda neste computador** antes de prometer:
292
+ `uv run --directory "<SKILL>" python helpers/matte.py --check`. Falhou: diga o que falta. Nada de serviço
293
+ pago, envio do vídeo para fora ou modelo baixado sem a pessoa autorizar.
294
+ 2. **Escolha uns 5 s difíceis**: cabelo solto contra o fundo, mãos se mexendo, a pessoa se movendo e, se houver,
295
+ um objeto cruzando na frente dela.
296
+ 3. **Recorte só esse trecho**, no tamanho de entrega e pelo mesmo caminho do final:
297
+ `python3 ferramentas/pessoa_recortada.py --edit '<EDIT>' --de 12.0 --ate 17.0`
298
+ 4. **Olhe a borda, não só se o fundo sumiu.** Monte a pessoa em cima de um fundo branco, de um preto e da camada
299
+ que vai passar por trás. Para os dois primeiros:
300
+
301
+ ```bash
302
+ ffmpeg -f lavfi -i color=white:s=1080x1920:d=5 -f lavfi -i color=black:s=1080x1920:d=5 \
303
+ -c:v libvpx-vp9 -i assets/pessoa.webm \
304
+ -filter_complex "[2:v]split[p1][p2];[0:v][p1]overlay=shortest=1[a];[1:v][p2]overlay=shortest=1[b];[a][b]hstack" \
305
+ -c:v libx264 -pix_fmt yuv420p quadros/teste_recorte.mp4
306
+ ```
307
+
308
+ A terceira é a própria amostra no estúdio. Toque as três em velocidade normal e depois quadro a quadro
309
+ (`helpers/tira_de_quadros.py --fps 30`).
310
+ 5. **Critérios.** Cabelo e dedos presentes. Ombros sem encolher nem sumir. Nenhum buraco no rosto ou no corpo.
311
+ Sem borda dupla e sem pedaço do fundo antigo grudado. O contorno fica firme: não pulsa e não deixa rastro
312
+ quando ela se mexe. O texto de trás desaparece atrás do corpo e volta a aparecer onde é fundo. Borda com a suavidade da imagem, sem aura clara.
313
+ 6. **Confira a transparência abrindo o arquivo de verdade.** Nem o nome do codec nem o que o tocador mostra provam
314
+ que ela existe. O
315
+ ffmpeg só lê o alfa do VP9 com o decodificador `libvpx-vp9` pedido antes do `-i`; sem ele, o alfa sai cheio
316
+ e parece que não tem transparência:
317
+
318
+ ```bash
319
+ ffmpeg -hide_banner -ss 2 -c:v libvpx-vp9 -i assets/pessoa.webm -frames:v 1 \
320
+ -vf "alphaextract,signalstats,metadata=print:key=lavfi.signalstats.YMIN,metadata=print:key=lavfi.signalstats.YMAX" \
321
+ -f null - 2>&1 | grep signalstats
322
+ ```
323
+
324
+ Tem que sair `YMIN=0` e `YMAX=255`: partes transparentes e partes cheias. Erro "Requested planes not
325
+ available" quer dizer que o arquivo não tem canal de transparência.
326
+ 7. **Mostre o teste**, com o que ele tem de limite, e espere.
327
+
328
+ **Não passou:** tente uma correção localizada e explique o motivo (recortar de novo o trecho, outro lado, outro
329
+ trecho de 5 s). Se continuar ruim, descarte o efeito para aquela composição, diga o limite e proponha a moldura
330
+ com o fundo original ou uma regravação (fundo liso e sem nada parecido com a pele ou o cabelo, luz de frente).
331
+ Nunca disfarce com brilho, desfoque pesado ou um retângulo por cima. Recorte exigido e impossível: diga, dê a
332
+ alternativa e não dê a tarefa como feita.
333
+
334
+ **Passou:** recorte o resto e reaproveite. O recorte fica guardado em `<EDIT>/renders/matte` e o
335
+ `assets/pessoa.json` diz que trecho ele cobre. Mudar só texto ou posição não pede recorte novo. Guarde a cópia
336
+ com transparência (`pessoa.webm`) separada da peça final já montada.
337
+
338
+ Três coisas diferentes, que só se trocam montando de novo: um vídeo que já tem a transparência dentro (o
339
+ `pessoa.webm`), uma pasta de imagens PNG transparentes e um vídeo preto e branco que serve de máscara. MP4 comum (H.264) não guarda transparência. Máscara
340
+ geométrica (retângulo, oval) não é recorte de fundo, e você não chama de recorte.
341
+
342
+ ## Comparar (antes e depois)
343
+
344
+ Mostra uma diferença de verdade, sem truque de montagem:
345
+
346
+ ```json
347
+ {"cena": "comparar", "de": 10.6, "ate": 14.0, "modo": "alternando", "trocas": ["palavra"], "som": "igualado",
348
+ "a": {"arquivo": "assets/cru.mp4", "inicio": 15.0, "rotulo": "Gravação crua"},
349
+ "b": {"arquivo": "corte", "inicio": 10.6, "rotulo": "Corte da skill"}}
350
+ ```
351
+
352
+ - **A mesma situação dos dois lados.** Antes de montar, confira que os dois pedaços mostram o mesmo momento; se não
353
+ mostram, diga e não monte como confronto. Dois trechos do mesmo arquivo (`inicio` diferente) ou do próprio corte
354
+ (`"arquivo": "corte"`) também valem.
355
+ - **Mesma escala e mesma velocidade.** Os dois aparecem inteiros, do mesmo tamanho, tocando juntos. Proporção ou
356
+ resolução diferente vem do arquivo, e o build avisa (nada é esticado nem piorado de propósito).
357
+ - **`modo`**: `lado_a_lado` (em linha ou empilhado, o que deixar a imagem maior; pode passar da zona segura dos
358
+ lados, porque não é texto) ou `alternando` (no mesmo lugar, trocando nas `trocas`, pelo menos 0,8 s cada).
359
+ - **Rótulo literal**, obrigatório: o que o lado é, sem opinião. "Melhor", "perfeito", "ruim" geram aviso.
360
+ - **Som**: `voz` (o padrão: a fala continua, os lados mudos); `a` ou `b` (só aquele lado; a voz do corte sai do
361
+ trecho e o build avisa a fala que fica muda: deixe esse espaço no corte); `igualado` (alternando: o som do lado
362
+ que está na tela, os dois no mesmo volume percebido, medido; o mais alto desce, nenhum sobe).
363
+ - A legenda sai no bloco. Não ponha texto por cima do detalhe que se compara.
364
+ - Na entrega, diga o que a comparação mostra e o que ela não prova.
365
+
366
+ ## Mudar o formato de uma edição aprovada
367
+
368
+ Levar um vídeo aprovado de 9:16 para 16:9 (ou para 4:5, 1:1) sem perder nada. O projeto aceita os quatro
369
+ (`"formato"`: `9:16`, `16:9`, `4:5` com 1080x1350, `1:1` com 1080x1080).
370
+
371
+ 1. **Versão separada.** Copie a pasta do projeto (`sala` para `sala-16x9`) e troque o `formato`. A aprovada não
372
+ é tocada. O nome do arquivo novo diz o formato. Gravação em pé indo para 16:9 vira close (seção "Quando não
373
+ cabe").
374
+ 2. **Fica igual:** a duração, a ordem dos blocos, a fala, a oferta e os textos aprovados.
375
+ 3. **Recomponha, não encolha.** Pessoa centralizada em cada recorte, acompanhando o movimento (seções acima).
376
+ Títulos e legendas reorganizados para o espaço novo. Tela e produto continuam legíveis. Imagem que não cabe
377
+ sem perder informação ganha outro arranjo com o mesmo material (contida, tela dividida).
378
+ 4. **Margens da rede de destino.** Reels 9:16 é conhecida: texto em y 230 a 1530 e x 140 a 940. O 4:5 (x 100 a
379
+ 960, y 110 a 1220) e o 1:1 (x 90 a 970, y 90 a 980) do projeto são margens folgadas, **a conferir na rede**: o
380
+ build avisa em todo build e a entrega diz que alguém ainda precisa conferir na rede. Para outra rede, deixe
381
+ margens folgadas (texto longe das bordas, sobretudo embaixo e à direita no vertical) e anote o mesmo.
382
+ 5. **Amostras** nos pontos em que a proporção nova mais aperta e nas passagens de um arranjo para outro. Espere
383
+ só se a pessoa pediu para aprovar.
384
+
385
+ ## Tela verde: o recorte da pessoa
386
+
387
+ O recorte vem desta skill (modelo selfie_multiclass, com fluxo óptico e filtro guiado), feito trecho por trecho
388
+ do `cut_timeline.json`: o filtro recomeça em cada corte e a forma da tomada anterior não vaza. Não use o
389
+ `npx hyperframes remove-background` para isso: ele deixa halo no cabelo e a cor do fundo antigo na borda.
390
+
391
+ 1. Avise: "O recorte leva uns 3 minutos por minuto de vídeo na primeira vez" (num Mac com chip Apple livre; com
392
+ o computador ocupado pode passar de 10 minutos por minuto). Rode em segundo plano.
393
+ 2. No projeto, só o trecho da tela verde:
394
+ `python3 ferramentas/pessoa_recortada.py --edit '<EDIT>' --de 28.03 --ate 32.3`
395
+ A ferramenta usa a skill anotada no `projeto.json` (`"skill"`) e diz na primeira linha qual usou; confira
396
+ que é esta skill (outra instalada no computador pode ser uma versão antiga). `--skill '<SKILL>'` força.
397
+ Sem `--de/--ate` monta o vídeo todo, o que demora bem mais. Trecho longo: passe antes pelo portão do recorte.
398
+ 3. Sai `assets/pessoa.webm` (fundo transparente) e `assets/pessoa.json` (o trecho que ele cobre e onde a pessoa
399
+ encosta na borda em cada tomada). O recorte fica guardado em `<EDIT>/renders/matte`: mudar o trecho depois é
400
+ rápido. Tela verde fora do trecho montado: o `build.py` para e diz o comando certo.
401
+ 4. O `cut.mp4` da pasta edit tem que ser o arquivo de verdade, nunca um atalho (a ferramenta recusa).
402
+ 5. Erro falando de onnxruntime ou do modelo: a instalação da skill está incompleta. Peça para rodar o instalador
403
+ dela de novo.
404
+
405
+ O `build.py` usa o `pessoa.json` para o lado que a câmera cortou (ombro, braço) encostar na borda da tela. Se
406
+ ele avisar que a câmera corta o corpo do lado de dentro, troque de lado ou use `centro`.
407
+
408
+ ## Passo a passo
409
+
410
+ 1. Leia a fala com `python3 build.py palavras` (mostra palavras, tempos e os cortes) e marque: gancho, prova,
411
+ explicação, chamada. Toque os trechos e marque as regiões obrigatórias.
412
+ 2. Conte o plano de blocos para a pessoa (regras acima; autorização em camadas).
413
+ 3. Escreva os `blocos`. As animações de cada bloco seguem `references/animacao.md`.
414
+ 4. Amostra do trecho mais difícil, 8 a 15 s: a troca de cena mais exigente, o gesto mais largo e a volta à
415
+ pessoa. `python3 build.py amostra 17.9 27.9`, depois `python3 build.py hf lint` e `python3 build.py hf check`.
416
+ 5. Abra no estúdio (`references/estudio.md`). Sem render. Toque com som no tamanho do celular e passe a agulha
417
+ quadro a quadro em cada troca.
418
+ 6. Com a amostra certa: `python3 build.py completo`, `check`, estúdio, e o render só no fim (`--quality delivery`).
419
+ 7. Confira o arquivo exportado nas trocas, com a tira de quadros a 30 qps.
420
+
421
+ ## O que conferir (tocando, e depois no arquivo exportado)
422
+
423
+ Vários quadros bonitos podem esconder um caminho ruim entre eles. Toque primeiro; depois olhe as passagens em
424
+ sequência densa de quadros. Anote o intervalo que você olhou.
425
+
426
+ - **Em qualquer momento:** a cabeça e os gestos que importam cabem. O rosto não salta de lugar na troca. A voz
427
+ continua casada com a boca.
428
+ - **Moldura:** o rosto inteiro dentro do quadro, olhando para dentro dele, sem mostrar só o peito; o papel
429
+ quadriculado (ou o vídeo desfocado) atrás; a borda lilás só depois que o quadro fechou; nenhuma peça na frente
430
+ do rosto enquanto o quadro fecha; a troca acontecendo no corte.
431
+ - **Tela cheia:** legenda no peito, sem tocar no queixo; peça em cima da cabeça sem cortar a testa.
432
+ - **Prova:** o rótulo legível, o dado privado borrado, a prova inteira à vista e legível no celular.
433
+ - **Tela verde e planos:** borda do cabelo e das mãos sem pedaço do fundo antigo; nada do cenário grudado na
434
+ pessoa (estante, banco do carro); o lado cortado encostado na borda; o fundo trocando no segundo certo; a
435
+ palavra atrás do corpo legível enquanto a pessoa se mexe; a frente sem tampar o rosto.
436
+ - **Acompanhar:** o rosto no lugar do começo ao fim da tomada, sem tremer nem dar pulo; nenhum aviso de cabeça
437
+ fora do quadro sem resposta.
438
+ - **Contida e comparar:** a gravação inteira à vista, com margem igual; os dois lados do mesmo tamanho, no mesmo
439
+ momento, com o rótulo certo; o som de um lado só (ou os dois no mesmo volume).
440
+ - Nada cortado na borda da tela, nada fora da zona segura, nenhuma faixa vazia.
441
+
442
+ ## Pegadinhas que já custaram retrabalho
443
+
444
+ - **Corte dentro da transição da moldura usa o enquadramento da moldura.** Se a câmera troca de tomada enquanto o
445
+ quadro ainda está fechando, o `tl.set` de tela cheia vence a animação e a moldura mostra o peito. O modelo já
446
+ trata; se escrever à mão, cada corte usa o enquadramento do bloco onde ele cai.
447
+ - **Corte arredondado pega o rosto da tomada errada.** O tempo do corte com 3 casas (21,933) fica antes do
448
+ começo do trecho novo (21,9333). O modelo procura o rosto com 2 ms de folga para o lado da tomada nova.
449
+ - **Anime clip-path e transform, nunca left/top/width/height.** A moldura é um `clip-path: inset(...)` no
450
+ `#frame` do tamanho da tela e um `x, y, scale` no `#inner`. left/top travam no pixel inteiro e o lint reclama.
451
+ - **Vídeo com tempo não se anima.** O `<video>` com `data-start` fica parado; o que mexe é a caixa em volta
452
+ (`#inner`, `.pw`, `.pw2`). E nunca ponha `data-start` numa caixa que tem um `<video data-start>` dentro.
453
+ - **Estado do quadro 0 com um fromTo curto**, não com `tl.set(..., 0)`: o set em 0 pode sumir quando o seek
454
+ volta ao começo.
455
+ - **Recorte feito sem o cut_timeline** carrega a forma da tomada anterior por uns 4 quadros depois de cada corte.
456
+ Rode sempre pelo `pessoa_recortada.py` (ele usa o timeline).
457
+ - **Tela verde precisa do mesmo tempo do corte.** O `pessoa.webm` tem os mesmos quadros do `cut.mp4`; o bloco
458
+ usa `data-media-start` igual ao início do bloco. Cortou de novo? Rode o recorte de novo.
459
+ - **Alfa do VP9 no ffmpeg:** sem `-c:v libvpx-vp9` antes do `-i`, o ffmpeg lê o `pessoa.webm` sem transparência.
460
+ - **O estúdio pode piscar a camada de baixo numa emenda.** No arquivo exportado não aparece. O arquivo é a
461
+ referência.
462
+
463
+ ## Erros comuns
464
+
465
+ - Moldura em cima da prova (a prova some num quadrinho).
466
+ - Moldura longa demais, decorativa o vídeo inteiro, ou entrando no meio de uma frase sem corte.
467
+ - Legenda ligada na moldura junto com a animação (duas coisas para ler).
468
+ - Print com dado privado de outra pessoa sem borrão.
469
+ - Tela verde sem avisar que o recorte demora, ou com moldura junto.
470
+ - Texto atrás da pessoa sem teste de recorte, ou chamado de 3D.
471
+ - Enquadramento conferido num quadro parado só.
472
+ - Mudar de formato por cima da versão aprovada.
473
+
474
+ ## Receitas: enquadramento, moldura, prova e tela verde
475
+
476
+ O `build.py` do projeto-modelo já faz tudo isto. Use esta página para entender o que ele fez, conferir um
477
+ quadro estranho ou escrever uma cena sob medida à mão.
478
+
479
+ ### 1. Onde está o rosto
480
+
481
+ Esta skill mede o rosto com o YuNet em até 40 quadros de cada trecho do corte e grava
482
+ `<EDIT>/face_layout.json`:
483
+
484
+ ```json
485
+ {"segments": [{"id": "r06", "start": 18.633333, "end": 21.933333,
486
+ "face": {"x0": 0.2017, "y0": 0.3629, "x1": 0.3598, "y1": 0.4864, "eyes_y": 0.4096, "mouth_y": 0.455}}]}
487
+ ```
488
+
489
+ Coordenadas em fração do quadro do `cut.mp4` (0 a 1). Um trecho = uma tomada, então o rosto só muda de
490
+ lugar num corte. Trecho sem rosto (`"face": null`, gravação de tela) usa o último rosto visto.
491
+
492
+ Comando, se faltar: `uv run --directory "<SKILL>" python helpers/face_layout.py --edit-dir '<EDIT>'`.
493
+ Ele também imprime uma sugestão de altura para gancho, legenda e chamada.
494
+
495
+ **Pegadinha do arredondamento:** o corte em 21,933 (3 casas) cai 0,3 ms ANTES do trecho novo (21,9333) e
496
+ pegaria o rosto da tomada anterior. Procure o rosto com folga para o lado novo:
497
+ `s.start - 0.002 <= t < s.end - 0.002`.
498
+
499
+ ### 2. Enquadrar pelo rosto (tela cheia e moldura)
500
+
501
+ O vídeo inteiro fica dentro de `#inner` (1080 x 1920, `transform-origin: 0 0`) e a caixa visível é o
502
+ `clip-path` do `#frame`. Para uma caixa `(bx, by, bw, bh)` e o rosto `(cx, cy)` = centro, `fw` = largura:
503
+
504
+ ```python
505
+ if caixa == tela_inteira:
506
+ z = zoom # 1,08 a 1,12 na tela cheia; 1 na prova
507
+ else: # moldura: rosto com uns 40% da largura da caixa
508
+ z = max(0.40 * bw / (fw * W), bw / W, bh / H)
509
+ x = clamp(bw / 2 - z * cx * W, bw - z * W, 0) # rosto no meio da largura, sem mostrar borda preta
510
+ y = clamp(0.42 * bh - z * cy * H, bh - z * H, 0) # rosto a 42% da altura da caixa
511
+ inner = {"x": x + bx, "y": y + by, "scale": z}
512
+ ```
513
+
514
+ Com `zoom` 1 na tela cheia o `x` trava em 0 (o vídeo já tem a largura da tela): o rosto não centraliza.
515
+ Por isso a tela cheia usa 1,08 a 1,12. A prova fica em 1 de propósito: a prova aparece inteira.
516
+
517
+ ### 3. A moldura
518
+
519
+ ```css
520
+ #bg{position:absolute;inset:0;opacity:0;background-color:#fffdfd;
521
+ background-image:linear-gradient(#e6ddf8 2px,transparent 2px),linear-gradient(90deg,#e6ddf8 2px,transparent 2px);background-size:60px 60px}
522
+ #borda{position:absolute;left:520px;top:980px;width:400px;height:540px;border-radius:40px;opacity:0;
523
+ box-shadow:0 0 0 6px #c7b7ef,0 16px 0 2px #665080,0 30px 50px rgba(53,44,64,.35)}
524
+ #frame{position:absolute;left:0;top:0;width:1080px;height:1920px;overflow:hidden}
525
+ #inner{position:absolute;left:0;top:0;width:1080px;height:1920px;transform-origin:0 0}
526
+ ```
527
+
528
+ Ordem das camadas: `#bg` (papel), `#borda` (o aro fica por baixo do quadro e aparece em volta), `#frame`.
529
+
530
+ Entrada (no corte em 21,933 de uma amostra que começa em 17,9, então 4,033 na timeline):
531
+
532
+ ```js
533
+ tl.set("#inner",{x:0,y:-78.2,scale:1.1},4.033); // tela cheia da tomada nova
534
+ tl.fromTo("#frame",{clipPath:"inset(0px 0px 0px 0px round 0px)"},
535
+ {clipPath:"inset(980px 160px 400px 520px round 40px)",duration:0.7,ease:"power3.inOut",immediateRender:false},4.033);
536
+ tl.fromTo("#inner",{x:0,y:-78.2,scale:1.1},{x:435.9,y:442.8,scale:0.9371,duration:0.7,ease:"power3.inOut",immediateRender:false},4.033);
537
+ tl.fromTo("#borda",{opacity:0},{opacity:1,duration:0.25,immediateRender:false},4.583); // aro só quando o quadro fechou
538
+ tl.fromTo("#bg",{opacity:0},{opacity:1,duration:0.6,immediateRender:false},4.033);
539
+ ```
540
+
541
+ O `inset` é `top right bottom left round raio`: `inset(y, W - x - w, H - y - h, x)`. O quadro e o vídeo
542
+ andam juntos na mesma curva (`power3.inOut`, 0,7 s), então a pessoa "encolhe para dentro" do quadro.
543
+
544
+ Saída no corte (troca seca, o corte esconde o salto):
545
+ ```js
546
+ tl.to("#bg",{opacity:0,duration:0.2,immediateRender:false},t - 0.05);
547
+ tl.set("#borda",{opacity:0},t);
548
+ tl.set("#frame",{clipPath:"inset(0px 0px 0px 0px round 0px)"},t);
549
+ tl.set("#inner",{/* tela cheia da tomada nova */},t);
550
+ ```
551
+ Saída fora de corte: o mesmo caminho da entrada ao contrário, em 0,55 s, e o papel some 0,4 s depois.
552
+
553
+ **O que vence nos 0,7 s em que o quadro fecha: o quadro.** Peça do catálogo cuja palavra cai nesse tempo entra
554
+ quando ele termina de fechar (o build avisa com o tempo novo); cena própria recebe
555
+ `window.__cenas[...].moldura.fechada_em` e o build avisa quando ela começa antes. A peça chega uns 0,3 a 0,6 s
556
+ depois da palavra, o que é melhor que passar na frente do rosto ainda grande.
557
+
558
+ **Fundo desfocado** (`"fundo": "desfocado"` no bloco): o build grava `assets/gerado/cut_fundo.mp4` (o corte
559
+ pequeno, desfocado e sem som) e põe atrás do quadro, no tempo do corte, entrando junto com o papel. É outro
560
+ arquivo, então o lint não acusa mídia repetida. Painel de vidro fosco ou outro arranjo continua sendo cena
561
+ própria.
562
+
563
+ Cada corte dentro do bloco troca o enquadramento com um `tl.set("#inner", ...)` no quadro do corte, usando
564
+ a caixa do bloco onde o corte cai. **Corte no meio da transição de entrada usa a moldura** (se usar a tela
565
+ cheia, o set vence o tween e o quadro mostra o peito).
566
+
567
+ No 16:9 a caixa padrão é x 1080, y 120, 720 x 840 (à direita) e a área livre fica à esquerda (x 100 a 1020).
568
+
569
+ ### 4. A prova
570
+
571
+ Gravação que já mostra a tela (câmera filmando o iPad): bloco `prova` sem `arquivo`, zoom 1, a imagem
572
+ inteira. Print ou vídeo de tela da pessoa: `arquivo`.
573
+
574
+ ```html
575
+ <div class="pvw" id="pvw1"> <!-- caixa sem tempo: é ela que o zoom mexe -->
576
+ <video id="pr1" class="midia" src="assets/reel.mp4" muted playsinline data-start="10.133" data-duration="2.734"
577
+ data-media-start="9.9" data-track-index="41"></video>
578
+ </div>
579
+ ```
580
+ ```css
581
+ .midia{position:absolute;left:0;top:0;width:100%;height:100%;object-fit:cover}
582
+ .midia.borrada{filter:blur(30px) brightness(.55)} /* encaixe "inteiro": cópia borrada atrás */
583
+ .midia.inteira{object-fit:contain}
584
+ .pvw{position:absolute;inset:0;transform-origin:0 0}
585
+ ```
586
+
587
+ A imagem ou o vídeo com `data-start` é um clip: o HyperFrames mostra e esconde sozinho no tempo certo. O
588
+ `data-media-start` é o `inicio` do bloco (e anda junto quando a amostra começa no meio da prova). O rótulo em
589
+ cima vem do campo `rotulo` do bloco (um `rotulo` do catálogo em y 250). O borrão não é mais uma camada por cima:
590
+ é queimado no arquivo (seção "Borrão").
591
+
592
+ ### 5. A tela verde
593
+
594
+ **O recorte.** `python3 ferramentas/pessoa_recortada.py --edit '<EDIT>' --de 28 --ate 32.3` roda o `helpers/matte.py` desta
595
+ skill (selfie_multiclass em ONNX, fluxo óptico entre quadros, filtro guiado na borda, um trecho por
596
+ tomada do `cut_timeline.json`) e junta os recortes com a cor do `cut.mp4`:
597
+
598
+ ```
599
+ ffmpeg -i cut.mp4 -f concat -safe 0 -i mattes.txt \
600
+ -filter_complex "[0:v]setpts=N/(30*TB),format=rgba[c];[1:v]setpts=N/(30*TB),format=gray,scale=1080:1920[m];[c][m]alphamerge,format=yuva420p[v]" \
601
+ -map "[v]" -c:v libvpx-vp9 -pix_fmt yuva420p -b:v 0 -crf 20 -auto-alt-ref 0 -metadata:s:v:0 alpha_mode=1 assets/pessoa.webm
602
+ ```
603
+
604
+ O `cut.mp4` da pasta edit tem que ser o arquivo de verdade (atalho faz o matte.py ignorar o timeline e
605
+ recortar tudo como um trecho só, e a forma da tomada anterior vaza na seguinte). O `hyperframes
606
+ remove-background` não serve: deixou halo no cabelo e a faixa de luz do fundo entre a barba e o pescoço.
607
+
608
+ **A cena.** (bloco de 28,033 a 32,3 s, `posicao: "esquerda"`, pessoa que a câmera corta à esquerda)
609
+ ```html
610
+ <video id="tv4" class="midia" src="assets/fundo.mp4" muted playsinline data-start="28.033" data-duration="4.267" data-media-start="0" data-track-index="1"></video>
611
+ <div class="pw" style="transform:translate(0px,729.6px) scale(0.62)">
612
+ <div class="pw2" id="pw4" style="filter:drop-shadow(8.1px 0px 0 #fff) drop-shadow(-8.1px 0px 0 #fff) drop-shadow(0px 8.1px 0 #fff)
613
+ drop-shadow(0px -8.1px 0 #fff) drop-shadow(5.6px 5.6px 0 #fff) (...as outras 3 diagonais...) drop-shadow(0 23px 29px rgba(0,0,0,.45))">
614
+ <video id="pessoa4" src="assets/pessoa.webm" muted playsinline data-start="28.033" data-duration="4.267" data-media-start="28.033" data-track-index="2"></video>
615
+ </div></div>
616
+ ```
617
+ ```js
618
+ tl.fromTo("#bg",{opacity:0},{opacity:1,duration:0.3,immediateRender:false},28.033);
619
+ tl.to("#frame",{opacity:0,duration:0.25,immediateRender:false},28.033); // o vídeo com o fundo antigo some
620
+ tl.fromTo("#pw4",{opacity:0,y:40},{opacity:1,y:0,duration:0.3,ease:"power3.out",immediateRender:false},28.033);
621
+ ```
622
+ Da tela verde para a moldura, o quadro já nasce no lugar da moldura e aparece (0,25 s), sem passar pela tela
623
+ cheia. Se o `pessoa.webm` foi montado só de um trecho (`--de/--ate`), o `data-media-start` desconta o
624
+ `inicio` gravado no `pessoa.json`.
625
+
626
+ - `.pw` é uma caixa SEM tempo com a posição fixa (pode ter `transform` no CSS porque o GSAP não mexe nela);
627
+ `.pw2` é quem o GSAP anima; o `<video>` com tempo fica quieto dentro. `data-media-start` do `pessoa.webm`
628
+ é o início do bloco no tempo do corte (os dois vídeos têm os mesmos quadros).
629
+ - Posição: escala `altura` (0,62 no canto, 0,8 no centro), pés na borda de baixo (`ty = H - s*H`) e o
630
+ centro do rosto em 70% (direita), 30% (esquerda) ou 50% (centro) da largura.
631
+ - Lado cortado pela câmera: o `pessoa.json` diz em quantos quadros a pessoa encosta na esquerda e na
632
+ direita do quadro (`touch_left`, `touch_right`). Pessoa no canto direito que encosta na direita: a borda
633
+ direita do vídeo encosta na borda da tela (o ombro cortado some na borda). Encosta do lado de dentro:
634
+ aparece um corte reto no meio da tela, então o `build.py` avisa para trocar de lado ou usar `centro`.
635
+ - Contorno branco: 8 `drop-shadow` sem desfoque em volta (5 px na tela, dividido pela escala) e uma sombra
636
+ suave embaixo. Esconde a franja fina que o recorte deixa na borda.
637
+ - O fundo pode ser imagem ou vídeo; `encaixe: "inteiro"` mostra o print inteiro por cima de uma cópia
638
+ borrada e escura dele mesmo.
639
+
640
+ ### 6. Legenda em cada cena
641
+
642
+ - Tela cheia e prova: uma linha, no máximo 3 palavras (`max_palavras`) e 14 letras (`max_letras`), nunca
643
+ duas na tela, quebra em vírgula, ponto ou pausa de 0,6 s. Legenda de uma palavra só que ficaria menos de
644
+ 0,3 s na tela junta com a vizinha. Altura: 300 px abaixo do queixo, entre y 1100 e 1400 (no peito).
645
+ Mesma altura enquanto a diferença for menor que 40 px (sem tremida entre uma legenda e a próxima).
646
+ - Estilo (`legenda.estilo`): `padrao` é caixa alta, Montserrat 900 60 px branca com contorno de 10 px
647
+ (`-webkit-text-stroke` + `paint-order: stroke fill`); `discreta` é menor (44 px), sem caixa alta, peso 700,
648
+ num fundo escuro leve arredondado, até 22 letras. Legenda escrita à mão (papelaria), manchete ou impacto é
649
+ cena própria.
650
+ - Moldura: sem legenda (a animação explica). Palavra a menos de 0,3 s antes da troca também sai, para a legenda
651
+ não piscar antes da transição. Com `na_moldura`, no 9:16 a legenda fica logo acima do quadro e no 16:9 na
652
+ área livre ao lado dele, sem atravessar a borda.
653
+ - Tela verde: legenda no peito da pessoa recortada.
654
+ - Peça ocupando o lugar da legenda: a legenda desce para 1420 ou sobe para 1120.