primocode 8.18.1 → 8.20.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 (30) hide show
  1. package/bin/primocode.js +5 -2
  2. package/lib/act.js +25 -3
  3. package/package.json +1 -1
  4. package/studio/ferramentas/corte.md +46 -5
  5. package/studio/server.py +89 -2
  6. package/studio/voz.py +92 -11
  7. package/studio/web/js/audio.js +35 -2
  8. package/studio/web/js/player.js +98 -11
  9. package/studio/web/js/sfx.js +107 -0
  10. package/studio/web/tool.html +1 -0
  11. package/studio/web/view.html +1 -0
  12. package/studio/__pycache__/voz.cpython-311.pyc +0 -0
  13. package/studio/arquivos/corte-estatico-corte-a5bab.json +0 -150
  14. package/studio/arquivos/corte-founders-ai-teste-do-player-2de1d.json +0 -65
  15. package/studio/arquivos/corte-legado-teste.json +0 -1
  16. package/studio/arquivos/corte-legado2.json +0 -1
  17. package/studio/arquivos/corte-minimo-2a829.json +0 -24
  18. package/studio/arquivos/corte-ok-00a3b.json +0 -18
  19. package/studio/arquivos/corte-ok-1270e.json +0 -22
  20. package/studio/arquivos/corte-sweep-corte-cfb29.json +0 -147
  21. package/studio/arquivos/corte-visual-completo-78f50.json +0 -35
  22. package/studio/arquivos/grade-sweep-grade-0c2f1.json +0 -119
  23. package/studio/arquivos/prisma-estatico-prisma-d8740.json +0 -182
  24. package/studio/arquivos/prisma-sweep-prisma-4c58c.json +0 -166
  25. package/studio/arquivos/prisma-y-b0785.json +0 -52
  26. package/studio/arquivos/prosa-sweep-prosa-f29cf.json +0 -80
  27. package/studio/arquivos/tela-estatico-tela-c7daf.json +0 -90
  28. package/studio/arquivos/tela-sweep-tela-0d2bf.json +0 -84
  29. package/studio/arquivos/traco-estatico-traco-25872.json +0 -113
  30. package/studio/arquivos/traco-sweep-traco-0bcf4.json +0 -102
@@ -33,8 +33,17 @@
33
33
  function duracaoDe(i) {
34
34
  /* "duracao": "3s" (texto) fazia acc virar concatenação e o relógio dava
35
35
  vídeo de 00:00. Número são ou o padrão — nunca corrente de texto. */
36
- var d = Number(cenas[i] && cenas[i].duracao);
37
- return (isFinite(d) && d > 0) ? Math.min(60, d) : 4;
36
+ var c = cenas[i] || {};
37
+ var d = Number(c.duracao);
38
+ d = (isFinite(d) && d > 0) ? Math.min(60, d) : 4;
39
+ /* A narração pré-renderizada tem duração conhecida (o servidor mediu o
40
+ WAV e gravou `narracaoDur` na cena). A cena dura o que for MAIOR:
41
+ o que o autor pediu ou a fala inteira + um respiro. É isto que torna
42
+ a linha do tempo determinística — o "cena espera a voz" do laço vira
43
+ só a rede de segurança para narração sintetizada na hora. */
44
+ var n = Number(c.narracaoDur);
45
+ if (isFinite(n) && n > 0 && c.narracaoAudio) d = Math.max(d, Math.min(90, n + 0.4));
46
+ return d;
38
47
  }
39
48
  function total() { return cenas.reduce(function (s, _, i) { return s + duracaoDe(i); }, 0); }
40
49
  function inicioDe(i) { var s = 0; for (var k = 0; k < i; k++) s += duracaoDe(k); return s; }
@@ -129,6 +138,7 @@
129
138
 
130
139
  function ir(n, semRelogio) {
131
140
  if (!cenas.length) return;
141
+ var anterior = atual;
132
142
  atual = Math.max(0, Math.min(cenas.length - 1, n));
133
143
  Array.prototype.forEach.call(palco.children, function (no, i) {
134
144
  no.style.display = i === atual ? "block" : "none";
@@ -139,6 +149,17 @@
139
149
  contar(no);
140
150
  }
141
151
  });
