primocode 10.13.0 → 10.14.1

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 (196) hide show
  1. package/README.md +66 -12
  2. package/bin/primocode.js +148 -8
  3. package/lib/act.js +56 -3
  4. package/lib/catalogo.js +12 -1
  5. package/lib/config.js +1 -0
  6. package/lib/estudio/cota.js +157 -0
  7. package/lib/estudio/dados/projetos/clube-ad5.json +105 -0
  8. package/lib/estudio/dados/projetos/clube-ae-sem-memoria.json +107 -0
  9. package/lib/estudio/dados/projetos/clube-agent.json +120 -0
  10. package/lib/estudio/dados/projetos/clube-antes-e-agora.json +86 -0
  11. package/lib/estudio/dados/projetos/clube-apresentando-clube.json +110 -0
  12. package/lib/estudio/dados/projetos/clube-bluevisa.json +106 -0
  13. package/lib/estudio/dados/projetos/clube-caught-in-the-fire.json +127 -0
  14. package/lib/estudio/dados/projetos/clube-chat-cliente-satisfeito.json +98 -0
  15. package/lib/estudio/dados/projetos/clube-chatgpt-anuncios.json +120 -0
  16. package/lib/estudio/dados/projetos/clube-claude-dj.json +140 -0
  17. package/lib/estudio/dados/projetos/clube-claude-mcp.json +142 -0
  18. package/lib/estudio/dados/projetos/clube-cleanui.json +106 -0
  19. package/lib/estudio/dados/projetos/clube-clinica-take-unico.json +128 -0
  20. package/lib/estudio/dados/projetos/clube-clinica.json +104 -0
  21. package/lib/estudio/dados/projetos/clube-clube-opener.json +125 -0
  22. package/lib/estudio/dados/projetos/clube-clube.json +108 -0
  23. package/lib/estudio/dados/projetos/clube-codigo.json +101 -0
  24. package/lib/estudio/dados/projetos/clube-distilbook.json +104 -0
  25. package/lib/estudio/dados/projetos/clube-drive-upload.json +115 -0
  26. package/lib/estudio/dados/projetos/clube-dub.json +119 -0
  27. package/lib/estudio/dados/projetos/clube-enxovaly.json +105 -0
  28. package/lib/estudio/dados/projetos/clube-fecha7.json +118 -0
  29. package/lib/estudio/dados/projetos/clube-filatov.json +128 -0
  30. package/lib/estudio/dados/projetos/clube-frame.json +108 -0
  31. package/lib/estudio/dados/projetos/clube-glass.json +118 -0
  32. package/lib/estudio/dados/projetos/clube-letra-em-apps.json +84 -0
  33. package/lib/estudio/dados/projetos/clube-letra-globo-3d.json +111 -0
  34. package/lib/estudio/dados/projetos/clube-letra-nos-apps.json +146 -0
  35. package/lib/estudio/dados/projetos/clube-letra-seis-mundos.json +100 -0
  36. package/lib/estudio/dados/projetos/clube-lula-3.json +146 -0
  37. package/lib/estudio/dados/projetos/clube-morph.json +119 -0
  38. package/lib/estudio/dados/projetos/clube-motion-designer.json +115 -0
  39. package/lib/estudio/dados/projetos/clube-motion-pacote.json +112 -0
  40. package/lib/estudio/dados/projetos/clube-movimento.json +103 -0
  41. package/lib/estudio/dados/projetos/clube-not-like-us.json +117 -0
  42. package/lib/estudio/dados/projetos/clube-pinterest-inspiracao.json +86 -0
  43. package/lib/estudio/dados/projetos/clube-pixel-e-tinta.json +108 -0
  44. package/lib/estudio/dados/projetos/clube-ponte.json +118 -0
  45. package/lib/estudio/dados/projetos/clube-processo-edit-tonal.json +126 -0
  46. package/lib/estudio/dados/projetos/clube-processo-motion-100-ia.json +109 -0
  47. package/lib/estudio/dados/projetos/clube-promo.json +114 -0
  48. package/lib/estudio/dados/projetos/clube-proposito.json +115 -0
  49. package/lib/estudio/dados/projetos/clube-rankhog.json +128 -0
  50. package/lib/estudio/dados/projetos/clube-recursao.json +116 -0
  51. package/lib/estudio/dados/projetos/clube-revelar.json +118 -0
  52. package/lib/estudio/dados/projetos/clube-robo.json +125 -0
  53. package/lib/estudio/dados/projetos/clube-shelby-ep2.json +144 -0
  54. package/lib/estudio/dados/projetos/clube-shelby.json +97 -0
  55. package/lib/estudio/dados/projetos/clube-solar-eclipse.json +96 -0
  56. package/lib/estudio/dados/projetos/clube-soldier.json +128 -0
  57. package/lib/estudio/dados/projetos/clube-som-de-cena.json +108 -0
  58. package/lib/estudio/dados/projetos/clube-spotify-candidatura.json +112 -0
  59. package/lib/estudio/dados/projetos/clube-tda-app.json +118 -0
  60. package/lib/estudio/dados/projetos/clube-tda-ia.json +75 -0
  61. package/lib/estudio/dados/projetos/clube-telegram-chat.json +118 -0
  62. package/lib/estudio/dados/projetos/clube-telegram-ilha.json +106 -0
  63. package/lib/estudio/dados/projetos/clube-tennessee-nike.json +132 -0
  64. package/lib/estudio/dados/projetos/clube-tudo-se-move.json +112 -0
  65. package/lib/estudio/dados/projetos/clube-uiad.json +107 -0
  66. package/lib/estudio/dados/projetos/clube-viralgrow.json +108 -0
  67. package/lib/estudio/dados/projetos/clube-whose-side.json +140 -0
  68. package/lib/estudio/dados/projetos/clube-youtube-inscrever.json +108 -0
  69. package/lib/estudio/dados/projetos/elementos-do-site-em-movimento.json +49 -0
  70. package/lib/estudio/dados/projetos/explainer-narrado.json +51 -0
  71. package/lib/estudio/dados/projetos/lancamento-de-produto.json +51 -0
  72. package/lib/estudio/dados/projetos/motion-so-com-sons.json +50 -0
  73. package/lib/estudio/dados/projetos/titulo-em-after-effects.json +51 -0
  74. package/lib/estudio/dados/projetos/tour-de-saas.json +50 -0
  75. package/lib/estudio/dados/projetos-ae/antes-e-agora/ae/cenas.jsx +733 -0
  76. package/lib/estudio/dados/projetos-ae/antes-e-agora/assets/fazer_assets.py +88 -0
  77. package/lib/estudio/dados/projetos-ae/letra-em-apps/ae/cenas.jsx +402 -0
  78. package/lib/estudio/dados/projetos-ae/letra-em-apps/assets/preparar_assets.py +17 -0
  79. package/lib/estudio/dados/projetos-ae/letra-em-apps/assets/svg_para_ae.py +25 -0
  80. package/lib/estudio/dados/projetos-ae/letra-nos-apps/BRIEF-AGENTES.md +31 -0
  81. package/lib/estudio/dados/projetos-ae/letra-nos-apps/README.md +53 -0
  82. package/lib/estudio/dados/projetos-ae/letra-nos-apps/ROTEIRO-CENAS.md +69 -0
  83. package/lib/estudio/dados/projetos-ae/letra-nos-apps/ae/A-agenda.jsx +148 -0
  84. package/lib/estudio/dados/projetos-ae/letra-nos-apps/ae/B-docs.jsx +174 -0
  85. package/lib/estudio/dados/projetos-ae/letra-nos-apps/ae/C-alttab.jsx +113 -0
  86. package/lib/estudio/dados/projetos-ae/letra-nos-apps/ae/D-spotify.jsx +118 -0
  87. package/lib/estudio/dados/projetos-ae/letra-nos-apps/ae/E-notas.jsx +146 -0
  88. package/lib/estudio/dados/projetos-ae/letra-nos-apps/ae/F-jornal1.jsx +144 -0
  89. package/lib/estudio/dados/projetos-ae/letra-nos-apps/ae/G-google.jsx +153 -0
  90. package/lib/estudio/dados/projetos-ae/letra-nos-apps/ae/H-mapa.jsx +176 -0
  91. package/lib/estudio/dados/projetos-ae/letra-nos-apps/ae/I-imagens.jsx +132 -0
  92. package/lib/estudio/dados/projetos-ae/letra-nos-apps/ae/J-jornal2.jsx +191 -0
  93. package/lib/estudio/dados/projetos-ae/letra-nos-apps/ae/K-maps.jsx +184 -0
  94. package/lib/estudio/dados/projetos-ae/letra-nos-apps/ae/camera-movimentos.jsx +48 -0
  95. package/lib/estudio/dados/projetos-ae/letra-nos-apps/ae/camera.jsx +57 -0
  96. package/lib/estudio/dados/projetos-ae/letra-nos-apps/ae/card-spotify.jsx +98 -0
  97. package/lib/estudio/dados/projetos-ae/letra-nos-apps/ae/digitar.jsx +38 -0
  98. package/lib/estudio/dados/projetos-ae/letra-nos-apps/ae/jornal-comum.jsx +196 -0
  99. package/lib/estudio/dados/projetos-ae/letra-nos-apps/ae/letra.jsx +23 -0
  100. package/lib/estudio/dados/projetos-ae/letra-nos-apps/ae/letra_automatica.py +83 -0
  101. package/lib/estudio/dados/projetos-ae/letra-nos-apps/ae/montagem.jsx +74 -0
  102. package/lib/estudio/dados/projetos-ae/letra-nos-apps/ae/w-agenda/render_html.py +13 -0
  103. package/lib/estudio/dados/projetos-ae/letra-nos-apps/ae/w-agenda/util.jsx +162 -0
  104. package/lib/estudio/dados/projetos-ae/letra-nos-apps/ae/w-midia-comum.jsx +114 -0
  105. package/lib/estudio/dados/projetos-ae/letra-nos-apps/ae/wg-util.jsx +360 -0
  106. package/lib/estudio/dados/projetos-ae/letra-nos-apps/assets/F-jornal1/render_html.py +13 -0
  107. package/lib/estudio/dados/projetos-ae/letra-nos-apps/assets/render_w-midia.py +26 -0
  108. package/lib/estudio/dados/projetos-ae/letra-nos-apps/assets/w-midia-ferramentas/inclin.py +30 -0
  109. package/lib/estudio/dados/projetos-ae/letra-nos-apps/assets/w-midia-ferramentas/medir_d.py +36 -0
  110. package/lib/estudio/dados/projetos-ae/letra-nos-apps/assets/w-midia-ferramentas/medir_e.py +27 -0
  111. package/lib/estudio/dados/projetos-ae/letra-nos-apps/camera/ajustar_movimentos.py +61 -0
  112. package/lib/estudio/dados/projetos-ae/letra-nos-apps/camera/ancorar.py +74 -0
  113. package/lib/estudio/dados/projetos-ae/letra-nos-apps/camera/assar.py +47 -0
  114. package/lib/estudio/dados/projetos-ae/letra-nos-apps/camera/camera3d_jornal.py +172 -0
  115. package/lib/estudio/dados/projetos-ae/letra-nos-apps/camera/comparar.py +32 -0
  116. package/lib/estudio/dados/projetos-ae/letra-nos-apps/camera/dados_ae_jornal.py +46 -0
  117. package/lib/estudio/dados/projetos-ae/letra-nos-apps/camera/folha_contato.py +28 -0
  118. package/lib/estudio/dados/projetos-ae/letra-nos-apps/camera/homografia_jornal.py +74 -0
  119. package/lib/estudio/dados/projetos-ae/letra-nos-apps/camera/integrar.py +44 -0
  120. package/lib/estudio/dados/projetos-ae/letra-nos-apps/camera/medir_quadro_a_quadro.py +32 -0
  121. package/lib/estudio/dados/projetos-ae/letra-nos-apps/camera/mesa_2d.py +64 -0
  122. package/lib/estudio/dados/projetos-ae/letra-nos-apps/camera/plot_cenas.py +11 -0
  123. package/lib/estudio/dados/projetos-ae/letra-nos-apps/camera/retificar_quadros.py +38 -0
  124. package/lib/estudio/dados/projetos-ae/letra-nos-apps/camera/w-agenda/assar_ab.py +52 -0
  125. package/lib/estudio/dados/projetos-ae/letra-nos-apps/camera/w-agenda/medir_ab.py +59 -0
  126. package/lib/estudio/dados/projetos-ae/letra-nos-apps/camera/wg_ajustar_h.py +111 -0
  127. package/lib/estudio/dados/projetos-ae/letra-nos-apps/camera/wg_corrige_cam.py +17 -0
  128. package/lib/estudio/dados/projetos-ae/letra-nos-apps/camera/wg_ecc_cadeia.py +80 -0
  129. package/lib/estudio/dados/projetos-ae/letra-nos-apps/camera/wg_finalizar_cam.py +65 -0
  130. package/lib/estudio/dados/projetos-ae/letra-nos-apps/camera/wg_mosaico.py +61 -0
  131. package/lib/estudio/dados/projetos-ae/letra-nos-apps/guia-do-metodo/tutorial-lyric-edit-interfaces/01-gramatica-e-roteiro.md +55 -0
  132. package/lib/estudio/dados/projetos-ae/letra-nos-apps/guia-do-metodo/tutorial-lyric-edit-interfaces/02-camera.md +66 -0
  133. package/lib/estudio/dados/projetos-ae/letra-nos-apps/guia-do-metodo/tutorial-lyric-edit-interfaces/03-montagem-no-ae.md +50 -0
  134. package/lib/estudio/dados/projetos-ae/letra-nos-apps/guia-do-metodo/tutorial-lyric-edit-interfaces/04-render-e-conferencia.md +43 -0
  135. package/lib/estudio/dados/projetos-ae/letra-nos-apps/guia-do-metodo/tutorial-lyric-edit-interfaces/05-abertura-celular-mergulho.md +43 -0
  136. package/lib/estudio/dados/projetos-ae/letra-nos-apps/guia-do-metodo/tutorial-lyric-edit-interfaces.md +42 -0
  137. package/lib/estudio/dados/projetos-ae/letra-nos-apps/transicao/atraso_imagem.py +31 -0
  138. package/lib/estudio/dados/projetos-ae/letra-nos-apps/transicao/fundo.py +56 -0
  139. package/lib/estudio/dados/projetos-ae/letra-nos-apps/transicao/juntar.py +45 -0
  140. package/lib/estudio/dados/projetos-ae/letra-nos-apps/transicao/montar.py +177 -0
  141. package/lib/estudio/dados/projetos-ae/letra-nos-apps/transicao/rastreio.py +74 -0
  142. package/lib/estudio/dados/projetos-ae/letra-nos-apps/transicao/sincronia.py +18 -0
  143. package/lib/estudio/dados/projetos-ae/pinterest-inspiracao/ae/cenas.jsx +530 -0
  144. package/lib/estudio/dados/projetos-ae/pinterest-inspiracao/assets/fazer_assets.py +107 -0
  145. package/lib/estudio/dados/projetos-ae/processo-motion-100-ia/assets/pessoas/figurinha.py +46 -0
  146. package/lib/estudio/dados/projetos-ae/processo-motion-100-ia/comp-a/BRIEF-A.md +83 -0
  147. package/lib/estudio/dados/projetos-ae/processo-motion-100-ia/comp-a/audio.py +179 -0
  148. package/lib/estudio/dados/projetos-ae/processo-motion-100-ia/comp-a/confere.py +20 -0
  149. package/lib/estudio/dados/projetos-ae/processo-motion-100-ia/comp-a/dados/tempo-parte1.js +1 -0
  150. package/lib/estudio/dados/projetos-ae/processo-motion-100-ia/comp-a/dados/tempo-parte2.js +1 -0
  151. package/lib/estudio/dados/projetos-ae/processo-motion-100-ia/comp-a/gerar_emojis.py +11 -0
  152. package/lib/estudio/dados/projetos-ae/processo-motion-100-ia/comp-a/img/filmes/_indice.js +122 -0
  153. package/lib/estudio/dados/projetos-ae/processo-motion-100-ia/comp-a/js/base.js +380 -0
  154. package/lib/estudio/dados/projetos-ae/processo-motion-100-ia/comp-a/js/main.js +86 -0
  155. package/lib/estudio/dados/projetos-ae/processo-motion-100-ia/comp-a/js/p1a.js +169 -0
  156. package/lib/estudio/dados/projetos-ae/processo-motion-100-ia/comp-a/js/p1b.js +455 -0
  157. package/lib/estudio/dados/projetos-ae/processo-motion-100-ia/comp-a/js/p1c.js +389 -0
  158. package/lib/estudio/dados/projetos-ae/processo-motion-100-ia/comp-a/js/p2.js +379 -0
  159. package/lib/estudio/dados/projetos-ae/processo-motion-100-ia/comp-a/video.py +62 -0
  160. package/lib/estudio/dados/projetos-ae/processo-motion-100-ia/take-unico/README.md +65 -0
  161. package/lib/estudio/dados/projetos-ae/processo-motion-100-ia/take-unico/oraculo_take.py +137 -0
  162. package/lib/estudio/dados/projetos-ae/processo-motion-100-ia/take-unico/render_take.py +388 -0
  163. package/lib/estudio/dados/projetos-ae/processo-motion-100-ia/take-unico/take.js +235 -0
  164. package/lib/estudio/editor.js +290 -0
  165. package/lib/estudio/effectcraft.js +152 -0
  166. package/lib/estudio/exportar.js +181 -0
  167. package/lib/estudio/index.js +97 -2
  168. package/lib/estudio/kit-ae/base.jsx +1146 -0
  169. package/lib/estudio/kit-ae/cenas.jsx +395 -0
  170. package/lib/estudio/kit-ae/primitivas.jsx +911 -0
  171. package/lib/estudio/maquina-diretor.js +393 -0
  172. package/lib/estudio/maquina-elementos.js +134 -0
  173. package/lib/estudio/maquina-layout.js +198 -0
  174. package/lib/estudio/maquina-som.js +478 -0
  175. package/lib/estudio/maquina-trilha.js +160 -0
  176. package/lib/estudio/maquina-voz.js +429 -0
  177. package/lib/estudio/maquina.js +516 -0
  178. package/lib/estudio/projetos.js +72 -0
  179. package/lib/headless.js +71 -0
  180. package/lib/hooks.js +72 -0
  181. package/lib/limites.js +100 -0
  182. package/lib/local/cerebro.json +398 -12
  183. package/lib/local/entrada.js +46 -2
  184. package/lib/marca-kit.js +312 -0
  185. package/lib/mcp.js +286 -6
  186. package/lib/perigo.js +31 -3
  187. package/lib/planos.js +49 -19
  188. package/lib/preparar.js +111 -0
  189. package/lib/retomar.js +55 -0
  190. package/lib/sandbox.js +197 -0
  191. package/lib/skills.js +3 -1
  192. package/lib/tools.js +13 -4
  193. package/lib/ui.js +1 -1
  194. package/package.json +4 -2
  195. package/skills/after-effects/SKILL.md +52 -0
  196. package/skills/maquina-de-motion/SKILL.md +84 -0
