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,335 @@
1
+ # Revisão sem retrabalho
2
+
3
+ Para quando o vídeo já existe e precisa de ajuste, diagnóstico ou conferência antes da entrega. A regra geral:
4
+ achar a causa, mexer no mínimo, conferir o que mudou e o que não podia mudar, e dizer a verdade sobre o que foi
5
+ feito.
6
+
7
+ | a pessoa diz | seção |
8
+ |---|---|
9
+ | "tá poluído", "tá confuso", "o que eu tiro?" | Diagnóstico só de leitura |
10
+ | "entre 00:12 e 00:18, arruma tal coisa" | Conserto num trecho |
11
+ | "de novo o mesmo erro" | Tentativa repetida |
12
+ | "tem chiado", "a voz sobe e desce" | Voz |
13
+ | "confere a legenda antes de eu postar" | Legendas checadas no áudio |
14
+ | "não pode aparecer nome de cliente", "confere se não vazou nada", vídeo com tela gravada ou borrão | Dado pessoal no arquivo exportado |
15
+ | "tenho uma pasta cheia de arquivo, o que uso?" | Triagem dos materiais |
16
+ | "faz um antes e depois" | Comparação justa |
17
+ | "quanto isso custou?" | Custo, sem inventar |
18
+
19
+ ## Ordem de prioridade
20
+
21
+ Quando há vários problemas, nesta ordem (a não ser que a pessoa destaque outra coisa):
22
+
23
+ 1. sentido e informação (o que é dito e mostrado está certo e fiel ao material);
24
+ 2. voz e sincronia;
25
+ 3. enquadramento e leitura;
26
+ 4. acabamento.
27
+
28
+ ## Cada problema em quatro partes
29
+
30
+ - **Onde:** o intervalo ou a frase, com o tempo conferido no vídeo.
31
+ - **O que está errado:** separe defeito (texto errado, palavra cortada, rosto coberto) de preferência nova ("quero
32
+ mais rosa").
33
+ - **A mudança:** algo que dá para conferir depois ("a legenda sobe 80 px entre 00:12 e 00:15").
34
+ - **O que preservar:** o que não pode mudar junto.
35
+
36
+ "Não ficou bom" sem detalhe: olhe o vídeo e aponte problemas concretos. Só pergunte a intenção se houver saídas
37
+ que não combinam entre si. Não invente defeito para justificar mais uma rodada.
38
+
39
+ Ideia nova de estilo não é correção: é decisão nova, e se decide com a pessoa. Correção pequena e que dá para
40
+ desfazer não precisa de confirmação.
41
+
42
+ Reaproveite o que continua válido: projeto, transcrição, rostos medidos, recorte, sons. Mudar posição ou fonte
43
+ não pede recorte novo nem animação redesenhada.
44
+
45
+ ## Diagnóstico só de leitura
46
+
47
+ Nesta etapa você não mexe no projeto. Só olha e escreve.
48
+
49
+ 1. Toque o vídeo inteiro com som, no tamanho do celular. Depois olhe uma folha com 1 quadro por segundo e tiras
50
+ densas nas trocas:
51
+ `uv run --directory "<SKILL>" python helpers/tira_de_quadros.py '<VIDEO>' 0 <fim> --fps 1 --colunas 8 --saida '<PROJETO>/quadros/folha.jpg'`
52
+ 2. Confira a fala real e diga, bloco a bloco, qual mensagem manda ali.
53
+ 3. Marque, com início e fim:
54
+ - onde rosto, textos, legenda, animações e imagens disputam o olho;
55
+ - onde falta contexto para entender;
56
+ - onde algo inserido não acrescenta nada.
57
+ 4. Separe erro objetivo (texto cobre o rosto, legenda repete o lettering) de gosto.
58
+ 5. Dê a cada problema uma saída só, escolhida da mais leve para a mais forte: **deixar** (fica como está; era
59
+ gosto, não erro), **mover** (vai para outro canto da tela), **encolher** (menor, mais curto ou mais baixo),
60
+ **atrasar** (entra depois, quando o que disputa com ele já saiu) ou **remover**.
61
+ 6. Escreva `diagnostico.md` no projeto: até cinco correções, da mais importante para a menos, e para cada uma o
62
+ jeito mais rápido de aplicar sem quebrar o que já está bom.
63
+
64
+ | # | de | até | problema | tipo | saída | como aplicar |
65
+ |---|---|---|---|---|---|---|
66
+ | 1 | 00:08,2 | 00:11,0 | lista e legenda brigando no mesmo lugar | erro | atrasar | a legenda volta só depois que a lista sai |
67
+ | 2 | 00:14,0 | 00:15,5 | carimbo que não corresponde a nenhuma frase | erro | remover | apagar a peça do `projeto.json` |
68
+
69
+ Não sugira fala nova, trilha nova, oferta nova nem material comprado. Arquivo que não abriu vira limite declarado,
70
+ não suposição.
71
+
72
+ ## Conserto num trecho
73
+
74
+ Entrada: a versão atual, o problema, o início e o fim, e como saber que ficou certo.
75
+
76
+ 1. **Ache a peça que causa.** Camada, arquivo ou valor. Texto em cima do rosto pode ser a posição, a ordem das
77
+ camadas ou uma máscara: corrija o mecanismo certo, não o sintoma.
78
+ 2. **Mude o mínimo.** Fora do intervalo nada se mexe: enquadramento, trilha, cores, fonte, emendas, duração, fala.
79
+ 3. **Se precisar sair do trecho,** pare, explique a dependência e mostre o menor alcance possível antes de fazer.
80
+ 4. **Mostre o trecho corrigido** no estúdio com 1 a 2 s de margem antes e depois.
81
+ 5. **Depois do render, compare com a aprovada.** Fora do trecho, imagem e som têm que ser os mesmos. Grave este
82
+ script no projeto e rode:
83
+
84
+ ```python
85
+ # comparar_versoes.py uso: python3 comparar_versoes.py aprovada.mp4 nova.mp4 <de> <ate>
86
+ import subprocess, sys, tempfile
87
+ from pathlib import Path
88
+ aprovada, nova, de, ate = sys.argv[1], sys.argv[2], float(sys.argv[3]), float(sys.argv[4])
89
+ tmp = Path(tempfile.mkdtemp())
90
+
91
+ def duracao(v):
92
+ return float(subprocess.run(["ffprobe", "-v", "error", "-show_entries", "format=duration", "-of", "csv=p=0", v],
93
+ capture_output=True, text=True).stdout)
94
+
95
+ def fora(t0, t1): # não encosta no trecho consertado (com 0,1 s de folga)
96
+ return t1 <= de - 0.1 or t0 >= ate + 0.1
97
+
98
+ avisos = []
99
+ if abs(duracao(aprovada) - duracao(nova)) > 0.05:
100
+ avisos.append(f"duração mudou: {duracao(aprovada):.2f} s para {duracao(nova):.2f} s")
101
+ subprocess.run(["ffmpeg", "-v", "error", "-i", aprovada, "-i", nova, "-lavfi",
102
+ f"[0:v][1:v]ssim=stats_file={tmp / 'ssim.log'}", "-f", "null", "-"], check=True)
103
+ num, den = subprocess.run(["ffprobe", "-v", "error", "-select_streams", "v:0", "-show_entries", "stream=r_frame_rate",
104
+ "-of", "csv=p=0", aprovada], capture_output=True, text=True).stdout.strip().split("/")
105
+ fps = float(num) / float(den)
106
+ ruins = []
107
+ for linha in open(tmp / "ssim.log"):
108
+ c = dict(p.split(":") for p in linha.split() if ":" in p)
109
+ t = (int(c["n"]) - 1) / fps
110
+ if fora(t, t + 1 / fps) and float(c["All"]) < 0.98:
111
+ ruins.append(t)
112
+ if ruins:
113
+ avisos.append(f"imagem mudou fora do trecho em {len(ruins)} quadros, de {ruins[0]:.2f} a {ruins[-1]:.2f} s")
114
+
115
+ def rms(v, nome): # volume a cada 0,5 s
116
+ log = tmp / f"{nome}.log"
117
+ subprocess.run(["ffmpeg", "-v", "error", "-i", v, "-map", "0:a:0", "-af",
118
+ f"aresample=48000,asetnsamples=n=24000,astats=metadata=1:reset=1,"
119
+ f"ametadata=print:key=lavfi.astats.Overall.RMS_level:file={log}", "-f", "null", "-"], check=True)
120
+ out, t = [], None
121
+ for l in open(log):
122
+ if "pts_time:" in l:
123
+ t = float(l.split("pts_time:")[1])
124
+ elif "RMS_level=" in l:
125
+ out.append((t, float(l.split("=")[1])))
126
+ return out
127
+
128
+ for (t, x), (_, y) in zip(rms(aprovada, "a"), rms(nova, "b")):
129
+ if fora(t, t + 0.5) and abs(x - y) > 1 and max(x, y) > -60:
130
+ avisos.append(f"som mudou fora do trecho em {t:.1f} s ({x:.1f} dB para {y:.1f} dB)")
131
+ print("\n".join(avisos) or "fora do trecho, nada mudou")
132
+ ```
133
+
134
+ Qualquer aviso fora do trecho é mudança sem querer: ache a causa antes de entregar. Olhe também a emenda do
135
+ trecho com a tira de quadros a 30 qps, para ver se continua lisa.
136
+ 6. **Versão nova, nunca por cima.** O nome diz o que mudou (`final_v2_legenda-00m12.mp4`). Na entrega, uma linha
137
+ do que mudou e o intervalo conferido.
138
+
139
+ Correção não é pretexto para redesenhar o vídeo.
140
+
141
+ ## Tentativa repetida
142
+
143
+ O mesmo erro voltou depois de uma correção:
144
+
145
+ 1. Antes da próxima tentativa, compare o que devia sair com o que saiu. Escreva a diferença em uma frase.
146
+ 2. Teste uma hipótese por vez, num trecho curto: o menor em que o defeito ainda aparece (uma amostra de 2 s, não o
147
+ vídeo inteiro).
148
+ 3. Se a correção repete a falha sem nada novo aprendido, pare esse ciclo. Conte o que testou, o que descobriu e o
149
+ que falta (uma informação da pessoa ou uma capacidade que o computador não tem). Siga com as correções que não
150
+ dependem disso.
151
+ 4. Refazer o vídeo todo não é jeito automático de consertar.
152
+
153
+ ## Voz
154
+
155
+ Chiado, picos, voz que estourou, eco de sala ou volume subindo e descendo que atrapalham entender.
156
+
157
+ - **Relate só o que achou de verdade.** `helpers/noise_check.py` mede o ruído de fundo, a saturação e o eco de sala
158
+ de cada vídeo (só a voz: `helpers/voz_check.py VIDEO`); `helpers/voice_levels.py` mede o volume desigual entre
159
+ frases. São medidas: ouça os tempos que a saída cita antes de afirmar, e diga "medi", não "ouvi".
160
+ - **Correção moderada** com o que é local: limpeza de ruído leve ou forte (`helpers/denoise.py`), ganho por
161
+ trecho. Mantenha o timbre, as pausas com intenção e o alinhamento com a imagem.
162
+ - **Saturação** (`voz SATURADA` ou `possível saturação`): a voz bateu no teto e a parte de cima da onda se perdeu.
163
+ **Não se recupera por inteiro.** Diga isso e não prometa recuperar: dá para suavizar o áspero dos picos, não
164
+ para desfazer. Baixar o volume não conserta (a saturação fica, só mais baixa). Se a frase saturada importa,
165
+ pergunte se dá para regravar com o celular mais longe da boca ou o ganho mais baixo. Saturação leve que foi
166
+ abaixada depois pode sair como `possível` ou nem aparecer: na dúvida, ouça os picos.
167
+ - **Eco de sala** (`eco de sala leve` ou `forte`): a voz continua soando depois que a pessoa para (a saída diz
168
+ quanto tempo leva para sumir) ou volta repetida alguns ms depois. **Trate leve:** tire um pouco do grave
169
+ embolado e abaixe só a cauda nas pausas, sem apagar:
170
+
171
+ ```bash
172
+ ffmpeg -i original.mp4 -c:v copy -af "highpass=f=90,equalizer=f=300:t=q:w=1.2:g=-3,agate=threshold=LIMIAR:ratio=2:range=0.3:attack=5:release=150" tratado.mp4
173
+ ```
174
+
175
+ `LIMIAR` fica 25 dB abaixo da voz medida no `noise_check` (voz -16 dB: 10^(-41/20), uns 0.009). Numa sala
176
+ sintética de 0,70 s essa receita levou a medida para 0,64 s: melhora pouco, e é isso mesmo, porque a sala não sai
177
+ do arquivo. Porta de ruído forte ou redução pesada apaga a cauda e picota a voz (o fim das palavras some e o
178
+ fundo liga e desliga): não use. Eco forte que atrapalha entender: diga e sugira regravar num cômodo com cortina,
179
+ sofá ou tapete.
180
+ - **Amostra com três situações:** um trecho de voz mais fraca, um de voz mais forte e um silêncio. Ponha o
181
+ original e o tratado um depois do outro, os dois igualados no mesmo volume percebido, para o ouvido não ser
182
+ enganado pelo mais alto (a receita de eco acima deixou o tratado quase 1 LU mais baixo; sem igualar, ele
183
+ pareceria pior só por isso):
184
+
185
+ ```bash
186
+ ffmpeg -ss 12 -t 6 -i original.mp4 -vn -ac 1 -ar 48000 -af loudnorm=I=-20:TP=-2 voz_original.wav
187
+ ffmpeg -ss 12 -t 6 -i tratado.mp4 -vn -ac 1 -ar 48000 -af loudnorm=I=-20:TP=-2 voz_tratado.wav
188
+ ffmpeg -i voz_original.wav -f lavfi -t 0.7 -i anullsrc=r=48000:cl=mono -i voz_tratado.wav \
189
+ -filter_complex "[0:a][1:a][2:a]concat=n=3:v=0:a=1" comparar_voz.wav
190
+ ```
191
+
192
+ Depois meça de novo o tratado com `helpers/voz_check.py` e registre as duas medidas.
193
+ - **Saída sem clipping:** pico verdadeiro de -1 dBTP ou menos (`-af ebur128=peak=true`).
194
+ - Se a pessoa pediu para ouvir antes, trate o vídeo inteiro só depois do ok. Se já autorizou, a comparação é
195
+ conferência sua.
196
+ - Nunca sintetize palavra nem troque a voz. Registre as medidas que fez e o que continuou com problema.
197
+
198
+ ## Legendas checadas no áudio
199
+
200
+ Antes de entregar, principalmente com nomes, números e termos técnicos.
201
+
202
+ 1. Confronte cada legenda com o áudio. Ouça de verdade os trechos com nome, número, marca e termo técnico.
203
+ 2. Glossário: a lista de nomes e termos da pessoa. Use na transcrição (`--prompt` do `transcribe.py`) e nas
204
+ correções do projeto (`"correcoes"` no `projeto.json`). O roteiro serve para grafia; não substitui o que foi
205
+ dito.
206
+ 3. Corrija erro de reconhecimento e pontuação. Negação, condição, ressalva e número nunca somem.
207
+ 4. Palavra que continua duvidosa não se completa como certa: vai para `palavras-duvidosas.md`, com o tempo, o que
208
+ você ouviu e as opções. Entregue essa lista junto.
209
+ 5. Legenda em pedaços de até 3 palavras, numa linha, que se leem naturalmente (o projeto corta assim:
210
+ `legenda.max_palavras` 3 e `max_letras` por linha). Cada uma aparece e some com a voz; nenhuma fica pendurada
211
+ no silêncio, e nenhuma pisca (uma palavra solta de 0,1 s): junte com a vizinha.
212
+ 6. Confira no formato de entrega: lugar, quebra de linha, tamanho e contraste. A legenda não pode ficar em cima
213
+ do rosto, das mãos nem do que a pessoa está mostrando. Lettering aprovado fica; sobreposição que não se lê se desfaz.
214
+ 7. Prévia focada nas legendas mais compridas ou mais difíceis.
215
+
216
+ Nunca edite o áudio da fala para ele concordar com o texto.
217
+
218
+ ## Dado pessoal no arquivo exportado
219
+
220
+ Obrigatório antes de entregar quando o vídeo tem tela gravada, conversa, print, painel, e-mail ou qualquer
221
+ borrão. É a última conferência, no arquivo exportado (o estúdio não serve: é o arquivo que vai para o mundo).
222
+
223
+ 1. Monte a lista do que não pode aparecer, olhando a gravação bruta: nomes de pessoas, de conversas, de
224
+ projetos e de clientes, loja, endereço, o que a pessoa pediu para esconder. Nome dela e da marca dela,
225
+ se podem aparecer, vão em `--ignorar`.
226
+ 2. Rode no arquivo exportado:
227
+ `uv run --directory '<SKILL>' python helpers/conferir_dados.py '<PROJ>/renders/final.mp4' --termos 'Maria Souza, Projeto X' --ignorar 'Vitória'`
228
+ Ele lê pelo OCR todos os quadros até 3 min de vídeo (nos mais longos, 4 por segundo; `--todos` lê todos) e
229
+ procura os termos, e-mail, CPF, CNPJ, telefone, cartão, @perfil e nome comum com sobrenome. No Mac usa o
230
+ leitor da Apple; fora dele, o Tesseract, se estiver instalado. Sem leitor, ele diz: aí a conferência é no olho,
231
+ com a tira de quadros a 30 qps em cada troca de tela.
232
+ 3. Cada achado vem com o texto lido, o tempo, os quadros (de e até) e a caixa em pixels. Alargue o borrão
233
+ (caixa e janela de tempo) ou tire o trecho, renderize e rode de novo até sair `0 achado(s)`. Os vazamentos
234
+ que já aconteceram: o primeiro quadro (borrão com fade de entrada), um quadro antes de o borrão entrar, uma
235
+ linha que mudou de lugar no menu, um menu que abre nos últimos 0,15 s.
236
+ 4. `possível nome` é palpite (um nome comum seguido de outra palavra com maiúscula): confira se pode aparecer.
237
+ 5. Zero achado não prova que não tem dado: o leitor erra letra pequena, borrada, girada ou em movimento. Olhe
238
+ também o primeiro e o último quadro.
239
+ 6. **O que ainda tem o dado fora do vídeo final.** O `borrar` do projeto queima o borrão na cópia do corte do
240
+ projeto (`assets/cut.mp4`), mas o `<EDIT>/cut.mp4`, as gravações brutas e o original de uma prova com
241
+ `arquivo` continuam com o dado legível. Se a pasta do projeto vai para alguém (zip, estúdio compartilhado),
242
+ mande sem a `edit/` e sem esses originais, e rode o `conferir_dados.py` também no `assets/cut.mp4`. Para
243
+ borrar um arquivo fora do projeto (o corte da `edit`, uma gravação), com o ffmpeg:
244
+
245
+ ```bash
246
+ ffmpeg -i cut.mp4 -filter_complex "[0:v]split[a][t];[t]crop=LARG:ALT:X:Y,boxblur=RL:2:RC:2[b];[a][b]overlay=X:Y:enable='between(t,DE,ATE)'" -c:a copy cut_borrado.mp4
247
+ ```
248
+
249
+ O `split` é obrigatório: usando `[0:v]` duas vezes o ffmpeg não reclama e o borrão não sai (visto no teste).
250
+ `RL` é no máximo metade do menor lado da caixa e `RC` no máximo um quarto (o `boxblur` recusa mais: numa
251
+ caixa de 26 px de altura, `boxblur=13:2:6:2`). Várias caixas: repita o trio em cadeia, cada um com o seu
252
+ `split` (`...overlay=...[v1];[v1]split[a2][t2];[t2]crop=...,boxblur=...[b2];[a2][b2]overlay=...`). Depois,
253
+ `conferir_dados.py` no `cut_borrado.mp4` também.
254
+
255
+ Na entrega, diga que rodou a conferência de dados, em quantos quadros, e o que não dá para garantir.
256
+
257
+ ## Triagem dos materiais
258
+
259
+ Pasta cheia de arquivos e nenhuma certeza do que usar. Nesta etapa não altere nada, não procure, não
260
+ compre e não gere nada.
261
+
262
+ 1. Faça o inventário da pasta (grave no projeto e rode com `python3 inventario.py '<PASTA>'`):
263
+
264
+ ```python
265
+ import hashlib, json, subprocess, sys
266
+ from pathlib import Path
267
+ pasta, vistos = Path(sys.argv[1]), {}
268
+ for arq in sorted(p for p in pasta.rglob("*") if p.is_file() and not p.name.startswith(".")):
269
+ h = hashlib.sha256()
270
+ with open(arq, "rb") as f:
271
+ for bloco in iter(lambda: f.read(1 << 20), b""):
272
+ h.update(bloco)
273
+ sha = h.hexdigest()[:12]
274
+ r = subprocess.run(["ffprobe", "-v", "error", "-select_streams", "v:0", "-show_entries",
275
+ "stream=width,height:format=duration", "-of", "json", str(arq)], capture_output=True, text=True)
276
+ info = json.loads(r.stdout or "{}")
277
+ s = (info.get("streams") or [{}])[0]
278
+ tam = f"{s['width']}x{s['height']}" if "width" in s else "sem imagem"
279
+ dur = info.get("format", {}).get("duration")
280
+ dup = f" IGUAL A {vistos[sha]}" if sha in vistos else ""
281
+ vistos.setdefault(sha, arq.name)
282
+ print(f"{arq.relative_to(pasta)} · {tam}" + (f" · {float(dur):.1f} s" if dur and float(dur) > 0.1 else "") + dup)
283
+ ```
284
+
285
+ 2. Confira a fala e olhe cada arquivo. Classifique em quatro tipos, sem misturar:
286
+ - **prova de verdade:** mostra de fato o que a fala afirma, e é da pessoa;
287
+ - **demonstração:** mostra como algo funciona;
288
+ - **inspiração visual:** referência de estilo, não entra no vídeo;
289
+ - **ilustração:** desenho, imagem de banco ou gerada. Ilustra, nunca prova.
290
+ 3. Aponte duplicatas (o inventário acha as iguais; as quase iguais, olhando), baixa resolução (menor que a área que
291
+ vai ocupar na tela), citação na fala a material que não está na pasta e origem ou direito desconhecido
292
+ (marcado para conferir; arquivo na pasta não quer dizer direito de uso).
293
+ 4. Faltou material: antes de buscar ou gerar, sugira deixar a própria gravação limpa na tela, ou um esquema
294
+ simples que seja fiel à fala. Buscar ou gerar imagem só com o ok da pessoa, e o que vier é ilustração.
295
+ 5. Escreva `materiais.md`: cada arquivo escolhido, a frase que ele sustenta, como vai aparecer e por quê. Depois a
296
+ lista de lacunas, duplicatas e itens a conferir.
297
+
298
+ ## Comparação justa (antes e depois, ou A e B)
299
+
300
+ 1. Os dois lados mostram a mesma situação? Se não, explique e não monte como confronto direto.
301
+ 2. Iguale velocidade, enquadramento, escala e sincronia. Não piore um lado em cor, som ou nitidez.
302
+ 3. Rótulos neutros e literais ("Antes", "Depois", "Versão A").
303
+ 4. Comparando som, iguale o volume percebido (como na seção Voz). Comparando imagem, nada de texto em cima do
304
+ detalhe.
305
+ 5. Lado a lado ou um depois do outro: o que se lê melhor no formato final.
306
+ 6. Se há fala gravada sobre aquilo, é ela que acompanha. Nenhum resultado ou número inventado.
307
+ 7. Entregue a amostra e diga o que ela deixa ver e o que ela não comprova.
308
+
309
+ ## Custo, sem inventar
310
+
311
+ Quando perguntarem quanto saiu, a resposta vem de conta feita, nunca de impressão. Número que você não viu (token,
312
+ crédito, saldo, preço por vídeo) vira "não medi".
313
+
314
+ Cada gasto tem a sua origem e o seu jeito de conferir. Não some tudo num número só:
315
+
316
+ | gasto | de onde sai o número |
317
+ |---|---|
318
+ | serviço cobrado por uso (voz sintética, imagem ou vídeo gerado por IA) | o extrato, ou o saldo antes e depois |
319
+ | uso do plano de IA | o painel de uso do plano; sem ele aberto, "não medido" |
320
+ | compra avulsa (música, fonte, banco de imagem) | o recibo |
321
+ | render no Mac | os minutos com a máquina presa: não é de graça, custa tempo |
322
+ | trabalho de gente | as horas anotadas |
323
+
324
+ Também conta como dado de verdade quanto tempo ficou esperando render e quantas peças passaram. O que for palpite
325
+ aparece com a palavra "estimativa" do lado. Promessa do tipo "economiza 80%" ou "a assinatura dá tantos vídeos
326
+ por mês" não entra.
327
+
328
+ Um ajuste pedido não libera, sozinho, nada que cobra (API paga, crédito, compra). Se o conserto não sai sem isso,
329
+ explique o motivo, mostre o caminho sem custo que existir e como ela vê o preço antes de gastar. Teto que ela já
330
+ liberou vale até acabar, sem perguntar de novo.
331
+
332
+ ## Entrega de uma revisão
333
+
334
+ Uma nota curta: os pontos corrigidos, o intervalo que você conferiu de verdade, o que ficou pendente e do que
335
+ depende, o nome da versão nova e a garantia de que a anterior continua intacta.
@@ -0,0 +1,146 @@
1
+ # Som e trilha
2
+
3
+ Dois trabalhos, nesta ordem:
4
+
5
+ 1. **Efeitos sonoros** casados com o que aparece na tela: `helpers/plano_sfx.py`.
6
+ 2. **Trilha** contínua por baixo da voz, no fim de tudo: `helpers/mixar_trilha.py`.
7
+
8
+ Rode os helpers com o Python desta skill (tem numpy): `uv run --directory "<SKILL>" python helpers/<nome>.py`.
9
+ Precisam do ffmpeg. Com o `--directory` o comando roda dentro da pasta da skill: passe cada arquivo com o caminho completo, entre aspas.
10
+
11
+ ## O caminho no projeto (um só)
12
+
13
+ No projeto-modelo (`<PROJ>`, a cópia do `modelo-projeto`), os sons vão pelo `projeto.json`. Nunca cole tag
14
+ `<audio>` no `index.html`: o build reescreve o arquivo a cada vez.
15
+
16
+ 1. `cd '<PROJ>' && python3 build.py completo`: o vídeo com as animações, **sem trilha**. O build grava
17
+ `sons_sugeridos.json` com o som que cada animação, zoom, troca de cena e entrada de prova pede, com o tempo do
18
+ PICO (o quadro em que o movimento bate). As cenas próprias não entram sozinhas: anote o quadro de cada
19
+ mudança num `<PROJ>/eventos.json` (`[{"t": 12.4, "tipo": "pop"}]`).
20
+ 2. `uv run --directory "<SKILL>" python helpers/plano_sfx.py --projeto "<PROJ>"`: lê o `sons_sugeridos.json`
21
+ (e o `eventos.json`), monta o plano (um som por animação, espaço mínimo de 0,65 s, fica o mais forte), mede a
22
+ voz no `cut.mp4`, copia os sons para `<PROJ>/assets/sfx` (com `LICENCAS.txt`) e escreve o campo `sons` do
23
+ `projeto.json`: arquivo, `em` (o pico), `pico_no_arquivo`, `inicio_no_arquivo` (quando o pico vem antes do
24
+ começo do vídeo, só a cabeça do som sai), `dur`, `volume` e `fade`. Grava também `<PROJ>/plano_sfx.json`.
25
+ 3. `python3 build.py completo` de novo: os sons entram no `index.html`, cada um na sua faixa. O estúdio toca
26
+ todos; confira ali com som. O build nunca descarta um som calado: o que não cabe sai com `aviso:`.
27
+ 4. Render: `python3 build.py hf render --quality delivery --output renders/final.mp4`. Os sons já vêm no arquivo.
28
+ 5. Corte seco, se precisar (`references/corte-seco.md`). Ele lê o `plano_sfx.json` pra não cortar em cima de
29
+ um efeito.
30
+ 6. Trilha por último, no arquivo renderizado (e já cortado): `helpers/mixar_trilha.py`. Assim a música não pula
31
+ nas emendas.
32
+
33
+ Se a trilha entrar antes do corte seco, a música pula em cada emenda e o corte seco deixa de enxergar as pausas.
34
+
35
+ Mudou uma animação de lugar? Rode o `completo`, o `plano_sfx.py --projeto` e o `completo` de novo: o plano troca
36
+ só os sons que ele mesmo escreveu (`"plano": true`); som escrito à mão no `projeto.json` fica. Com o
37
+ `sons_sugeridos.json` de uma amostra, ele troca só os sons daquele trecho e avisa.
38
+
39
+ Fora do projeto-modelo (vídeo já pronto, sem HyperFrames): monte o plano com um `eventos.json` e junte os sons
40
+ por cima com `--aplicar` (seção abaixo).
41
+
42
+ ## Efeitos sonoros
43
+
44
+ ### A regra
45
+
46
+ - **Vídeo com animação**: cada animação que importa ganha o seu som, combinando com o movimento. Pop no pop, whoosh no deslize, impacto no carimbo, ding na notificação. O pico do som cai no quadro em que o movimento bate, nunca na palavra. Não tem teto de quantidade (o André aprovou 23 sons em 56 s): quem tira é o espaço mínimo.
47
+ - **Vídeo sem animação** (só a pessoa falando): uns 5 ou 6 sons no vídeo inteiro de 1 a 1min30. Um na abertura, um no maior número de dinheiro (e no segundo maior, se estiver longe), um em cada grande virada de assunto (no máximo 2) e um na chamada.
48
+ - Nunca som em cada palavra, nem em cada item de lista sem animação.
49
+ - Espaço mínimo de 0,65 s entre dois sons. Se dois caem perto, fica o mais forte.
50
+ - Os pequenos ficam baixinhos. Só os momentos-chave ficam altos.
51
+
52
+ Tabela completa, níveis e quando **não** pôr som: `references/tabela-de-sons.md`.
53
+
54
+ ### Passo a passo
55
+
56
+ 1. **Liste os eventos visuais** com o tempo do quadro em que cada movimento bate: o pouso do pop (fim do crescimento), o meio do deslize, o impacto do carimbo, o instante em que a notificação aparece. No projeto-modelo, o `sons_sugeridos.json` já faz isso para as peças do catálogo; você só escreve os das cenas próprias. Pegue esse tempo do código da animação (início do movimento + tempo até o pouso), nunca do começo da palavra. Salve em `eventos.json` (modelo em `references/exemplo-eventos.json`):
57
+
58
+ ```json
59
+ [{"t": 1.20, "tipo": "pop"},
60
+ {"t": 3.40, "tipo": "impacto", "nivel": "destaque"},
61
+ {"t": 7.64, "tipo": "whoosh-grande", "forcar": true, "nota": "tela cheia vira moldura"}]
62
+ ```
63
+
64
+ 2. **Monte o plano**:
65
+
66
+ ```bash
67
+ uv run --directory "<SKILL>" python helpers/plano_sfx.py --projeto "<PROJ>" # projeto-modelo
68
+ uv run --directory "<SKILL>" python helpers/plano_sfx.py eventos.json --video final.mp4 # vídeo pronto
69
+ ```
70
+
71
+ Ele lista os sons que ficaram, os que saíram e o motivo, e confere onde o pico caiu. O desvio tem que ficar abaixo de 1 quadro (33 ms a 30 fps). Com `--video` (ou, no `--projeto`, o `cut.mp4` do edit), ele também acerta os níveis pela voz do vídeo.
72
+
73
+ 3. **Coloque os sons**, de um destes jeitos:
74
+ - **No projeto-modelo**: o `--projeto` já escreveu o campo `sons` do `projeto.json`. Rode `python3 build.py completo` e o render.
75
+ - **No vídeo pronto**: `--aplicar final.mp4 --video-saida final_sons.mp4`. A voz fica no lugar e o volume final vai pra -14 LUFS.
76
+
77
+ 4. **Guarde o `plano_sfx.json`**. O corte seco usa ele.
78
+
79
+ Detalhes do plano:
80
+
81
+ - `--tipos` lista os tipos e os sons de cada um. Apelidos em português funcionam ("aparece", "deslize", "carimbo", "riscar", "moedas").
82
+ - Som específico num evento: `"som": "woven:ID"` (`assets/sfx/woven` desta skill), `"kit:NOME"` (kit de `assets/sfx` desta skill), `"bib:categoria:nome"` (biblioteca de 445 sons CC0 em `~/.editor-video/efeitos`, ex. `bib:impacto:boom`) ou um caminho de arquivo.
83
+ - `"nivel"`: `destaque`, `medio`, `discreto` ou um número em dBFS de pico.
84
+ - `"forcar": true`: o som fica mesmo perto de outro e mesmo passando do máximo. Use em momento-chave e pra disfarçar uma emenda de corte visível.
85
+ - `"dur"`: quanto tempo toca (digitação, aplauso).
86
+ - `--modo motion` (padrão: um som por animação; só o espaço mínimo tira) ou `--modo fala` (sem animação, 1 a cada 15 s). `--max N` põe um teto. `--espaco 0.7` troca o espaço mínimo. `--variar` alterna os sons do mesmo tipo.
87
+ - Mais de um arquivo de eventos: `plano_sfx.py sons_sugeridos.json eventos.json --projeto "<PROJ>"` (sem arquivo, o `--projeto` lê os dois da pasta).
88
+ - O `--html` antigo saiu: ele gravava um `sfx_audio.html` na raiz do projeto (dois erros no lint do estúdio) para colar no `index.html`, que o build reescreve.
89
+ - `--medir SOM` mostra duração, pico e começo de qualquer som.
90
+
91
+ ## Trilha
92
+
93
+ ### A regra
94
+
95
+ - A trilha fica **22 dB abaixo da voz** (padrão). A faixa boa é de 20 a 24. Com 28 ou mais ela some no celular.
96
+ - Sempre medida contra a voz, em LUFS. Um número de ganho sozinho ("-40 dB") não diz nada, porque depende de quão alta a música veio.
97
+ - A trilha abaixa quando a pessoa fala (duck) e volta nas pausas longas e no final.
98
+ - Entra contínua por cima do vídeo já cortado.
99
+ - "A música sumiu": suba 3 dB (`--abaixo-da-voz 19`). "Tá competindo com a minha voz": desça 3 (`--abaixo-da-voz 25`).
100
+
101
+ ### Passo a passo
102
+
103
+ ```bash
104
+ uv run --directory "<SKILL>" python helpers/mixar_trilha.py --video final_seco.mp4 --trilha musica.wav \
105
+ --abaixo-da-voz 22 --saida final_trilha.mp4
106
+ ```
107
+
108
+ Opções:
109
+
110
+ - `--entrada-em 12.0`: a música entra no segundo 12 do vídeo (ex.: quando a pessoa fala "trilha sonora").
111
+ - `--respiro` (ou `--respiro 3`): a música entra mais alta por 2 s (ou 3), 10 dB acima (`--respiro-db`), e depois assenta. Bom na entrada da música.
112
+ - `--duck 8`: quanto ela abaixa na fala, no máximo.
113
+ - `--fade-fim 1.5`: fade no fim. `--inicio-trilha 30`: começa a música do segundo 30 dela.
114
+ - Música mais curta que o vídeo repete sozinha, com crossfade de 1 s.
115
+
116
+ A resposta traz: quantos dB a trilha ficou abaixo da voz, quanto o duck abaixou, a duração da imagem e do som (têm que bater com a entrada), o desvio da voz (tem que dar 0 ms) e o volume final (-14 LUFS). Os números ficam também em `SAIDA.trilha.json`.
117
+
118
+ ### Onde achar trilha
119
+
120
+ - Biblioteca de trilhas desta skill em `~/.editor-video/trilhas`, por humor (animada, calma, épica, inspiradora...). Liste e escolha com o `helpers/trilhas.py`. São de uso próprio da pessoa: não redistribua o arquivo.
121
+ - Música que a pessoa mandar: pergunte se ela tem direito de usar em anúncio.
122
+
123
+ ## Como falar com a pessoa
124
+
125
+ - Antes: "Vou pôr um som em cada animação, baixinho, e os mais fortes só nos momentos importantes. A música fica por baixo da sua voz e abaixa quando você fala."
126
+ - Depois: diga quantos sons entraram, quais momentos têm som forte e quantos dB a música ficou abaixo da voz. Uma linha cada.
127
+ - Ofereça um ajuste por vez: "quer a música um pouco mais alta?", "quer tirar algum som?".
128
+ - Pedido pra tirar um som: apague o evento (ou mude pra `"nivel": "discreto"`) e rode de novo. Não mexa no resto.
129
+
130
+ ## Pegadinhas conhecidas
131
+
132
+ - **HyperFrames**: quando o `<audio>` tem `data-automation` com lane de volume, o `data-volume` é ignorado. O build não usa lane: o ganho vai no `data-volume` (no máximo 3,98, +12 dB) e as descidas em `data-fade-out`/`data-fade-in`.
133
+ - **HyperFrames**: cada som com o seu `data-track-index`. O build numera.
134
+ - **Som cujo pico vem antes do começo do vídeo** (um clique logo no quadro 0): o build começa o som no 0 e pula a cabeça do arquivo (`data-media-start`), com uma subida de 10 ms. Nunca some.
135
+ - **ffmpeg 8**: o `sidechaincompress` corta a saída quando uma das entradas acaba antes. O `mixar_trilha.py` passa todas as entradas por `apad` e `atrim` na duração exata do vídeo.
136
+ - **Som com vários picos parecidos** (glitch, risco de disco, impacto saturado): o "pico" usado é o começo do trecho mais forte (a 1 dB do máximo). É onde o ouvido sente a batida.
137
+ - **Pico real depois do AAC**: o codificador pode passar do teto em até 2 dB. Os scripts medem depois de gravar e, se passou de -0,5 dBTP, gravam de novo com um limitador leve só nos picos. O volume integrado continua -14 LUFS.
138
+ - **Trilha que já veio mixada no vídeo**: não dá pra tirar. Renderize de novo sem trilha.
139
+
140
+ ## Arquivos
141
+
142
+ - `helpers/plano_sfx.py`: plano de sons, `--projeto`, `--aplicar`, `--tipos`, `--medir`.
143
+ - `helpers/mixar_trilha.py`: trilha com duck, medida contra a voz.
144
+ - `references/tabela-de-sons.md`: tipo de animação e som, densidade, níveis em dB, quando não pôr som, medidas de cada arquivo.
145
+ - `references/exemplo-eventos.json`: modelo de eventos.
146
+ - `assets/sfx/woven/`: 35 sons do Woven SFX (CC0, domínio público). Licença em `assets/sfx/woven/LICENCA.md`.
@@ -0,0 +1,130 @@
1
+ # Tabela de sons
2
+
3
+ Níveis em dBFS de **pico de amostra, medido no próprio arquivo**, com a voz do vídeo perto de -14 LUFS. O `plano_sfx.py` usa esses números como padrão e corrige sozinho se a voz do vídeo estiver mais alta ou mais baixa (passe `--video`).
4
+
5
+ ## Tipo de animação e som que combina
6
+
7
+ | O que acontece na tela | tipo | som padrão | nível |
8
+ |---|---|---|---|
9
+ | Texto, ícone, cartão ou balão aparece | `pop` | woven:pop-hand | -18,5 |
10
+ | Algo desliza, entra ou sai rápido | `whoosh` | woven:fast-whoosh | -17,5 |
11
+ | Troca grande: tela cheia vira moldura, câmera gira, painel entra | `whoosh-grande` | woven:swish-whoosh-large | -12,5 |
12
+ | Palavra grande, número final ou carimbo pousa com força (com tremida) | `impacto` | woven:bass-impact | -11,5 |
13
+ | A grande revelação: logo, produto, placa final | `revelacao` | woven:base-drop | -11,5 |
14
+ | Item que empilha ou encaixa, sem drama | `batida` | woven:dull-thud | -14,5 |
15
+ | Algo riscado, cancelado, negado | `risco` | woven:record-needle-scratch | -12 |
16
+ | Notificação, venda que cai, celular recebendo | `notificacao` | woven:notification-ding | -12,5 |
17
+ | Balão de conversa, botão final, resposta | `mensagem` | woven:message-pop-reply | -15,5 |
18
+ | Tela liga, IA entra, falha digital | `glitch` | woven:glitch-logo | -13,5 |
19
+ | Cursor clica, dedo toca no botão | `clique` | woven:mouse-click-2 | -18 |
20
+ | Texto sendo digitado (passe `"dur"`) | `digitar` | woven:keyboard-typing-realistic | -22 |
21
+ | Check, item marcado, contagem | `tique` | woven:tick-sound | -19 |
22
+ | Bipe de interface | `beep` | woven:beep-short | -19 |
23
+ | Moedas, preço que aparece | `dinheiro` | woven:several-coins | -15 |
24
+ | Print, foto, captura de tela | `camera` | woven:camera-shutter-1-shot | -15 |
25
+ | Suspense que cresce até a revelação (o pico é o fim da subida) | `subida` | kit:rise | -15 |
26
+ | Deu certo, meta batida | `sucesso` | kit:success | -15 |
27
+ | Errado, o que não fazer | `erro` | kit:error | -15 |
28
+ | Reação de espanto (usar pouco) | `surpresa` | woven:female-gasp | -17 |
29
+ | Conquista, fim de história (usar pouco) | `aplauso` | woven:cheers-and-applause | -22 |
30
+
31
+ Níveis prontos pra usar no evento: `destaque` -12, `medio` -15, `discreto` -18, `baixo` -20.
32
+
33
+ Onde o som alinha: quase todos alinham o **pico** no tempo do evento. `digitar` e `aplauso` alinham o **começo** do som. Sons do kit desta skill e da biblioteca usam o ponto forte que já vem anotado no índice deles (`anchor_s`).
34
+
35
+ Cauda: cada som toca até 0,8 s depois do pico (0,3 s na `subida`, 1,2 s na `revelacao`, 2 s no `aplauso`) e sai com fade. Assim a cauda de um impacto não passa por cima da fala.
36
+
37
+ ## Densidade
38
+
39
+ - **Com animação**: um som por animação que importa. Referência aprovada: IMG_1498 v2, 23 sons em 56 s ("gostei"). O teto do script é 1 som a cada 2 s (`--modo motion`).
40
+ - **Sem animação**: 5 ou 6 sons num vídeo de 1 a 1min30 (`--modo fala`, 1 a cada 15 s). Abertura, maior número de dinheiro, até 2 viradas de assunto, chamada.
41
+ - Espaço mínimo de 0,65 s entre picos. Se dois caem perto, fica o mais forte. Os forçados (`"forcar": true`) sempre ficam.
42
+ - Passou do máximo: saem os mais fracos primeiro.
43
+ - Momento em nível `destaque`: no máximo um a cada 6 ou 8 s. Se tudo é destaque, nada é.
44
+
45
+ ## Volumes em dB
46
+
47
+ | O quê | Valor |
48
+ |---|---|
49
+ | Voz (referência) | -14 LUFS integrado |
50
+ | Efeito em momento-chave | pico -11 a -13 dBFS |
51
+ | Efeito médio | pico -15 dBFS |
52
+ | Efeito pequeno (pop, clique, tique) | pico -17 a -19 dBFS |
53
+ | Som contínuo (digitação) | pico -22 dBFS |
54
+ | Trilha | 22 dB abaixo da voz (faixa boa 20 a 24) |
55
+ | Duck da trilha na fala | até 8 dB |
56
+ | Respiro da trilha na entrada | +10 dB por 2 s |
57
+ | Final do vídeo | -14 LUFS, pico real até -1 dBTP |
58
+
59
+ De onde vêm esses números:
60
+
61
+ - IMG_1498 v2 (aprovado): no código os sons estavam marcados de -10 a -17, mas medidos no arquivo de verdade eles ficaram uns 3 dB abaixo disso, com a voz em -15,5 LUFS. Trazendo pra voz em -14, dá os valores da tabela.
62
+ - Reel "uma IA editou": trilha uns 24 dB abaixo da voz, com sidechain, mixada no pós. Uma tentativa 28,5 dB abaixo ficou praticamente inaudível no celular.
63
+ - IMG_1527: trilha com ganho 0.14 (uns -17 dB) e 0.07 competiu com a voz. O que conta é a distância até a voz, medida em LUFS.
64
+ - DJI_0033: trilha uns 30 dB abaixo da voz, com respiro de 11 dB na entrada. Pelo que se viu no reel, 28 dB ou mais já some no celular. Por isso o padrão aqui é 22, com a faixa de 20 a 24.
65
+
66
+ ## Quando NÃO pôr som
67
+
68
+ - Em cada palavra, ou em cada item de lista que não tem animação.
69
+ - Na legenda palavra por palavra (ela anda o tempo todo).
70
+ - Em movimento contínuo e lento: zoom devagar, câmera flutuando, fundo girando.
71
+ - Duas animações a menos de 0,65 s: um som só, o mais forte.
72
+ - Em cima de uma palavra importante dita baixinho: o som cobre a palavra. Adiante o evento pra logo antes dela ou empurre pra logo depois.
73
+ - Em frase emotiva ou história séria. Silêncio também é direção.
74
+ - Sons de humor (sapo, espanto, aplauso) em vídeo sério ou de oferta cara.
75
+ - `subida` (riser) só antes de uma revelação de verdade, no máximo 1 ou 2 por vídeo.
76
+ - Vídeo sem animação: nada de som por enfeite. Siga os 5 ou 6 momentos.
77
+
78
+ ## Uso extra: disfarçar emenda
79
+
80
+ Onde uma emenda de corte ficou visível (tomada errada tirada, pulo de imagem), um `whoosh` ou `pop` forçado em cima da emenda disfarça. Use `"forcar": true`.
81
+
82
+ ## Medidas dos arquivos
83
+
84
+ Medido com `plano_sfx.py --medir`. Duração em segundos, "pico" é o ponto forte (começo do trecho a 1 dB do máximo), nível em dBFS.
85
+
86
+ | som | duração | pico (s) | nível |
87
+ |---|---|---|---|
88
+ | woven:airplane-ding | 1,18 | 0,168 | 0,0 |
89
+ | woven:applause | 12,91 | 0,503 | 0,0 |
90
+ | woven:base-drop | 3,30 | 0,053 | -6,6 |
91
+ | woven:bass-impact | 2,46 | 0,069 | 0,0 |
92
+ | woven:beep-short | 0,70 | 0,026 | -12,0 |
93
+ | woven:camera-analog | 0,86 | 0,069 | -1,3 |
94
+ | woven:camera-flash | 6,46 | 0,310 | -0,1 |
95
+ | woven:camera-shutter-1-shot | 0,28 | 0,105 | -1,5 |
96
+ | woven:camera-shutter-8-shots | 1,11 | 0,114 | -0,3 |
97
+ | woven:camera-shutter-release | 0,58 | 0,051 | -2,6 |
98
+ | woven:cheers-and-applause | 4,09 | 0,251 | -1,4 |
99
+ | woven:deep-whoosh | 3,23 | 0,516 | -2,2 |
100
+ | woven:dj-scratch | 1,56 | 0,164 | -3,2 |
101
+ | woven:dull-thud | 1,39 | 0,038 | -2,6 |
102
+ | woven:elevator-ding | 2,00 | 0,003 | -2,9 |
103
+ | woven:explosion | 3,18 | 0,087 | -0,1 |
104
+ | woven:fast-whoosh | 0,39 | 0,112 | -8,1 |
105
+ | woven:female-gasp | 0,49 | 0,106 | -7,4 |
106
+ | woven:frog-ribbit | 0,70 | 0,126 | -1,4 |
107
+ | woven:glitch-logo | 0,63 | 0,141 | -7,2 |
108
+ | woven:keyboard-typing-realistic | 3,39 | 1,802 | -2,8 |
109
+ | woven:keyboard-typing | 10,29 | 5,792 | -0,1 |
110
+ | woven:male-gasp | 0,46 | 0,212 | -5,0 |
111
+ | woven:message-pop-reply | 0,88 | 0,038 | -0,1 |
112
+ | woven:money-chalking | 1,86 | 0,090 | -7,9 |
113
+ | woven:mouse-click-1 | 0,77 | 0,361 | -1,2 |
114
+ | woven:mouse-click-2 | 0,19 | 0,146 | -3,3 |
115
+ | woven:notification-ding | 2,00 | 0,064 | -9,0 |
116
+ | woven:pop-hand | 0,35 | 0,026 | -2,2 |
117
+ | woven:record-needle-scratch | 1,65 | 0,237 | 0,0 |
118
+ | woven:record-scratch | 1,28 | 0,482 | -1,7 |
119
+ | woven:several-coins | 1,42 | 0,029 | -0,4 |
120
+ | woven:sideways-record-needle | 0,58 | 0,435 | -0,6 |
121
+ | woven:swish-whoosh-large | 0,79 | 0,134 | 0,0 |
122
+ | woven:tick-sound | 0,56 | 0,028 | -10,4 |
123
+
124
+ Kit desta skill (ponto forte do índice `assets/sfx/sfx.json`): `kit:pop` 0,003 s, `kit:whoosh` 0,15 s, `kit:rise` 1,228 s, `kit:metal_riser` 1,654 s, `kit:success` 0,023 s, `kit:error` 0,188 s, `kit:bass_drop` 0,016 s, `kit:metal_hit` 0,164 s, `kit:notification` 0,008 s, `kit:cash` 0,07 s, `kit:keyboard` 0,111 s, `kit:mouse_click` 0 s, `kit:tick` 0 s, `kit:data` 0,025 s.
125
+
126
+ ## Onde cada som mora
127
+
128
+ - `woven:ID`: `assets/sfx/woven/ID.wav` desta skill (35 sons, CC0).
129
+ - `kit:NOME`: `assets/sfx/` desta skill (índice `sfx.json`). Outra pasta: variável `SC_KIT_SFX`.
130
+ - `bib:...`: `~/.editor-video/efeitos/` (índice `efeitos.json`, 445 sons CC0 por categoria: transicao, impacto, revelacao, interface, tecnologia, sucesso, erro, humor). Outra pasta: variável `SC_BIBLIOTECA_SFX` (ou `EDITOR_VIDEO_EFEITOS`). `bib:categoria` pega uma versão diferente a cada uso.