152
+ /* SFX na entrada da cena — só durante a reprodução (navegar com as setas
153
+ não faz barulho) e nunca na primeira montagem. `doc.sfx === false`
154
+ desliga tudo; `cena.sfx` escolhe o efeito ("whoosh" | "impacto" |
155
+ "click" | "nenhum") e ganha do automático por transição. */
156
+ if (sfx && tocando && ehVideo && atual !== anterior && doc.sfx !== false) {
157
+ var cenaNova = cenas[atual] || {};
158
+ if (cenaNova.sfx !== "nenhum") {
159
+ if (cenaNova.sfx && sfx[cenaNova.sfx]) sfx[cenaNova.sfx]();
160
+ else sfx.transicao(cenaNova.transicao, atual);
161
+ }
162
+ }
142
163
  narrar();
143
164
  pintarApresentador();
144
165
  if (!semRelogio) decorrido = inicioDe(atual);
@@ -255,6 +276,7 @@
255
276
  function narrar() {
256
277
  if (typeof Narracao !== "undefined") Narracao.parar();
257
278
  if (vozGravada) { vozGravada.pause(); vozGravada = null; }
279
+ if (trilha && trilha.duck) trilha.duck(false);
258
280
  if (mudo || doc.narracao === false) return;
259
281
 
260
282
  var cena = cenas[atual] || {};
@@ -263,13 +285,35 @@
263
285
  if (cena.narracaoAudio) {
264
286
  vozGravada = new Audio(cena.narracaoAudio);
265
287
  vozGravada.volume = (doc.voz && doc.voz.volume != null) ? doc.voz.volume : 1;
288
+ /* Pelo grafo da trilha, quando ele existe: a voz entra na gravação MP4
289
+ sem "compartilhar áudio da aba", e a música cede espaço (duck)
290
+ enquanto a fala dura. Sem grafo, toca direto como antes. */
291
+ if (trilha && trilha.ctx && trilha.entradaVoz) {
292
+ try {
293
+ var fonteVoz = trilha.ctx.createMediaElementSource(vozGravada);
294
+ fonteVoz.connect(trilha.entradaVoz);
295
+ } catch (_) { /* elemento já conectado ou grafo indisponível */ }
296
+ if (trilha.duck) {
297
+ trilha.duck(true);
298
+ vozGravada.onended = function () { if (trilha && trilha.duck) trilha.duck(false); };
299
+ }
300
+ }
266
301
  var p = vozGravada.play();
267
302
  if (p && p.catch) p.catch(function () {});
268
303
  return;
269
304
  }
270
305
 
271
306
  if (typeof Narracao === "undefined" || !Narracao.disponivel()) return;
272
- if (cena.narracao) Narracao.falar(cena.narracao, doc.voz || {});
307
+ if (cena.narracao) {
308
+ if (trilha && trilha.duck) {
309
+ trilha.duck(true);
310
+ Narracao.falar(cena.narracao, doc.voz || {}).then(function () {
311
+ if (trilha && trilha.duck) trilha.duck(false);
312
+ });
313
+ } else {
314
+ Narracao.falar(cena.narracao, doc.voz || {});
315
+ }
316
+ }
273
317
  }
274
318
 
275
319
  /* ----------------------------------------------------- apresentador --- */
@@ -317,11 +361,18 @@
317
361
 
318
362
  /* ------------------------------------------------------------ trilha -- */
319
363
 
364
+ var sfx = null;
365
+
320
366
  function prepararTrilha() {
321
- var cfg = doc.trilha;
322
- if (!cfg || (!cfg.src && cfg.tipo !== "gerada")) return;
323
367
  if (typeof criarTrilha !== "function") return;
368
+ var cfg = doc.trilha;
369
+ /* Sem trilha o grafo ainda nasce (tipo "nenhuma"): é por ele que a
370
+ narração e os SFX entram na gravação MP4. */
371
+ if (!cfg || (!cfg.src && cfg.tipo !== "gerada")) cfg = { tipo: "nenhuma" };
324
372
  trilha = criarTrilha(cfg, function (msg) { aviso(msg, 3000); });
373
+ if (trilha && trilha.ctx && trilha.no && typeof criarSfx === "function" && doc.sfx !== false) {
374
+ sfx = criarSfx(trilha.ctx, trilha.no);
375
+ }
325
376
  }