@@ -0,0 +1,114 @@
1
+ // =====================================================================
2
+ // Ajudantes comuns das cenas C-alttab, D-spotify e E-notas (agente w-midia). ES3.
3
+ // Carregar com $.evalFile(P + "ae/w-midia-comum.jsx") depois de definir a variável global P (raiz do projeto, com barra no fim).
4
+ // =====================================================================
5
+ var WM = WM || {};
6
+ WM.DUR = 814 / 24; // 33,9167 s: tempo interno de toda cena = tempo do vídeo
7
+ WM.FPS = 24;
8
+
9
+ // acha item do projeto pelo nome (primeiro que bater)
10
+ WM.item = function (nome) {
11
+ for (var i = 1; i <= app.project.numItems; i++) if (app.project.item(i).name == nome) return app.project.item(i);
12
+ return null;
13
+ };
14
+ // pasta do projeto
15
+ WM.pasta = function (nome) {
16
+ var f = WM.item(nome);
17
+ if (f && f instanceof FolderItem) return f;
18
+ return app.project.items.addFolder(nome);
19
+ };
20
+ // comp: se já existe, apaga as camadas e reaproveita (assim quem usa a comp em outra cena não perde a ligação)
21
+ WM.comp = function (nome, w, h, pasta) {
22
+ var c = WM.item(nome);
23
+ if (c && c instanceof CompItem) {
24
+ while (c.numLayers > 0) { c.layer(1).locked = false; c.layer(1).remove(); }
25
+ c.width = w; c.height = h; c.duration = WM.DUR; c.frameRate = WM.FPS;
26
+ } else {
27
+ c = app.project.items.addComp(nome, w, h, 1, WM.DUR, WM.FPS);
28
+ }
29
+ if (pasta) c.parentFolder = pasta;
30
+ c.bgColor = [0, 0, 0];
31
+ c.motionBlur = true; c.shutterAngle = 90; c.shutterPhase = -45; c.motionBlurSamplesPerFrame = 16; c.motionBlurAdaptiveSampleLimit = 128;
32
+ return c;
33
+ };
34
+ // importa PNG (reaproveita se já importado com o mesmo caminho)
35
+ WM.png = function (caminho, pasta) {
36
+ var f = new File(caminho);
37
+ for (var i = 1; i <= app.project.numItems; i++) {
38
+ var it = app.project.item(i);
39
+ if (it instanceof FootageItem && it.file && it.file.fsName == f.fsName) { it.replace(f); return it; }
40
+ }
41
+ var io = new ImportOptions(f); var ft = app.project.importFile(io);
42
+ if (pasta) ft.parentFolder = pasta;
43
+ return ft;
44
+ };
45
+ // camada de PNG 3x posta no mundo: canto superior esquerdo do PNG no ponto (x,y) do mundo
46
+ WM.camadaPNG = function (comp, ft, x, y, nome) {
47
+ var L = comp.layers.add(ft); L.name = nome || ft.name;
48
+ var tr = L.property("ADBE Transform Group");
49
+ tr.property("ADBE Anchor Point").setValue([0, 0]);
50
+ tr.property("ADBE Position").setValue([x, y]);
51
+ tr.property("ADBE Scale").setValue([100 / 3, 100 / 3]);
52
+ L.startTime = 0; L.inPoint = 0; L.outPoint = WM.DUR;
53
+ return L;
54
+ };
55
+ // texto de ponto
56
+ WM.texto = function (comp, txt, fonte, tam, cor, just, x, y, nome, track, leading) {
57
+ var L = comp.layers.addText(txt); L.name = nome || txt;
58
+ var p = L.property("ADBE Text Properties").property("ADBE Text Document");
59
+ var d = p.value;
60
+ d.resetCharStyle(); d.resetParagraphStyle();
61
+ d.font = fonte; d.fontSize = tam; d.fillColor = cor; d.applyFill = true; d.applyStroke = false;
62
+ d.tracking = track || 0;
63
+ if (leading) { d.autoLeading = false; d.leading = leading; }
64
+ d.justification = just || ParagraphJustification.LEFT_JUSTIFY;
65
+ d.text = txt;
66
+ p.setValue(d);
67
+ L.property("ADBE Transform Group").property("ADBE Position").setValue([x, y]);
68
+ L.startTime = 0; L.inPoint = 0; L.outPoint = WM.DUR;
69
+ return L;
70
+ };
71
+ // cor hex -> [r,g,b] 0..1
72
+ WM.cor = function (h) { h = h.replace("#", ""); return [parseInt(h.substr(0, 2), 16) / 255, parseInt(h.substr(2, 2), 16) / 255, parseInt(h.substr(4, 2), 16) / 255]; };
73
+ // forma de retângulo arredondado (path de máscara/forma) centrada em (cx,cy), lados w,h, raio r
74
+ WM.retRed = function (cx, cy, w, h, r) {
75
+ r = Math.max(0, Math.min(r, w / 2, h / 2));
76
+ var x0 = cx - w / 2, x1 = cx + w / 2, y0 = cy - h / 2, y1 = cy + h / 2, k = 0.5523 * r;
77
+ var s = new Shape();
78
+ s.vertices = [[x0 + r, y0], [x1 - r, y0], [x1, y0 + r], [x1, y1 - r], [x1 - r, y1], [x0 + r, y1], [x0, y1 - r], [x0, y0 + r]];
79
+ s.inTangents = [[-k, 0], [0, 0], [0, -k], [0, 0], [k, 0], [0, 0], [0, k], [0, 0]];
80
+ s.outTangents = [[0, 0], [k, 0], [0, 0], [0, k], [0, 0], [-k, 0], [0, 0], [0, -k]];
81
+ s.closed = true;
82
+ return s;
83
+ };
84
+ // liga motion blur em toda camada da comp
85
+ WM.blurTodas = function (comp) { for (var i = 1; i <= comp.numLayers; i++) { try { comp.layer(i).motionBlur = true; } catch (e) {} } };
86
+ // ease em todas as chaves de uma propriedade (influência em %)
87
+ WM.easeTodas = function (prop, infIn, infOut) {
88
+ for (var k = 1; k <= prop.numKeys; k++) {
89
+ var n = 1; try { var v = prop.keyValue(k); if (v instanceof Array && prop.propertyValueType != PropertyValueType.TwoD_SPATIAL && prop.propertyValueType != PropertyValueType.ThreeD_SPATIAL) n = v.length; } catch (e) {}
90
+ var ei = [], eo = [], j; for (j = 0; j < n; j++) { ei.push(new KeyframeEase(0, infIn)); eo.push(new KeyframeEase(0, infOut)); }
91
+ prop.setTemporalEaseAtKey(k, ei, eo);
92
+ }
93
+ };
94
+ // chaves de uma lista [[t,v],...] com interpolação linear ou bezier
95
+ WM.chaves = function (prop, lista, tipo) {
96
+ var ts = [], vs = [], i; for (i = 0; i < lista.length; i++) { ts.push(lista[i][0]); vs.push(lista[i][1]); }
97
+ prop.setValuesAtTimes(ts, vs);
98
+ if (tipo == "linear") for (i = 1; i <= prop.numKeys; i++) prop.setInterpolationTypeAtKey(i, KeyframeInterpolationType.LINEAR, KeyframeInterpolationType.LINEAR);
99
+ if (tipo == "hold") for (i = 1; i <= prop.numKeys; i++) prop.setInterpolationTypeAtKey(i, KeyframeInterpolationType.HOLD, KeyframeInterpolationType.HOLD);
100
+ if (tipo == "suave") for (i = 1; i <= prop.numKeys; i++) { prop.setInterpolationTypeAtKey(i, KeyframeInterpolationType.BEZIER, KeyframeInterpolationType.BEZIER); try { prop.setTemporalContinuousAtKey(i, true); prop.setTemporalAutoBezierAtKey(i, true); } catch (e) {} }
101
+ };
102
+ // troca as chaves de um controle do CAM num intervalo (apaga as chaves entre t0 e t1 e grava a lista)
103
+ WM.trocarChaves = function (prop, t0, t1, lista) {
104
+ for (var k = prop.numKeys; k >= 1; k--) { var t = prop.keyTime(k); if (t >= t0 - 1e-4 && t <= t1 + 1e-4) prop.removeKey(k); }
105
+ for (var i = 0; i < lista.length; i++) prop.setValueAtTime(lista[i][0], lista[i][1]);
106
+ for (var j = 1; j <= prop.numKeys; j++) prop.setInterpolationTypeAtKey(j, KeyframeInterpolationType.LINEAR, KeyframeInterpolationType.LINEAR);
107
+ };
108
+ // apaga sólidos/nulls que sobraram sem uso (cada rodada do gerador cria novos)
109
+ WM.limparSolidos = function () {
110
+ for (var i = app.project.numItems; i >= 1; i--) {
111
+ var it = app.project.item(i);
112
+ if (it instanceof FootageItem && it.mainSource instanceof SolidSource && it.usedIn.length === 0) it.remove();
113
+ }
114
+ };
@@ -0,0 +1,360 @@
1
+ // =====================================================================
2
+ // Utilitários das cenas G, H, I, K (agente w-google, 17/10). ES3.
3
+ // Estrutura de cada cena (por causa da inclinação 3D medida no original):
4
+ // "MUNDO <id>" comp quadrada 1080+2*margem; CAM (camera.jsx) no centro; todo o mundo é filho do CAM.
5
+ // "CENA <id>" 1080x1080: só a camada "MUNDO <id>" centrada + Corner Pin (resto projetivo da câmera medida).
6
+ // Coordenadas do mundo = px do quadro de referência do original (como no contrato).
7
+ // Carregar: $.evalFile(WG_P + "ae/wg-util.jsx") com WG_P = caminho decodificado do projeto.
8
+ // =====================================================================
9
+ var WG = {};
10
+ WG.P = File.decode("<HOME>/Documents/Cria%C3%A7%C3%A3o%20de%20conteudo/07-videos/projetos/2026-10-17-subzmotion-recriacao/");
11
+ WG.DUR = 814 / 24;
12
+ // ajudantes do projeto (camera.jsx, digitar.jsx) carregados aqui e guardados no WG (evita problema de escopo do $.evalFile)
13
+ $.evalFile(WG.P + "ae/camera.jsx");
14
+ $.evalFile(WG.P + "ae/digitar.jsx");
15
+ WG.CAMERA_criar = CAMERA_criar; WG.CAMERA_lerJSON = CAMERA_lerJSON; WG.CAMERA_encaixe = CAMERA_encaixe; WG.DIGITAR = DIGITAR;
16
+ // textos de letra (17/10): lidos por slot de ae/letra.json (O autor cola a letra; vazio = "reserva" em inglês)
17
+ $.evalFile(WG.P + "ae/letra.jsx");
18
+ WG.LETRA = LETRA;
19
+ // tempos de digitação: as palavras do slot entram na janela [d0, d1] que o original usa na tela,
20
+ // na mesma proporção dos tempos em que são cantadas (palavra 1 começa em d0; a última termina em d1)
21
+ // início de cada palavra NA TELA do original (contado quadro a quadro; a voz vem antes porque a câmera ainda chega)
22
+ WG.DIG = {
23
+ G1: { t: [17.20], fim: 17.60 }, G2: { t: [17.85, 18.12, 18.36], fim: 18.60 },
24
+ H1: { t: [19.17, 19.45, 19.85, 20.05], fim: 20.33 }, H2: { t: [20.85, 21.12, 21.40, 21.78, 22.00], fim: 22.25 },
25
+ I1: { t: [22.48, 22.70, 23.20], fim: 23.45 },
26
+ K1: { t: [28.33], fim: 29.00 }, K2: { t: [29.25, 29.55, 29.80, 30.10, 30.40, 30.70, 30.85], fim: 31.00 },
27
+ K3: { t: [31.15, 31.29], fim: 31.75 }, K4: { t: [32.45, 32.62, 32.85, 32.92, 33.00], fim: 33.30 }
28
+ };
29
+ // tempos de digitação do slot: os do original se o texto tem o mesmo nº de palavras; senão, proporcionais à voz na mesma janela
30
+ WG.tempoDig = function (id, s) {
31
+ var o = WG.DIG[id];
32
+ if (o.t.length == s.palavras.length) return o.t;
33
+ return WG.janela(s, o.t[0], o.fim);
34
+ };
35
+ WG.janela = function (s, d0, d1) {
36
+ var t = s.tempos, n = t.length, r = [];
37
+ if (n == 1) return [d0];
38
+ var passo = (t[n - 1] - t[0]) / (n - 1), tot = t[n - 1] - t[0] + passo;
39
+ for (var i = 0; i < n; i++) r.push(d0 + (t[i] - t[0]) / tot * (d1 - d0));
40
+ return r;
41
+ };
42
+ WG.FPS = 24;
43
+ // ---- constantes compartilhadas entre cenas (para os "fundos" das cenas vizinhas)
44
+ WG.H_MAPA = { x: -226, y: 34, k: 1.1 }; // mapa-satelite.png: canto sup. esq. no mundo H e escala (px do mundo por px da imagem)
45
+ WG.H_M1 = [470, 408]; // marcador 1 (@mari.frames, anel amarelo) no mundo H
46
+ WG.H_M1_R = 47; // raio externo do marcador (anel incluso)
47
+ WG.AMARELO = "#F5AB06";
48
+ // página grande da busca de imagens (cena I): grupo com coordenadas locais = tela do original em 23,083
49
+ WG.I_PAG = { anc: [540, 540], pos: [2140.78, 1228.53], esc: 263.92, rot: 2.534 }; // câmera de I no quadro 23,083 (onde a página foi medida)
50
+ WG.I_CEL = { c1: [405, 270, 186, 188], c2: [597, 270, 435, 188], c3: [405, 464, 372, 196], c4: [783, 464, 249, 196], r: 22 }; // c1 tirada do recorte do mapa em H (22,2) levado pela câmera
51
+ WG.I_IMGS = ["assets/I-imagens/ceu-1.png", "assets/I-imagens/ceu-2.png", "assets/I-imagens/ceu-3.png", "assets/I-imagens/ceu-4.png"];
52
+ // ponto local da página grande -> mundo I
53
+ WG.iLocalParaMundo = function (p) {
54
+ var r = WG.I_PAG.rot * Math.PI / 180, e = WG.I_PAG.esc / 100, dx = p[0] - WG.I_PAG.anc[0], dy = p[1] - WG.I_PAG.anc[1];
55
+ return [WG.I_PAG.pos[0] + e * (Math.cos(r) * dx - Math.sin(r) * dy), WG.I_PAG.pos[1] + e * (Math.sin(r) * dx + Math.cos(r) * dy)];
56
+ };
57
+ // ponto do mundo B -> mundo A (mesma tela no instante t; ca, cb = câmeras)
58
+ WG.mundoBparaA = function (W, ca, cb) {
59
+ var e = Math.pow(2, cb.z - ca.z), r = (cb.g - ca.g) * Math.PI / 180, dx = W[0] - cb.mx, dy = W[1] - cb.my;
60
+ return [ca.mx + e * (Math.cos(r) * dx - Math.sin(r) * dy), ca.my + e * (Math.sin(r) * dx + Math.cos(r) * dy)];
61
+ };
62
+
63
+ WG.item = function (nome) {
64
+ for (var i = 1; i <= app.project.numItems; i++) if (app.project.item(i).name == nome) return app.project.item(i);
65
+ return null;
66
+ };
67
+ WG.pasta = function (nome) {
68
+ var f = WG.item(nome);
69
+ if (!f) f = app.project.items.addFolder(nome);
70
+ return f;
71
+ };
72
+ WG.comp = function (nome, w, h, pasta) {
73
+ var c = WG.item(nome);
74
+ if (c && c instanceof CompItem) {
75
+ while (c.numLayers > 0) c.layer(1).remove();
76
+ c.width = w; c.height = h;
77
+ } else {
78
+ c = app.project.items.addComp(nome, w, h, 1, WG.DUR, WG.FPS);
79
+ }
80
+ if (pasta) c.parentFolder = pasta;
81
+ c.duration = WG.DUR; c.frameRate = WG.FPS;
82
+ c.motionBlur = true; c.shutterAngle = 90; c.shutterPhase = -45;
83
+ c.motionBlurSamplesPerFrame = 16; c.motionBlurAdaptiveSampleLimit = 128;
84
+ c.bgColor = [0, 0, 0];
85
+ return c;
86
+ };
87
+ WG._foot = {};
88
+ WG.footage = function (rel) {
89
+ if (WG._foot[rel]) return WG._foot[rel];
90
+ var f = new File(WG.P + rel);
91
+ for (var i = 1; i <= app.project.numItems; i++) {
92
+ var it = app.project.item(i);
93
+ if (it instanceof FootageItem && it.file && it.file.fsName == f.fsName) { WG._foot[rel] = it; return it; }
94
+ }
95
+ var io = new ImportOptions(f);
96
+ var it2 = app.project.importFile(io);
97
+ it2.parentFolder = WG.pasta("wg assets");
98
+ WG._foot[rel] = it2;
99
+ return it2;
100
+ };
101
+ WG.cor = function (hex) {
102
+ hex = hex.replace("#", "");
103
+ return [parseInt(hex.substr(0, 2), 16) / 255, parseInt(hex.substr(2, 2), 16) / 255, parseInt(hex.substr(4, 2), 16) / 255];
104
+ };
105
+ WG.tr = function (L) { return L.property("ADBE Transform Group"); };
106
+ // define o transform (sempre DEPOIS de L.parent = pai, porque o AE compensa ao parentear)
107
+ WG.pos = function (L, anc, pos, esc, rot) {
108
+ var t = WG.tr(L);
109
+ t.property("ADBE Anchor Point").setValue(anc);
110
+ t.property("ADBE Position").setValue(pos);
111
+ t.property("ADBE Scale").setValue(esc || [100, 100]);
112
+ t.property("ADBE Rotate Z").setValue(rot || 0);
113
+ t.property("ADBE Opacity").setValue(100);
114
+ };
115
+ WG.nulo = function (comp, pai, nome, anc, pos, esc, rot) {
116
+ var L = comp.layers.addNull(comp.duration); L.name = nome; L.enabled = false;
117
+ if (pai) L.parent = pai;
118
+ WG.pos(L, anc || [0, 0], pos || [0, 0], esc, rot);
119
+ return L;
120
+ };
121
+ // ---- formas (camada de forma vetorial)
122
+ // o: {x, y, w, h, r, cor, alfa, traco, tracoL, elipse:true}
123
+ WG.forma = function (comp, pai, nome, o) {
124
+ var L = comp.layers.addShape(); L.name = nome;
125
+ if (pai) L.parent = pai;
126
+ var root = L.property("ADBE Root Vectors Group");
127
+ root.addProperty("ADBE Vector Group");
128
+ var v = root.property(1).property("ADBE Vectors Group");
129
+ v.addProperty(o.elipse ? "ADBE Vector Shape - Ellipse" : "ADBE Vector Shape - Rect");
130
+ if (o.cor) v.addProperty("ADBE Vector Graphic - Fill");
131
+ if (o.traco) v.addProperty("ADBE Vector Graphic - Stroke");
132
+ v = L.property("ADBE Root Vectors Group").property(1).property("ADBE Vectors Group");
133
+ if (o.elipse) v.property("ADBE Vector Shape - Ellipse").property("ADBE Vector Ellipse Size").setValue([o.w, o.h]);
134
+ else {
135
+ v.property("ADBE Vector Shape - Rect").property("ADBE Vector Rect Size").setValue([o.w, o.h]);
136
+ v.property("ADBE Vector Shape - Rect").property("ADBE Vector Rect Roundness").setValue(o.r || 0);
137
+ }
138
+ if (o.cor) v.property("ADBE Vector Graphic - Fill").property("ADBE Vector Fill Color").setValue(WG.cor(o.cor));
139
+ if (o.traco) {
140
+ v.property("ADBE Vector Graphic - Stroke").property("ADBE Vector Stroke Color").setValue(WG.cor(o.traco));
141
+ v.property("ADBE Vector Graphic - Stroke").property("ADBE Vector Stroke Width").setValue(o.tracoL || 2);
142
+ }
143
+ WG.pos(L, [0, 0], [o.x + o.w / 2, o.y + o.h / 2]);
144
+ if (o.alfa !== undefined) WG.tr(L).property("ADBE Opacity").setValue(o.alfa);
145
+ L.motionBlur = true;
146
+ return L;
147
+ };
148
+ WG.rectProp = function (L, nome) { // nome: "ADBE Vector Rect Size" | "...Position" | "...Roundness"
149
+ return L.property("ADBE Root Vectors Group").property(1).property("ADBE Vectors Group").property("ADBE Vector Shape - Rect").property(nome);
150
+ };
151
+ // ---- texto de ponto. o: {x, y (linha de base), fonte, tam, cor, just: "E"|"C"|"D", track, italico, traco, tracoL}
152
+ WG.texto = function (comp, pai, nome, s, o) {
153
+ var L = comp.layers.addText(s); L.name = nome;
154
+ if (pai) L.parent = pai;
155
+ var tp = L.property("ADBE Text Properties").property("ADBE Text Document");
156
+ var td = tp.value;
157
+ td.resetCharStyle(); td.resetParagraphStyle();
158
+ td.font = o.fonte; td.fontSize = o.tam; td.applyFill = true; td.fillColor = WG.cor(o.cor || "#FFFFFF");
159
+ if (o.traco) { td.applyStroke = true; td.strokeColor = WG.cor(o.traco); td.strokeWidth = o.tracoL || 2; td.strokeOverFill = false; }
160
+ else td.applyStroke = false;
161
+ td.justification = (o.just == "C") ? ParagraphJustification.CENTER_JUSTIFY : (o.just == "D") ? ParagraphJustification.RIGHT_JUSTIFY : ParagraphJustification.LEFT_JUSTIFY;
162
+ td.tracking = o.track || 0;
163
+ if (o.italico) td.fauxItalic = true;
164
+ if (o.negrito) td.fauxBold = true;
165
+ if (o.entrelinha) { td.autoLeading = false; td.leading = o.entrelinha; }
166
+ if (o.hscale) td.horizontalScale = o.hscale / 100; // TextDocument usa 1 = 100%
167
+ tp.setValue(td);
168
+ WG.pos(L, [0, 0], [o.x, o.y]);
169
+ L.motionBlur = true;
170
+ return L;
171
+ };
172
+ // ---- caminhos de máscara
173
+ WG.formaRet = function (x, y, w, h, r) {
174
+ var s = new Shape();
175
+ r = Math.max(0, Math.min(r || 0, w / 2, h / 2));
176
+ if (r < 0.01) {
177
+ s.vertices = [[x, y], [x + w, y], [x + w, y + h], [x, y + h]];
178
+ s.inTangents = [[0, 0], [0, 0], [0, 0], [0, 0]]; s.outTangents = [[0, 0], [0, 0], [0, 0], [0, 0]];
179
+ } else {
180
+ var k = r * 0.5523;
181
+ s.vertices = [[x + r, y], [x + w - r, y], [x + w, y + r], [x + w, y + h - r], [x + w - r, y + h], [x + r, y + h], [x, y + h - r], [x, y + r]];
182
+ s.inTangents = [[-k, 0], [0, 0], [0, -k], [0, 0], [k, 0], [0, 0], [0, k], [0, 0]];
183
+ s.outTangents = [[0, 0], [k, 0], [0, 0], [0, k], [0, 0], [-k, 0], [0, 0], [0, -k]];
184
+ }
185
+ s.closed = true; return s;
186
+ };
187
+ WG.formaElipse = function (cx, cy, rx, ry) {
188
+ var s = new Shape(); var kx = rx * 0.5523, ky = ry * 0.5523;
189
+ s.vertices = [[cx, cy - ry], [cx + rx, cy], [cx, cy + ry], [cx - rx, cy]];
190
+ s.inTangents = [[-kx, 0], [0, -ky], [kx, 0], [0, ky]];
191
+ s.outTangents = [[kx, 0], [0, ky], [-kx, 0], [0, -ky]];
192
+ s.closed = true; return s;
193
+ };
194
+ WG.mascara = function (L, shape, nome) {
195
+ var m = L.property("ADBE Mask Parade").addProperty("ADBE Mask Atom");
196
+ m.name = nome || "mascara";
197
+ L.property("ADBE Mask Parade").property(m.name).property("ADBE Mask Shape").setValue(shape);
198
+ return L.property("ADBE Mask Parade").property(m.name);
199
+ };
200
+ // ---- imagem recortada (cobre w x h, centro opcional deslocado), cantos arredondados r. o: {x,y,w,h,r, fx, fy (0..1 foco), circulo}
201
+ WG.imagem = function (comp, pai, nome, rel, o) {
202
+ var it = WG.footage(rel);
203
+ var L = comp.layers.add(it); L.name = nome;
204
+ if (pai) L.parent = pai;
205
+ var fw = it.width, fh = it.height;
206
+ var sc = Math.max(o.w / fw, o.h / fh) * (o.zoom || 1);
207
+ var mw = o.w / sc, mh = o.h / sc;
208
+ var fx = (o.fx === undefined) ? 0.5 : o.fx, fy = (o.fy === undefined) ? 0.5 : o.fy;
209
+ var cx = mw / 2 + (fw - mw) * fx, cy = mh / 2 + (fh - mh) * fy;
210
+ WG.pos(L, [cx, cy], [o.x + o.w / 2, o.y + o.h / 2], [sc * 100, sc * 100]);
211
+ if (o.circulo) WG.mascara(L, WG.formaElipse(cx, cy, mw / 2, mh / 2), "circulo");
212
+ else WG.mascara(L, WG.formaRet(cx - mw / 2, cy - mh / 2, mw, mh, (o.r || 0) / sc), "recorte");
213
+ L.motionBlur = true;
214
+ L.quality = LayerQuality.BEST;
215
+ return L;
216
+ };
217
+ // ---- ease robusto: tenta 1, 2 e 3 dimensões (Scale pede 3 mesmo em camada 2D; Position espacial pede 1)
218
+ WG.ease = function (prop, k, inInf, outInf) {
219
+ var tent = [1, 2, 3];
220
+ for (var j = 0; j < tent.length; j++) {
221
+ var a = [], b = [];
222
+ for (var d = 0; d < tent[j]; d++) { a.push(new KeyframeEase(0, Math.max(0.1, inInf))); b.push(new KeyframeEase(0, Math.max(0.1, outInf))); }
223
+ try { prop.setTemporalEaseAtKey(k, a, b); return true; } catch (e) {}
224
+ }
225
+ return false;
226
+ };
227
+ // ---- chaves com suavização. lista = [[t, v], ...]; inf = influência (0..100) da suavização
228
+ WG.chaves = function (prop, lista, inf, linear) {
229
+ var ts = [], vs = [], i;
230
+ for (i = 0; i < lista.length; i++) { ts.push(lista[i][0]); vs.push(lista[i][1]); }
231
+ prop.setValuesAtTimes(ts, vs);
232
+ for (i = 1; i <= prop.numKeys; i++) {
233
+ if (linear) { prop.setInterpolationTypeAtKey(i, KeyframeInterpolationType.LINEAR, KeyframeInterpolationType.LINEAR); continue; }
234
+ prop.setInterpolationTypeAtKey(i, KeyframeInterpolationType.BEZIER, KeyframeInterpolationType.BEZIER);
235
+ WG.ease(prop, i, inf || 70, inf || 70);
236
+ if (prop.isSpatial) { try { prop.setSpatialAutoBezierAtKey(i, false); prop.setSpatialContinuousAtKey(i, false); } catch (er2) {} }
237
+ }
238
+ };
239
+ // ---- duas chaves com saída rápida e chegada lenta (cauda longa, como as curvas do autor)
240
+ // inSaida = influência na saída da 1ª chave (baixo = arranca rápido); inChegada = influência na chegada da 2ª (alto = pousa devagar)
241
+ WG.chave2 = function (prop, t0, v0, t1, v1, inSaida, inChegada) {
242
+ prop.setValuesAtTimes([t0, t1], [v0, v1]);
243
+ var n = prop.numKeys, k0 = prop.nearestKeyIndex(t0), k1 = prop.nearestKeyIndex(t1);
244
+ prop.setInterpolationTypeAtKey(k0, KeyframeInterpolationType.BEZIER, KeyframeInterpolationType.BEZIER);
245
+ prop.setInterpolationTypeAtKey(k1, KeyframeInterpolationType.BEZIER, KeyframeInterpolationType.BEZIER);
246
+ WG.ease(prop, k0, 33, inSaida);
247
+ WG.ease(prop, k1, inChegada, 33);
248
+ if (prop.isSpatial) { try { prop.setSpatialAutoBezierAtKey(k0, false); prop.setSpatialAutoBezierAtKey(k1, false); } catch (er) {} }
249
+ };
250
+ // ---- câmera: CAM a partir da câmera ajustada; devolve {cam, json}
251
+ WG.camera = function (compMundo, id) {
252
+ var arq = WG.P + "camera/cena-" + id + "-ajustada.json";
253
+ var cam = WG.CAMERA_criar(compMundo, arq);
254
+ return { cam: cam, d: WG.CAMERA_lerJSON(arq) };
255
+ };
256
+ WG.camValor = function (cam, nome, t) { return cam.property("ADBE Effect Parade").property(nome).property(1).valueAtTime(t, false); };
257
+ WG.camEm = function (cam, t) {
258
+ return { z: WG.camValor(cam, "Zoom (log2)", t), mx: WG.camValor(cam, "Mira X", t), my: WG.camValor(cam, "Mira Y", t), g: WG.camValor(cam, "Giro", t) };
259
+ };
260
+ // interpola a câmera direto do JSON (para usar a câmera de OUTRA cena)
261
+ WG.camJSON = function (d, t) {
262
+ function iv(lst) {
263
+ if (t <= lst[0][0]) return lst[0][1];
264
+ for (var i = 1; i < lst.length; i++) if (lst[i][0] >= t) { var u = (t - lst[i - 1][0]) / (lst[i][0] - lst[i - 1][0]); return lst[i - 1][1] * (1 - u) + lst[i][1] * u; }
265
+ return lst[lst.length - 1][1];
266
+ }
267
+ return { z: iv(d.chaves.zoom), mx: iv(d.chaves.mx), my: iv(d.chaves.my), g: iv(d.chaves.giro) };
268
+ };
269
+ // nulo que leva o mundo de outra cena (B) para dentro deste mundo (A), alinhado na tela no instante t:
270
+ // ponto Wb -> Wa = Ma + R(gb-ga) * 2^(zb-za) * (Wb - Mb)
271
+ WG.nuloOutroMundo = function (comp, cam, nome, ca, cb) {
272
+ var e = 100 * Math.pow(2, cb.z - ca.z);
273
+ return WG.nulo(comp, cam, nome, [cb.mx, cb.my], [ca.mx, ca.my], [e, e], cb.g - ca.g);
274
+ };
275
+ // ---- comp provisória de encaixe (sólido cinza + nome)
276
+ WG.provisoria = function (nome) {
277
+ var c = WG.item(nome);
278
+ if (c && c instanceof CompItem) return c;
279
+ c = app.project.items.addComp(nome, 1080, 1080, 1, WG.DUR, WG.FPS);
280
+ c.parentFolder = WG.pasta("wg encaixes provisorios");
281
+ c.layers.addSolid([0.45, 0.45, 0.47], "cinza", 1080, 1080, 1, WG.DUR);
282
+ var g = c.layers.addShape(); g.name = "grade";
283
+ var gr = g.property("ADBE Root Vectors Group"); gr.addProperty("ADBE Vector Group");
284
+ var v = gr.property(1).property("ADBE Vectors Group"); v.addProperty("ADBE Vector Shape - Rect"); v.addProperty("ADBE Vector Graphic - Stroke");
285
+ v = g.property("ADBE Root Vectors Group").property(1).property("ADBE Vectors Group");
286
+ v.property("ADBE Vector Shape - Rect").property("ADBE Vector Rect Size").setValue([1000, 1000]);
287
+ v.property("ADBE Vector Graphic - Stroke").property("ADBE Vector Stroke Color").setValue([1, 1, 1]);
288
+ v.property("ADBE Vector Graphic - Stroke").property("ADBE Vector Stroke Width").setValue(12);
289
+ WG.pos(g, [0, 0], [540, 540]);
290
+ var t = c.layers.addText(nome); var tp = t.property("ADBE Text Properties").property("ADBE Text Document"); var td = tp.value;
291
+ td.font = "Inter-Bold"; td.fontSize = 90; td.fillColor = [1, 1, 1]; td.justification = ParagraphJustification.CENTER_JUSTIFY; tp.setValue(td);
292
+ WG.pos(t, [0, 0], [540, 570]);
293
+ return c;
294
+ };
295
+ // ---- monta CENA <id>: camada MUNDO centrada + Corner Pin com os cantos medidos
296
+ WG.cena = function (id, compMundo, d, pasta) {
297
+ var cena = WG.comp("CENA " + id, 1080, 1080, pasta);
298
+ var L = cena.layers.add(compMundo); L.name = "MUNDO " + id;
299
+ WG.pos(L, [compMundo.width / 2, compMundo.height / 2], [540, 540]);
300
+ L.motionBlur = true; L.quality = LayerQuality.BEST;
301
+ if (d.cantos) {
302
+ L.property("ADBE Effect Parade").addProperty("ADBE Corner Pin");
303
+ var fx = L.property("ADBE Effect Parade").property("ADBE Corner Pin");
304
+ var nomes = ["ADBE Corner Pin-0001", "ADBE Corner Pin-0002", "ADBE Corner Pin-0003", "ADBE Corner Pin-0004"];
305
+ for (var k = 0; k < 4; k++) {
306
+ var ts = [], vs = [];
307
+ for (var i = 0; i < d.cantos.length; i++) { ts.push(d.cantos[i][0]); vs.push([d.cantos[i][1 + 2 * k], d.cantos[i][2 + 2 * k]]); }
308
+ var p = fx.property(nomes[k]); p.setValuesAtTimes(ts, vs);
309
+ for (var j = 1; j <= p.numKeys; j++) p.setInterpolationTypeAtKey(j, KeyframeInterpolationType.LINEAR, KeyframeInterpolationType.LINEAR);
310
+ }
311
+ }
312
+ return cena;
313
+ };
314
+
315
+ // remove sólidos/nulos que ficaram sem uso depois de refazer uma cena
316
+ WG.limparSolidos = function () {
317
+ for (var i = app.project.numItems; i >= 1; i--) {
318
+ var it = app.project.item(i);
319
+ if (it instanceof FootageItem && it.mainSource instanceof SolidSource && it.usedIn.length == 0) it.remove();
320
+ }
321
+ };
322
+
323
+ // ---- caminho livre em coordenadas do mundo (curva suave por Catmull-Rom). o: {fechado, cor, alfa, traco, tracoL, tracejado:[traço, vão], reto}
324
+ WG.caminho = function (comp, pai, nome, pts, o) {
325
+ var L = comp.layers.addShape(); L.name = nome;
326
+ if (pai) L.parent = pai;
327
+ var root = L.property("ADBE Root Vectors Group"); root.addProperty("ADBE Vector Group");
328
+ var v = root.property(1).property("ADBE Vectors Group");
329
+ v.addProperty("ADBE Vector Shape - Group");
330
+ if (o.cor) v.addProperty("ADBE Vector Graphic - Fill");
331
+ if (o.traco) v.addProperty("ADBE Vector Graphic - Stroke");
332
+ v = L.property("ADBE Root Vectors Group").property(1).property("ADBE Vectors Group");
333
+ var n = pts.length, s = new Shape(), ins = [], outs = [], i;
334
+ for (i = 0; i < n; i++) {
335
+ var a = pts[(i - 1 + n) % n], b = pts[(i + 1) % n];
336
+ if (o.reto || (!o.fechado && (i == 0 || i == n - 1))) { ins.push([0, 0]); outs.push([0, 0]); continue; }
337
+ var tx = (b[0] - a[0]) / 6, ty = (b[1] - a[1]) / 6;
338
+ ins.push([-tx, -ty]); outs.push([tx, ty]);
339
+ }
340
+ s.vertices = pts; s.inTangents = ins; s.outTangents = outs; s.closed = !!o.fechado;
341
+ v.property("ADBE Vector Shape - Group").property("ADBE Vector Shape").setValue(s);
342
+ if (o.cor) v.property("ADBE Vector Graphic - Fill").property("ADBE Vector Fill Color").setValue(WG.cor(o.cor));
343
+ if (o.traco) {
344
+ var st = v.property("ADBE Vector Graphic - Stroke");
345
+ st.property("ADBE Vector Stroke Color").setValue(WG.cor(o.traco));
346
+ st.property("ADBE Vector Stroke Width").setValue(o.tracoL || 2);
347
+ st.property("ADBE Vector Stroke Line Cap").setValue(2); st.property("ADBE Vector Stroke Line Join").setValue(2);
348
+ if (o.tracejado) {
349
+ st.property("ADBE Vector Stroke Dashes").addProperty("ADBE Vector Stroke Dash 1");
350
+ st.property("ADBE Vector Stroke Dashes").addProperty("ADBE Vector Stroke Gap 1");
351
+ st = L.property("ADBE Root Vectors Group").property(1).property("ADBE Vectors Group").property("ADBE Vector Graphic - Stroke");
352
+ st.property("ADBE Vector Stroke Dashes").property("ADBE Vector Stroke Dash 1").setValue(o.tracejado[0]);
353
+ st.property("ADBE Vector Stroke Dashes").property("ADBE Vector Stroke Gap 1").setValue(o.tracejado[1]);
354
+ }
355
+ }
356
+ WG.pos(L, [0, 0], [0, 0]);
357
+ if (o.alfa !== undefined) WG.tr(L).property("ADBE Opacity").setValue(o.alfa);
358
+ L.motionBlur = true;
359
+ return L;
360
+ };
@@ -0,0 +1,13 @@
1
+ """Tira PNG de uma página HTML do jornal com Playwright (Chromium). Uso:
2
+ python -I render_html.py arquivo.html "?p=1" largura altura escala saida.png"""
3
+ import sys, pathlib
4
+ from playwright.sync_api import sync_playwright
5
+ html, q, w, h, dsf, out = sys.argv[1], sys.argv[2], int(sys.argv[3]), int(sys.argv[4]), float(sys.argv[5]), sys.argv[6]
6
+ url = pathlib.Path(html).resolve().as_uri() + q
7
+ with sync_playwright() as p:
8
+ b = p.chromium.launch()
9
+ pg = b.new_page(viewport={"width": w, "height": h}, device_scale_factor=dsf)
10
+ pg.goto(url); pg.wait_for_selector("body[data-ok='1']", timeout=20000); pg.wait_for_timeout(300)
11
+ pg.locator("#pg").screenshot(path=out, omit_background=True)
12
+ b.close()
13
+ print("ok", out)
@@ -0,0 +1,26 @@
1
+ # Renderiza as interfaces HTML das cenas C, D e E (agente w-midia) em PNG 3x com fundo transparente.
2
+ # Uso: python render_w-midia.py (todas) | python render_w-midia.py C-alttab/desktop.html (uma)
3
+ import sys, pathlib
4
+ from playwright.sync_api import sync_playwright
5
+
6
+ AQUI = pathlib.Path(__file__).resolve().parent
7
+ PAGINAS = { # html -> (largura, altura) em px CSS
8
+ "C-alttab/desktop.html": (1080, 1080),
9
+ "C-alttab/alttab.html": (1080, 1080),
10
+ "D-spotify/janela.html": (2002, 1292),
11
+ "E-notas/ui.html": (1900, 1250),
12
+ "E-notas/notas.html": (2400, 600),
13
+ }
14
+ alvo = sys.argv[1:] or list(PAGINAS)
15
+ with sync_playwright() as p:
16
+ nav = p.chromium.launch()
17
+ for rel in alvo:
18
+ w, h = PAGINAS[rel]
19
+ pg = nav.new_page(viewport={"width": w, "height": h}, device_scale_factor=3)
20
+ pg.goto((AQUI / rel).as_uri())
21
+ pg.wait_for_timeout(600)
22
+ saida = (AQUI / rel).with_suffix(".png")
23
+ pg.screenshot(path=str(saida), omit_background=True, full_page=False)
24
+ print("ok", saida.name, w * 3, "x", h * 3)
25
+ pg.close()
26
+ nav.close()
@@ -0,0 +1,30 @@
1
+ # inclinação das linhas de letra: para cada faixa de texto, ajusta y = a*x + b nos pixels de texto -> declive por linha
2
+ import sys, subprocess, numpy as np
3
+ from PIL import Image
4
+ REF = str(__import__("pathlib").Path(__file__).resolve().parents[2] / "ref" / "original-bt709.mp4") # cópia do original com cor marcada bt709 (o ae_see e o ffmpeg leem sem erro)
5
+ def ref_frame(t):
6
+ f = int(round(t * 24))
7
+ out = subprocess.run(["ffmpeg", "-v", "error", "-ss", str((f - 0.5) / 24), "-i", REF, "-frames:v", "1", "-f", "rawvideo", "-pix_fmt", "rgb24", "-"], capture_output=True).stdout
8
+ return np.frombuffer(out, np.uint8).reshape(1080, 1080, 3).astype(int)
9
+ def decl(a):
10
+ r, g, b = a[..., 0], a[..., 1], a[..., 2]
11
+ tx = ((b > 140) & (g > 100) & (b > r + 20)) | ((r > 200) & (g > 200) & (b > 200))
12
+ rows = tx.sum(1) > 25
13
+ res = []; i = 0
14
+ while i < 1080:
15
+ if rows[i]:
16
+ j = i
17
+ while j < 1080 and rows[j]: j += 1
18
+ if j - i > 15:
19
+ ys, xs = np.nonzero(tx[max(0, i - 15):min(1080, j + 15)])
20
+ if xs.max() - xs.min() > 300:
21
+ A = np.vstack([xs, np.ones_like(xs)]).T
22
+ a1, b1 = np.linalg.lstsq(A, ys + max(0, i - 15), rcond=None)[0]
23
+ res.append((int((i + j) / 2), round(a1 * 1000, 1)))
24
+ i = j
25
+ else: i += 1
26
+ return res
27
+ for i in range(1, len(sys.argv), 2):
28
+ t = float(sys.argv[i + 1])
29
+ print("t=%.3f REF (y, declive px/1000px) %s" % (t, decl(ref_frame(t))))
30
+ print(" NOS %s" % decl(np.asarray(Image.open(sys.argv[i]).convert("RGB")).astype(int)))
@@ -0,0 +1,36 @@
1
+ # mede no quadro: centros das linhas de letra (y), passo, x do início do texto e borda esq. do painel azul
2
+ import sys, subprocess, numpy as np
3
+ from PIL import Image
4
+ REF = str(__import__("pathlib").Path(__file__).resolve().parents[2] / "ref" / "original-bt709.mp4") # cópia do original com cor marcada bt709 (o ae_see e o ffmpeg leem sem erro)
5
+ def ref_frame(t):
6
+ f = int(round(t * 24))
7
+ out = subprocess.run(["ffmpeg", "-v", "error", "-ss", str((f - 0.5) / 24), "-i", REF, "-frames:v", "1", "-f", "rawvideo", "-pix_fmt", "rgb24", "-"], capture_output=True).stdout
8
+ return np.frombuffer(out, np.uint8).reshape(1080, 1080, 3).astype(int)
9
+ def medir(a):
10
+ r, g, b = a[..., 0], a[..., 1], a[..., 2]
11
+ azul = (abs(r - 0) < 25) & (abs(g - 51) < 22) & (abs(b - 90) < 25)
12
+ texto = (b > 140) & (g > 100) & (b > r + 20)
13
+ texto |= (r > 200) & (g > 200) & (b > 200)
14
+ # só texto que tem azul na mesma linha (dentro do painel)
15
+ rows = texto.sum(1)
16
+ on = rows > 25
17
+ lines = []; i = 0
18
+ while i < 1080:
19
+ if on[i]:
20
+ j = i
21
+ while j < 1080 and on[j]: j += 1
22
+ if j - i > 12: lines.append((i + j) / 2)
23
+ i = j
24
+ else: i += 1
25
+ xs = []
26
+ for y in lines:
27
+ cols = np.nonzero(texto[int(y) - 5:int(y) + 5].any(0))[0]
28
+ if len(cols): xs.append(cols.min())
29
+ mid = azul[540]; c = np.nonzero(mid)[0]
30
+ return lines, (int(np.median(xs)) if xs else None), (int(c.min()) if len(c) else None)
31
+ for i in range(1, len(sys.argv), 2):
32
+ t = float(sys.argv[i + 1]); o = np.asarray(Image.open(sys.argv[i]).convert("RGB")).astype(int); r = ref_frame(t)
33
+ lo, xo, bo = medir(o); lr, xr, br = medir(r)
34
+ pas = lambda L: (np.median(np.diff(L)) if len(L) > 1 else None)
35
+ print("t=%.3f REF linhas %s passo %s xtexto %s azul %s" % (t, [int(v) for v in lr], pas(lr), xr, br))
36
+ print(" NOS linhas %s passo %s xtexto %s azul %s" % ([int(v) for v in lo], pas(lo), xo, bo))
@@ -0,0 +1,27 @@
1
+ # mede na cena E: centro do círculo amarelo (UI fixa) e centros dos balões (fileira), nosso x original
2
+ import sys, subprocess, numpy as np, cv2
3
+ from PIL import Image
4
+ REF = str(__import__("pathlib").Path(__file__).resolve().parents[2] / "ref" / "original-bt709.mp4") # cópia do original com cor marcada bt709 (o ae_see e o ffmpeg leem sem erro)
5
+ def ref_frame(t):
6
+ f = int(round(t * 24))
7
+ out = subprocess.run(["ffmpeg", "-v", "error", "-ss", str((f - 0.5) / 24), "-i", REF, "-frames:v", "1", "-f", "rawvideo", "-pix_fmt", "rgb24", "-"], capture_output=True).stdout
8
+ return np.frombuffer(out, np.uint8).reshape(1080, 1080, 3).astype(int)
9
+ def medir(a):
10
+ r, g, b = a[..., 0], a[..., 1], a[..., 2]
11
+ am = (r > 200) & (g > 140) & (g < 210) & (b < 70); am[:780] = False
12
+ ys, xs = np.nonzero(am)
13
+ yel = (int(xs.mean()), int(ys.mean()), len(xs)) if len(xs) > 300 else None
14
+ bub = (abs(r - 31) < 7) & (abs(g - 33) < 7) & (abs(b - 37) < 7)
15
+ bub = cv2.morphologyEx(bub.astype(np.uint8), cv2.MORPH_OPEN, np.ones((5, 5), np.uint8))
16
+ n, lab, st, cen = cv2.connectedComponentsWithStats(bub)
17
+ bs = []
18
+ for i in range(1, n):
19
+ x, y, w, h, area = st[i]
20
+ if area > 3000 and w > 80 and h > 40: bs.append((int(x), int(x + w), int(y), int(y + h)))
21
+ bs.sort()
22
+ return yel, bs
23
+ for i in range(1, len(sys.argv), 2):
24
+ t = float(sys.argv[i + 1]); o = np.asarray(Image.open(sys.argv[i]).convert("RGB")).astype(int)
25
+ yo, bo = medir(o); yr, br = medir(ref_frame(t))
26
+ print("t=%.4f REF amarelo %s balões %s" % (t, yr, br))
27
+ print(" NOS amarelo %s balões %s" % (yo, bo))