326
377
 
327
378
  /* --------------------------------------------------------- transporte -- */
@@ -337,7 +388,7 @@
337
388
  '<div class="tp-tempo" id="tp-total">00:00</div>' +
338
389
  '<button class="tp-btn pequeno" id="tp-som" title="Mudo (M)"></button>' +
339
390
  '<input class="tp-vol" id="tp-vol" type="range" min="0" max="100" value="70">' +
340
- '<button class="tp-btn texto" id="tp-gravar" title="Gravar em .webm">Gravar</button>';
391
+ '<button class="tp-btn texto primo" id="tp-gravar" title="Baixar este vídeo como arquivo">Baixar MP4</button>';
341
392
  document.body.appendChild(transporte);
342
393
 
343
394
  document.getElementById("tp-tocar").onclick = function () { tocando ? pausar() : tocar(); };
@@ -393,14 +444,47 @@
393
444
  iniciarGravacao();
394
445
  }
395
446
 
447
+ /* O melhor formato que este navegador sabe gravar.
448
+ *
449
+ * A ordem importa: H.264 com AAC é o MP4 que toca em qualquer lugar —
450
+ * WhatsApp, Instagram, PowerPoint, TV. AV1 em MP4 é MP4 de verdade mas ainda
451
+ * não toca em tudo, então vem depois. O webm é o último recurso: abre em
452
+ * navegador e pouco mais.
453
+ */
454
+ var FORMATOS = [
455
+ "video/mp4;codecs=avc1.42E01E,mp4a.40.2",
456
+ "video/mp4;codecs=avc1,mp4a.40.2",
457
+ "video/mp4;codecs=avc1",
458
+ "video/mp4",
459
+ "video/webm;codecs=vp9,opus",
460
+ "video/webm",
461
+ ];
462
+
463
+ function escolherFormato() {
464
+ for (var i = 0; i < FORMATOS.length; i++) {
465
+ if (MediaRecorder.isTypeSupported(FORMATOS[i])) return FORMATOS[i];
466
+ }
467
+ return "video/webm";
468
+ }
469
+
470
+ function gravaMp4() { return /mp4/.test(escolherFormato()); }
471
+
396
472
  function iniciarGravacao() {
397
473
  if (!navigator.mediaDevices || !navigator.mediaDevices.getDisplayMedia) {
398
474
  return aviso("este navegador não grava a tela", 3000);
399
475
  }
400
476
  // audio:true deixa o usuário marcar "compartilhar áudio da aba" — é assim
401
477
  // que a narração falada entra na gravação
478
+ // preferCurrentTab tira o passo de escolher a janela: o Chrome já vem
479
+ // com ESTA aba selecionada, então baixar vira um clique e um "permitir"
480
+ // em vez de um clique, uma escolha e um "permitir".
402
481
  navigator.mediaDevices.getDisplayMedia({
403
482
  video: { frameRate: 30 }, audio: true,
483
+ preferCurrentTab: true, selfBrowserSurface: "include",
484
+ }).catch(function () {
485
+ // Navegador que não conhece preferCurrentTab recusa o pedido inteiro:
486
+ // repete sem as opções novas em vez de falhar.
487
+ return navigator.mediaDevices.getDisplayMedia({ video: { frameRate: 30 }, audio: true });
404
488
  }).then(function (fluxo) {
405
489
  fluxoTela = fluxo;
406
490
  var faixas = fluxo.getVideoTracks();
@@ -410,11 +494,14 @@
410
494
  }
411
495
  var misto = new MediaStream(faixas);
412
496
  pedacos = [];
413
- // MP4 primeiro, quando o navegador sabe gravar mp4 (Safari sabe;
414
- // Chrome grava webm). O usuário pediu "baixar em mp4": onde dá, dá.
415
- var tipo = MediaRecorder.isTypeSupported("video/mp4") ? "video/mp4"
416
- : MediaRecorder.isTypeSupported("video/webm;codecs=vp9,opus")
417
- ? "video/webm;codecs=vp9,opus" : "video/webm";
497
+ // MP4 primeiro, e testando os codecs NOMEADOS antes do genérico.
498
+ //
499
+ // Testar só "video/mp4" perdia MP4 em navegador que existe: o Chrome
500
+ // responde false para o nome solto e true para
501
+ // "video/mp4;codecs=avc1.42E01E,mp4a.40.2". Quem pediu MP4 recebia
502
+ // webm à toa. A lista vai do mais compatível (H.264 + AAC, que toca em
503
+ // tudo) para o menos, e só cai no webm quando não há MP4 nenhum.
504
+ var tipo = escolherFormato();
418
505
  gravador = new MediaRecorder(misto, { mimeType: tipo, videoBitsPerSecond: 8000000 });
419
506
  gravador.ondataavailable = function (ev) { if (ev.data.size) pedacos.push(ev.data); };
420
507
  gravador.onstop = baixarGravacao;
@@ -0,0 +1,107 @@
1
+ /* ==========================================================================
2
+ sfx.js — efeitos sonoros do Corte, sintetizados na hora.
3
+
4
+ Nenhum arquivo, nenhuma licença: whoosh é ruído filtrado com varredura,
5
+ impacto é um seno grave despencando, click é um blip curto. Tudo entra no
6
+ mesmo grafo da trilha (via `destino`), então a gravação MP4 captura os
7
+ efeitos junto — sem depender de "compartilhar áudio da aba".
8
+
9
+ Uso:
10
+ var sfx = criarSfx(ctx, destino); // destino: nó do grafo (compressor)
11
+ sfx.whoosh(); // transição de cena
12
+ sfx.impacto(); // ênfase (flash, número grande)
13
+ sfx.click(); // entrada de elemento, feedback discreto
14
+
15
+ O volume de cada efeito já vem calibrado para sentar SOB a narração.
16
+ ========================================================================== */
17
+
18
+ function criarSfx(ctx, destino) {
19
+ "use strict";
20
+ if (!ctx || !destino) return null;
21
+
22
+ var saida = ctx.createGain();
23
+ saida.gain.value = 1;
24
+ saida.connect(destino);
25
+
26
+ var ruido = null;
27
+ function bufferRuido() {
28
+ if (ruido) return ruido;
29
+ ruido = ctx.createBuffer(1, ctx.sampleRate * 1.2, ctx.sampleRate);
30
+ var d = ruido.getChannelData(0);
31
+ for (var i = 0; i < d.length; i++) d[i] = Math.random() * 2 - 1;
32
+ return ruido;
33
+ }
34
+
35
+ /* Varredura de ruído — o "passar de página" do vídeo. `variacao` muda o
36
+ miolo da varredura para os whooshes não saírem todos idênticos. */
37
+ function whoosh(variacao) {
38
+ var agora = ctx.currentTime;
39
+ var v = (variacao == null ? Math.random() : variacao) % 1;
40
+ var s = ctx.createBufferSource(), g = ctx.createGain(), f = ctx.createBiquadFilter();
41
+ s.buffer = bufferRuido();
42
+ f.type = "bandpass";
43
+ f.Q.value = 1.1;
44
+ f.frequency.setValueAtTime(300 + v * 300, agora);
45
+ f.frequency.exponentialRampToValueAtTime(2200 + v * 1400, agora + 0.16);
46
+ f.frequency.exponentialRampToValueAtTime(500, agora + 0.42);
47
+ g.gain.setValueAtTime(0.0001, agora);
48
+ g.gain.exponentialRampToValueAtTime(0.11, agora + 0.10);
49
+ g.gain.exponentialRampToValueAtTime(0.0001, agora + 0.45);
50
+ s.connect(f); f.connect(g); g.connect(saida);
51
+ s.start(agora); s.stop(agora + 0.5);
52
+ }
53
+
54
+ /* Seno grave despencando + um sopro de ruído no ataque. */
55
+ function impacto() {
56
+ var agora = ctx.currentTime;
57
+ var o = ctx.createOscillator(), g = ctx.createGain();
58
+ o.type = "sine";
59
+ o.frequency.setValueAtTime(120, agora);
60
+ o.frequency.exponentialRampToValueAtTime(36, agora + 0.5);
61
+ g.gain.setValueAtTime(0.30, agora);
62
+ g.gain.exponentialRampToValueAtTime(0.0001, agora + 0.9);
63
+ o.connect(g); g.connect(saida);
64
+ o.start(agora); o.stop(agora + 1.0);
65
+
66
+ var s = ctx.createBufferSource(), gr = ctx.createGain(), f = ctx.createBiquadFilter();
67
+ s.buffer = bufferRuido();
68
+ f.type = "lowpass";
69
+ f.frequency.value = 900;
70
+ gr.gain.setValueAtTime(0.09, agora);
71
+ gr.gain.exponentialRampToValueAtTime(0.0001, agora + 0.22);
72
+ s.connect(f); f.connect(gr); gr.connect(saida);
73
+ s.start(agora); s.stop(agora + 0.3);
74
+ }
75
+
76
+ /* Blip de interface: curto, agudo, discreto. */
77
+ function click() {
78
+ var agora = ctx.currentTime;
79
+ var o = ctx.createOscillator(), g = ctx.createGain();
80
+ o.type = "sine";
81
+ o.frequency.setValueAtTime(2100, agora);
82
+ g.gain.setValueAtTime(0.06, agora);
83
+ g.gain.exponentialRampToValueAtTime(0.0001, agora + 0.05);
84
+ o.connect(g); g.connect(saida);
85
+ o.start(agora); o.stop(agora + 0.07);
86
+ }
87
+
88
+ /* O efeito certo para a ENTRADA de uma cena, pela transição dela.
89
+ flash e zoom pedem peso; corte seco não pede nada. */
90
+ function transicao(tipo, indice) {
91
+ if (tipo === "corte") return;
92
+ if (tipo === "flash" || tipo === "zoom") return impacto();
93
+ whoosh(((indice || 0) * 0.37) % 1);
94
+ }
95
+
96
+ return {
97
+ whoosh: whoosh,
98
+ impacto: impacto,
99
+ click: click,
100
+ transicao: transicao,
101
+ volume: function (v) { saida.gain.value = v; },
102
+ };
103
+ }
104
+
105
+ if (typeof module !== "undefined" && module.exports) {
106
+ module.exports = { criarSfx: criarSfx };
107
+ }
@@ -67,6 +67,7 @@
67
67
  document.getElementById("btn-baixar").innerHTML = svgIcone("baixar");
68
68
  </script>
69
69
  <script src="/js/audio.js"></script>
70
+ <script src="/js/sfx.js"></script>
70
71
  <script src="/js/voz-neural.js"></script>
71
72
  <script src="/js/narracao.js"></script>
72
73
  <script src="/js/midia.js"></script>
@@ -17,6 +17,7 @@
17
17
  <script src="/js/render-prosa.js"></script>
18
18
  <script src="/js/render-grade.js"></script>
19
19
  <script src="/js/audio.js"></script>
20
+ <script src="/js/sfx.js"></script>
20
21
  <script src="/js/voz-neural.js"></script>
21
22
  <script src="/js/narracao.js"></script>
22
23
  <script src="/js/player.js"></script>
@@ -1,150 +0,0 @@
1
- {
2
- "id": "corte-estatico-corte-a5bab",
3
- "ferramenta": "corte",
4
- "titulo": "estatico-corte",
5
- "doc": {
6
- "tema": "brasa",
7
- "largura": 1080,
8
- "altura": 1920,
9
- "acabamento": "grao",
10
- "trilha": {
11
- "tipo": "gerada",
12
- "estilo": "pulso",
13
- "volume": 0.7
14
- },
15
- "cenas": [
16
- {
17
- "layout": "centro",
18
- "duracao": 3,
19
- "fundo": "aurora",
20
- "transicao": "flash",
21
- "elementos": [
22
- {
23
- "tipo": "texto",
24
- "papel": "titulo",
25
- "texto": "Sua conta subiu\nde novo.",
26
- "tamanho": 124,
27
- "estilo": "gradiente",
28
- "anim": "nenhuma"
29
- }
30
- ]
31
- },
32
- {
33
- "layout": "centro",
34
- "duracao": 3,
35
- "fundo": "vinheta",
36
- "transicao": "limpar",
37
- "elementos": [
38
- {
39
- "tipo": "texto",
40
- "papel": "titulo",
41
- "texto": "E não foi o seu chuveiro.",
42
- "tamanho": 78,
43
- "estilo": "marcador",
44
- "anim": "nenhuma"
45
- }
46
- ]
47
- },
48
- {
49
- "layout": "centro",
50
- "duracao": 4,
51
- "transicao": "zoom",
52
- "acabamento": "vinheta",
53
- "fundo": {
54
- "imagem": "/midia/torre.jpg",
55
- "escurecer": 0.5
56
- },
57
- "elementos": [
58
- {
59
- "tipo": "numeros",
60
- "contar": true,
61
- "anim": "nenhuma",
62
- "tamanho": 180,
63
- "itens": [
64
- "+38% | bandeira tarifária em 12 meses"
65
- ]
66
- }
67
- ]
68
- },
69
- {
70
- "layout": "livre",
71
- "duracao": 4,
72
- "transicao": "deslizar",
73
- "elementos": [
74
- {
75
- "tipo": "imagem",
76
- "src": "/midia/campo.jpg",
77
- "x": 0,
78
- "y": 0,
79
- "l": 1080,
80
- "a": 1920,
81
- "raio": 0,
82
- "movimento": "aproximar",
83
- "filtro": "contraste",
84
- "anim": "nenhuma"
85
- },
86
- {
87
- "tipo": "forma",
88
- "forma": "retangulo",
89
- "x": 0,
90
- "y": 1180,
91
- "l": 1080,
92
- "a": 740,
93
- "preenchimento": "rgba(10,5,6,.72)",
94
- "anim": "nenhuma"
95
- },
96
- {
97
- "tipo": "texto",
98
- "x": 90,
99
- "y": 1320,
100
- "l": 900,
101
- "a": 420,
102
- "texto": "O custo está\nna transmissão",
103
- "tamanho": 104,
104
- "peso": 750,
105
- "estilo": "sombra",
106
- "anim": "nenhuma"
107
- }
108
- ]
109
- },
110
- {
111
- "layout": "centro",
112
- "duracao": 5,
113
- "fundo": "raios",
114
- "transicao": "subir",
115
- "elementos": [
116
- {
117
- "tipo": "lista",
118
- "revelar": true,
119
- "tamanho": 52,
120
- "intervalo": 0.9,
121
- "itens": [
122
- "Linhas saturadas no Nordeste",
123
- "Usina gerando sem escoar",
124
- "A conta chega em quem consome"
125
- ],
126
- "anim": "nenhuma"
127
- }
128
- ]
129
- },
130
- {
131
- "layout": "centro",
132
- "duracao": 3,
133
- "fundo": "brilho",
134
- "transicao": "fade",
135
- "acabamento": "luz",
136
- "elementos": [
137
- {
138
- "tipo": "texto",
139
- "papel": "titulo",
140
- "texto": "Segue para\nentender a próxima.",
141
- "tamanho": 96,
142
- "estilo": "contorno-tom",
143
- "anim": "nenhuma"
144
- }
145
- ]
146
- }
147
- ]
148
- },
149
- "atualizado": "2026-08-16T15:08:28+00:00"
150
- }
@@ -1,65 +0,0 @@
1
- {
2
- "id": "corte-founders-ai-teste-do-player-2de1d",
3
- "ferramenta": "corte",
4
- "titulo": "Founders AI — teste do player",
5
- "doc": {
6
- "tema": "brasa",
7
- "largura": 1080,
8
- "altura": 1920,
9
- "acabamento": "grao",
10
- "trilha": {
11
- "tipo": "gerada",
12
- "estilo": "pulso",
13
- "volume": 0.7
14
- },
15
- "cenas": [
16
- {
17
- "layout": "centro",
18
- "duracao": 3,
19
- "fundo": "aurora",
20
- "transicao": "flash",
21
- "elementos": [
22
- {
23
- "tipo": "texto",
24
- "papel": "titulo",
25
- "texto": "Imersão\nFounders AI",
26
- "tamanho": 124,
27
- "estilo": "gradiente",
28
- "anim": "desfoque"
29
- }
30
- ]
31
- },
32
- {
33
- "layout": "centro",
34
- "duracao": 3,
35
- "fundo": "vinheta",
36
- "elementos": [
37
- {
38
- "tipo": "texto",
39
- "papel": "titulo",
40
- "texto": "Paris Group · Chapecó",
41
- "tamanho": 78,
42
- "estilo": "marcador",
43
- "anim": "palavra"
44
- }
45
- ]
46
- },
47
- {
48
- "layout": "centro",
49
- "duracao": 4,
50
- "fundo": "raios",
51
- "elementos": [
52
- {
53
- "tipo": "numeros",
54
- "contar": true,
55
- "tamanho": 180,
56
- "itens": [
57
- "20 | empresários por turma"
58
- ]
59
- }
60
- ]
61
- }
62
- ]
63
- },
64
- "atualizado": "2026-08-16T14:55:24+00:00"
65
- }
@@ -1 +0,0 @@
1
- {"id": "corte-legado-teste", "ferramenta": "corte", "titulo": "legado", "doc": {"tema": "meia-noite", "largura": 1080, "altura": 1920, "cenas": [{"duracao": "4s", "fundo": "aurora", "elementos": [{"tipo": "titulo", "texto": "Imersão Founders AI"}, {"tipo": "subtitulo", "conteudo": "Paris Group · Chapecó"}]}]}}
@@ -1 +0,0 @@
1
- {"id": "corte-legado2", "ferramenta": "corte", "titulo": "legado2", "doc": {"tema": "meia-noite", "largura": 1080, "altura": 1920, "cenas": [{"duracao": "4s", "fundo": "aurora", "elementos": [{"tipo": "titulo", "texto": "Imersão Founders AI", "anim": "nenhuma"}, {"tipo": "subtitulo", "conteudo": "Paris Group · Chapecó", "anim": "nenhuma"}]}]}}
@@ -1,24 +0,0 @@
1
- {
2
- "id": "corte-minimo-2a829",
3
- "ferramenta": "corte",
4
- "titulo": "minimo",
5
- "doc": {
6
- "tema": "claro",
7
- "largura": 1080,
8
- "altura": 1920,
9
- "cenas": [
10
- {
11
- "layout": "centro",
12
- "duracao": 5,
13
- "elementos": [
14
- {
15
- "tipo": "texto",
16
- "texto": "TESTE VISIVEL",
17
- "tamanho": 120
18
- }
19
- ]
20
- }
21
- ]
22
- },
23
- "atualizado": "2026-08-16T14:57:24+00:00"
24
- }
@@ -1,18 +0,0 @@
1
- {
2
- "id": "corte-ok-00a3b",
3
- "ferramenta": "corte",
4
- "titulo": "ok",
5
- "doc": {
6
- "cenas": [
7
- {
8
- "elementos": [
9
- {
10
- "tipo": "texto",
11
- "texto": "oi"
12
- }
13
- ]
14
- }
15
- ]
16
- },
17
- "atualizado": "2026-08-16T15:05:32+00:00"
18
- }
@@ -1,22 +0,0 @@
1
- {
2
- "id": "corte-ok-1270e",
3
- "ferramenta": "corte",
4
- "titulo": "ok",
5
- "doc": {
6
- "tema": "brasa",
7
- "cenas": [
8
- {
9
- "duracao": 3,
10
- "elementos": [
11
- {
12
- "tipo": "texto",
13
- "papel": "titulo",
14
- "texto": "Founders AI",
15
- "anim": "nenhuma"
16
- }
17
- ]
18
- }
19
- ]
20
- },
21
- "atualizado": "2026-08-16T17:50:21+00:00"
22
- }