primocode 10.12.0 → 10.14.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.
- package/README.md +74 -12
- package/bin/primocode.js +148 -8
- package/lib/act.js +48 -1
- package/lib/catalogo.js +12 -1
- package/lib/config.js +1 -0
- package/lib/estudio/assinaturas/gerativo.json +1 -1
- package/lib/estudio/camadas.js +4 -0
- package/lib/estudio/cota.js +150 -0
- package/lib/estudio/dados/projetos/clube-ad5.json +105 -0
- package/lib/estudio/dados/projetos/clube-ae-sem-memoria.json +107 -0
- package/lib/estudio/dados/projetos/clube-agent.json +120 -0
- package/lib/estudio/dados/projetos/clube-antes-e-agora.json +86 -0
- package/lib/estudio/dados/projetos/clube-apresentando-clube.json +110 -0
- package/lib/estudio/dados/projetos/clube-bluevisa.json +106 -0
- package/lib/estudio/dados/projetos/clube-caught-in-the-fire.json +127 -0
- package/lib/estudio/dados/projetos/clube-chat-cliente-satisfeito.json +98 -0
- package/lib/estudio/dados/projetos/clube-chatgpt-anuncios.json +120 -0
- package/lib/estudio/dados/projetos/clube-claude-dj.json +140 -0
- package/lib/estudio/dados/projetos/clube-claude-mcp.json +142 -0
- package/lib/estudio/dados/projetos/clube-cleanui.json +106 -0
- package/lib/estudio/dados/projetos/clube-clinica-take-unico.json +128 -0
- package/lib/estudio/dados/projetos/clube-clinica.json +104 -0
- package/lib/estudio/dados/projetos/clube-clube-opener.json +125 -0
- package/lib/estudio/dados/projetos/clube-clube.json +108 -0
- package/lib/estudio/dados/projetos/clube-codigo.json +101 -0
- package/lib/estudio/dados/projetos/clube-distilbook.json +104 -0
- package/lib/estudio/dados/projetos/clube-drive-upload.json +115 -0
- package/lib/estudio/dados/projetos/clube-dub.json +119 -0
- package/lib/estudio/dados/projetos/clube-enxovaly.json +105 -0
- package/lib/estudio/dados/projetos/clube-fecha7.json +118 -0
- package/lib/estudio/dados/projetos/clube-filatov.json +128 -0
- package/lib/estudio/dados/projetos/clube-frame.json +108 -0
- package/lib/estudio/dados/projetos/clube-glass.json +118 -0
- package/lib/estudio/dados/projetos/clube-letra-em-apps.json +84 -0
- package/lib/estudio/dados/projetos/clube-letra-globo-3d.json +111 -0
- package/lib/estudio/dados/projetos/clube-letra-nos-apps.json +146 -0
- package/lib/estudio/dados/projetos/clube-letra-seis-mundos.json +100 -0
- package/lib/estudio/dados/projetos/clube-lula-3.json +146 -0
- package/lib/estudio/dados/projetos/clube-morph.json +119 -0
- package/lib/estudio/dados/projetos/clube-motion-designer.json +115 -0
- package/lib/estudio/dados/projetos/clube-motion-pacote.json +112 -0
- package/lib/estudio/dados/projetos/clube-movimento.json +103 -0
- package/lib/estudio/dados/projetos/clube-not-like-us.json +117 -0
- package/lib/estudio/dados/projetos/clube-pinterest-inspiracao.json +86 -0
- package/lib/estudio/dados/projetos/clube-pixel-e-tinta.json +108 -0
- package/lib/estudio/dados/projetos/clube-ponte.json +118 -0
- package/lib/estudio/dados/projetos/clube-processo-edit-tonal.json +126 -0
- package/lib/estudio/dados/projetos/clube-processo-motion-100-ia.json +109 -0
- package/lib/estudio/dados/projetos/clube-promo.json +114 -0
- package/lib/estudio/dados/projetos/clube-proposito.json +115 -0
- package/lib/estudio/dados/projetos/clube-rankhog.json +128 -0
- package/lib/estudio/dados/projetos/clube-recursao.json +116 -0
- package/lib/estudio/dados/projetos/clube-revelar.json +118 -0
- package/lib/estudio/dados/projetos/clube-robo.json +125 -0
- package/lib/estudio/dados/projetos/clube-shelby-ep2.json +144 -0
- package/lib/estudio/dados/projetos/clube-shelby.json +97 -0
- package/lib/estudio/dados/projetos/clube-solar-eclipse.json +96 -0
- package/lib/estudio/dados/projetos/clube-soldier.json +128 -0
- package/lib/estudio/dados/projetos/clube-som-de-cena.json +108 -0
- package/lib/estudio/dados/projetos/clube-spotify-candidatura.json +112 -0
- package/lib/estudio/dados/projetos/clube-tda-app.json +118 -0
- package/lib/estudio/dados/projetos/clube-tda-ia.json +75 -0
- package/lib/estudio/dados/projetos/clube-telegram-chat.json +118 -0
- package/lib/estudio/dados/projetos/clube-telegram-ilha.json +106 -0
- package/lib/estudio/dados/projetos/clube-tennessee-nike.json +132 -0
- package/lib/estudio/dados/projetos/clube-tudo-se-move.json +112 -0
- package/lib/estudio/dados/projetos/clube-uiad.json +107 -0
- package/lib/estudio/dados/projetos/clube-viralgrow.json +108 -0
- package/lib/estudio/dados/projetos/clube-whose-side.json +140 -0
- package/lib/estudio/dados/projetos/clube-youtube-inscrever.json +108 -0
- package/lib/estudio/dados/projetos/elementos-do-site-em-movimento.json +49 -0
- package/lib/estudio/dados/projetos/explainer-narrado.json +51 -0
- package/lib/estudio/dados/projetos/lancamento-de-produto.json +51 -0
- package/lib/estudio/dados/projetos/motion-so-com-sons.json +50 -0
- package/lib/estudio/dados/projetos/titulo-em-after-effects.json +51 -0
- package/lib/estudio/dados/projetos/tour-de-saas.json +50 -0
- package/lib/estudio/dados/projetos-ae/antes-e-agora/ae/cenas.jsx +733 -0
- package/lib/estudio/dados/projetos-ae/antes-e-agora/assets/fazer_assets.py +88 -0
- package/lib/estudio/dados/projetos-ae/letra-em-apps/ae/cenas.jsx +402 -0
- package/lib/estudio/dados/projetos-ae/letra-em-apps/assets/preparar_assets.py +17 -0
- package/lib/estudio/dados/projetos-ae/letra-em-apps/assets/svg_para_ae.py +25 -0
- package/lib/estudio/dados/projetos-ae/letra-nos-apps/BRIEF-AGENTES.md +31 -0
- package/lib/estudio/dados/projetos-ae/letra-nos-apps/README.md +53 -0
- package/lib/estudio/dados/projetos-ae/letra-nos-apps/ROTEIRO-CENAS.md +69 -0
- package/lib/estudio/dados/projetos-ae/letra-nos-apps/ae/A-agenda.jsx +148 -0
- package/lib/estudio/dados/projetos-ae/letra-nos-apps/ae/B-docs.jsx +174 -0
- package/lib/estudio/dados/projetos-ae/letra-nos-apps/ae/C-alttab.jsx +113 -0
- package/lib/estudio/dados/projetos-ae/letra-nos-apps/ae/D-spotify.jsx +118 -0
- package/lib/estudio/dados/projetos-ae/letra-nos-apps/ae/E-notas.jsx +146 -0
- package/lib/estudio/dados/projetos-ae/letra-nos-apps/ae/F-jornal1.jsx +144 -0
- package/lib/estudio/dados/projetos-ae/letra-nos-apps/ae/G-google.jsx +153 -0
- package/lib/estudio/dados/projetos-ae/letra-nos-apps/ae/H-mapa.jsx +176 -0
- package/lib/estudio/dados/projetos-ae/letra-nos-apps/ae/I-imagens.jsx +132 -0
- package/lib/estudio/dados/projetos-ae/letra-nos-apps/ae/J-jornal2.jsx +191 -0
- package/lib/estudio/dados/projetos-ae/letra-nos-apps/ae/K-maps.jsx +184 -0
- package/lib/estudio/dados/projetos-ae/letra-nos-apps/ae/camera-movimentos.jsx +48 -0
- package/lib/estudio/dados/projetos-ae/letra-nos-apps/ae/camera.jsx +57 -0
- package/lib/estudio/dados/projetos-ae/letra-nos-apps/ae/card-spotify.jsx +98 -0
- package/lib/estudio/dados/projetos-ae/letra-nos-apps/ae/digitar.jsx +38 -0
- package/lib/estudio/dados/projetos-ae/letra-nos-apps/ae/jornal-comum.jsx +196 -0
- package/lib/estudio/dados/projetos-ae/letra-nos-apps/ae/letra.jsx +23 -0
- package/lib/estudio/dados/projetos-ae/letra-nos-apps/ae/letra_automatica.py +83 -0
- package/lib/estudio/dados/projetos-ae/letra-nos-apps/ae/montagem.jsx +74 -0
- package/lib/estudio/dados/projetos-ae/letra-nos-apps/ae/w-agenda/render_html.py +13 -0
- package/lib/estudio/dados/projetos-ae/letra-nos-apps/ae/w-agenda/util.jsx +162 -0
- package/lib/estudio/dados/projetos-ae/letra-nos-apps/ae/w-midia-comum.jsx +114 -0
- package/lib/estudio/dados/projetos-ae/letra-nos-apps/ae/wg-util.jsx +360 -0
- package/lib/estudio/dados/projetos-ae/letra-nos-apps/assets/F-jornal1/render_html.py +13 -0
- package/lib/estudio/dados/projetos-ae/letra-nos-apps/assets/render_w-midia.py +26 -0
- package/lib/estudio/dados/projetos-ae/letra-nos-apps/assets/w-midia-ferramentas/inclin.py +30 -0
- package/lib/estudio/dados/projetos-ae/letra-nos-apps/assets/w-midia-ferramentas/medir_d.py +36 -0
- package/lib/estudio/dados/projetos-ae/letra-nos-apps/assets/w-midia-ferramentas/medir_e.py +27 -0
- package/lib/estudio/dados/projetos-ae/letra-nos-apps/camera/ajustar_movimentos.py +61 -0
- package/lib/estudio/dados/projetos-ae/letra-nos-apps/camera/ancorar.py +74 -0
- package/lib/estudio/dados/projetos-ae/letra-nos-apps/camera/assar.py +47 -0
- package/lib/estudio/dados/projetos-ae/letra-nos-apps/camera/camera3d_jornal.py +172 -0
- package/lib/estudio/dados/projetos-ae/letra-nos-apps/camera/comparar.py +32 -0
- package/lib/estudio/dados/projetos-ae/letra-nos-apps/camera/dados_ae_jornal.py +46 -0
- package/lib/estudio/dados/projetos-ae/letra-nos-apps/camera/folha_contato.py +28 -0
- package/lib/estudio/dados/projetos-ae/letra-nos-apps/camera/homografia_jornal.py +74 -0
- package/lib/estudio/dados/projetos-ae/letra-nos-apps/camera/integrar.py +44 -0
- package/lib/estudio/dados/projetos-ae/letra-nos-apps/camera/medir_quadro_a_quadro.py +32 -0
- package/lib/estudio/dados/projetos-ae/letra-nos-apps/camera/mesa_2d.py +64 -0
- package/lib/estudio/dados/projetos-ae/letra-nos-apps/camera/plot_cenas.py +11 -0
- package/lib/estudio/dados/projetos-ae/letra-nos-apps/camera/retificar_quadros.py +38 -0
- package/lib/estudio/dados/projetos-ae/letra-nos-apps/camera/w-agenda/assar_ab.py +52 -0
- package/lib/estudio/dados/projetos-ae/letra-nos-apps/camera/w-agenda/medir_ab.py +59 -0
- package/lib/estudio/dados/projetos-ae/letra-nos-apps/camera/wg_ajustar_h.py +111 -0
- package/lib/estudio/dados/projetos-ae/letra-nos-apps/camera/wg_corrige_cam.py +17 -0
- package/lib/estudio/dados/projetos-ae/letra-nos-apps/camera/wg_ecc_cadeia.py +80 -0
- package/lib/estudio/dados/projetos-ae/letra-nos-apps/camera/wg_finalizar_cam.py +65 -0
- package/lib/estudio/dados/projetos-ae/letra-nos-apps/camera/wg_mosaico.py +61 -0
- package/lib/estudio/dados/projetos-ae/letra-nos-apps/guia-do-metodo/tutorial-lyric-edit-interfaces/01-gramatica-e-roteiro.md +55 -0
- package/lib/estudio/dados/projetos-ae/letra-nos-apps/guia-do-metodo/tutorial-lyric-edit-interfaces/02-camera.md +66 -0
- package/lib/estudio/dados/projetos-ae/letra-nos-apps/guia-do-metodo/tutorial-lyric-edit-interfaces/03-montagem-no-ae.md +50 -0
- package/lib/estudio/dados/projetos-ae/letra-nos-apps/guia-do-metodo/tutorial-lyric-edit-interfaces/04-render-e-conferencia.md +43 -0
- package/lib/estudio/dados/projetos-ae/letra-nos-apps/guia-do-metodo/tutorial-lyric-edit-interfaces/05-abertura-celular-mergulho.md +43 -0
- package/lib/estudio/dados/projetos-ae/letra-nos-apps/guia-do-metodo/tutorial-lyric-edit-interfaces.md +42 -0
- package/lib/estudio/dados/projetos-ae/letra-nos-apps/transicao/atraso_imagem.py +31 -0
- package/lib/estudio/dados/projetos-ae/letra-nos-apps/transicao/fundo.py +56 -0
- package/lib/estudio/dados/projetos-ae/letra-nos-apps/transicao/juntar.py +45 -0
- package/lib/estudio/dados/projetos-ae/letra-nos-apps/transicao/montar.py +177 -0
- package/lib/estudio/dados/projetos-ae/letra-nos-apps/transicao/rastreio.py +74 -0
- package/lib/estudio/dados/projetos-ae/letra-nos-apps/transicao/sincronia.py +18 -0
- package/lib/estudio/dados/projetos-ae/pinterest-inspiracao/ae/cenas.jsx +530 -0
- package/lib/estudio/dados/projetos-ae/pinterest-inspiracao/assets/fazer_assets.py +107 -0
- package/lib/estudio/dados/projetos-ae/processo-motion-100-ia/assets/pessoas/figurinha.py +46 -0
- package/lib/estudio/dados/projetos-ae/processo-motion-100-ia/comp-a/BRIEF-A.md +83 -0
- package/lib/estudio/dados/projetos-ae/processo-motion-100-ia/comp-a/audio.py +179 -0
- package/lib/estudio/dados/projetos-ae/processo-motion-100-ia/comp-a/confere.py +20 -0
- package/lib/estudio/dados/projetos-ae/processo-motion-100-ia/comp-a/dados/tempo-parte1.js +1 -0
- package/lib/estudio/dados/projetos-ae/processo-motion-100-ia/comp-a/dados/tempo-parte2.js +1 -0
- package/lib/estudio/dados/projetos-ae/processo-motion-100-ia/comp-a/gerar_emojis.py +11 -0
- package/lib/estudio/dados/projetos-ae/processo-motion-100-ia/comp-a/img/filmes/_indice.js +122 -0
- package/lib/estudio/dados/projetos-ae/processo-motion-100-ia/comp-a/js/base.js +380 -0
- package/lib/estudio/dados/projetos-ae/processo-motion-100-ia/comp-a/js/main.js +86 -0
- package/lib/estudio/dados/projetos-ae/processo-motion-100-ia/comp-a/js/p1a.js +169 -0
- package/lib/estudio/dados/projetos-ae/processo-motion-100-ia/comp-a/js/p1b.js +455 -0
- package/lib/estudio/dados/projetos-ae/processo-motion-100-ia/comp-a/js/p1c.js +389 -0
- package/lib/estudio/dados/projetos-ae/processo-motion-100-ia/comp-a/js/p2.js +379 -0
- package/lib/estudio/dados/projetos-ae/processo-motion-100-ia/comp-a/video.py +62 -0
- package/lib/estudio/dados/projetos-ae/processo-motion-100-ia/take-unico/README.md +65 -0
- package/lib/estudio/dados/projetos-ae/processo-motion-100-ia/take-unico/oraculo_take.py +137 -0
- package/lib/estudio/dados/projetos-ae/processo-motion-100-ia/take-unico/render_take.py +388 -0
- package/lib/estudio/dados/projetos-ae/processo-motion-100-ia/take-unico/take.js +235 -0
- package/lib/estudio/diretor.js +2 -1
- package/lib/estudio/editor.js +285 -0
- package/lib/estudio/efeitos-fabrica/terminal-digitando.jsx +2 -1
- package/lib/estudio/effectcraft.js +152 -0
- package/lib/estudio/exportar.js +181 -0
- package/lib/estudio/gerativo.js +44 -15
- package/lib/estudio/index.js +126 -5
- package/lib/estudio/kit/gerativo.jsx +15 -0
- package/lib/estudio/kit-ae/base.jsx +1146 -0
- package/lib/estudio/kit-ae/cenas.jsx +395 -0
- package/lib/estudio/kit-ae/primitivas.jsx +911 -0
- package/lib/estudio/kokoro.js +3 -1
- package/lib/estudio/maquina-diretor.js +393 -0
- package/lib/estudio/maquina-elementos.js +134 -0
- package/lib/estudio/maquina-layout.js +198 -0
- package/lib/estudio/maquina-som.js +478 -0
- package/lib/estudio/maquina-trilha.js +160 -0
- package/lib/estudio/maquina-voz.js +429 -0
- package/lib/estudio/maquina.js +516 -0
- package/lib/estudio/projetos.js +60 -0
- package/lib/estudio/remotion.js +6 -4
- package/lib/estudio/revisor.js +61 -0
- package/lib/estudio/voicestudio.js +81 -0
- package/lib/headless.js +71 -0
- package/lib/hooks.js +72 -0
- package/lib/local/cerebro.json +398 -12
- package/lib/local/entrada.js +46 -2
- package/lib/marca-kit.js +309 -0
- package/lib/mcp.js +286 -6
- package/lib/perigo.js +31 -3
- package/lib/planos.js +47 -19
- package/lib/preparar.js +111 -0
- package/lib/retomar.js +55 -0
- package/lib/sandbox.js +197 -0
- package/lib/skills.js +3 -1
- package/lib/tools.js +13 -4
- package/lib/ui.js +1 -1
- package/lib/video/auto.js +18 -3
- package/package.json +4 -2
- package/skills/after-effects/SKILL.md +52 -0
- package/skills/maquina-de-motion/SKILL.md +84 -0
- package/skills/motion-de-primeira/SKILL.md +33 -51
package/lib/estudio/index.js
CHANGED
|
@@ -48,6 +48,7 @@ const video = require('./video.js');
|
|
|
48
48
|
const batida = require('./batida.js');
|
|
49
49
|
const revisor = require('./revisor.js');
|
|
50
50
|
const marcaLib = require('./marca.js');
|
|
51
|
+
const marcaKit = require('../marca-kit.js');
|
|
51
52
|
const conferencia = require('./conferencia.js');
|
|
52
53
|
const margem = require('./margem.js');
|
|
53
54
|
const assinatura = require('./assinatura.js');
|
|
@@ -65,6 +66,7 @@ const gerativo = require('./gerativo.js');
|
|
|
65
66
|
const fluido = require('./fluido.js');
|
|
66
67
|
const vox = require('./vox.js');
|
|
67
68
|
const kokoro = require('./kokoro.js');
|
|
69
|
+
const voicestudio = require('./voicestudio.js');
|
|
68
70
|
const lancamento = require('./lancamento.js');
|
|
69
71
|
const glifos = require('./glifos.js');
|
|
70
72
|
const personagem = require('./personagem.js');
|
|
@@ -361,7 +363,7 @@ async function roteiroDoServidor(p, args) {
|
|
|
361
363
|
estilo: args.estilo || (escolherEstilo({ pedido }) === 'impacto' ? 'impacto' : undefined),
|
|
362
364
|
}, cfg.token);
|
|
363
365
|
if (!r || !r.ok) return { ok: false, error: (r && r.erro) || 'o roteirista não respondeu.' };
|
|
364
|
-
return { ok: true, roteiro: { ...r.roteiro, marca: (args.roteiro && args.roteiro.marca) || p.marca || undefined } };
|
|
366
|
+
return { ok: true, roteiro: { ...r.roteiro, marca: marcaKit.preencher((args.roteiro && args.roteiro.marca) || p.marca || undefined, { pastas: [p.pasta, process.cwd()] }) } };
|
|
365
367
|
}
|
|
366
368
|
|
|
367
369
|
async function ferramentaPlano(args) {
|
|
@@ -505,6 +507,9 @@ async function ferramentaMidia(args) {
|
|
|
505
507
|
const p = args.id ? projeto.ler(args.id) : null;
|
|
506
508
|
if (args.id && !p) return semProjeto(args.id);
|
|
507
509
|
|
|
510
|
+
if (acao === 'projetos') return require('./projetos.js').procurar({ termo: args.termo, categoria: args.categoria, limite: args.limite });
|
|
511
|
+
if (acao === 'projeto') return require('./projetos.js').ver(args.nome || args.id_item || args.termo);
|
|
512
|
+
|
|
508
513
|
if (acao === 'fontes') {
|
|
509
514
|
if (args.conferir) return assets.conferirFonte(args.conferir);
|
|
510
515
|
return { ok: true, fontes: assets.FONTES, biblioteca: biblioteca.cardapio(),
|
|
@@ -662,6 +667,86 @@ async function baixarEscolhido(lista, args, p) {
|
|
|
662
667
|
comoUsar: r.ok ? `no plano: "src": "${r.relativo}"` : undefined };
|
|
663
668
|
}
|
|
664
669
|
|
|
670
|
+
// ── estudio_ae ───────────────────────────────────────────────────────────
|
|
671
|
+
|
|
672
|
+
/** O motor After Effects: roda o JSX do agente na pasta do projeto e devolve o mp4 e os quadros. */
|
|
673
|
+
async function ferramentaAE(args) {
|
|
674
|
+
const p = args.id ? projeto.ler(args.id) : null;
|
|
675
|
+
if (!args.id || !p) return semProjeto(args.id);
|
|
676
|
+
if (!args.script || !args.comp) return { ok: false, error: 'estudio_ae pede script (o JSX) e comp (o nome da composição).' };
|
|
677
|
+
return require('./cota.js').comCota(() => renderAE(args, p));
|
|
678
|
+
}
|
|
679
|
+
|
|
680
|
+
async function renderAE(args, p) {
|
|
681
|
+
const kitM = marcaKit.preencher(null, { pastas: [p.pasta, process.cwd()] });
|
|
682
|
+
const fontesKit = kitM && kitM.kit ? [kitM.fontes && kitM.fontes.titulo, kitM.fontes && kitM.fontes.texto].filter(Boolean) : [];
|
|
683
|
+
const r = await require('./effectcraft.js').renderizar({
|
|
684
|
+
pasta: p.pasta, script: String(args.script), comp: String(args.comp),
|
|
685
|
+
fontes: [...new Set([...(Array.isArray(args.fontes) ? args.fontes : []), ...fontesKit])], audio: args.audio || undefined,
|
|
686
|
+
conferir: Array.isArray(args.conferir) ? args.conferir : [],
|
|
687
|
+
});
|
|
688
|
+
if (!r.ok) return r;
|
|
689
|
+
const daMarca = kitM && kitM.kit ? { marca: { nome: kitM.nome, cores: kitM.cores, fontes: kitM.fontes, logo: kitM.logo } } : {};
|
|
690
|
+
return { ...r, ...daMarca, nota: 'Olhe os quadros (arquivos em ae/) antes de dar por pronto; ajuste o JSX e rode de novo se algo estiver torto.' };
|
|
691
|
+
}
|
|
692
|
+
|
|
693
|
+
// ── estudio_motion ───────────────────────────────────────────────────────
|
|
694
|
+
|
|
695
|
+
/** O pacote pra postar (exportar.js) + a galeria; nunca derruba o vídeo. `entrega:false` desliga. */
|
|
696
|
+
function entregar(args, p, r) {
|
|
697
|
+
const x = r._exportar || {}; delete r._exportar;
|
|
698
|
+
if (args.entrega === false) return;
|
|
699
|
+
try {
|
|
700
|
+
const E = require('./exportar.js');
|
|
701
|
+
const e = E.exportar({ video: r.video, pasta: p.pasta, assunto: args.assunto, formatos: args.formatos, cenas: x.cenas, palavras: x.palavras, trilha: r.trilha && { ...r.trilha, arquivo: x.trilhaArquivo }, sfx: x.sfx });
|
|
702
|
+
if (e.ok) {
|
|
703
|
+
r.entrega = { pasta: e.dir, arquivos: e.arquivos.map((f) => path.basename(f)), creditos: e.creditos, ...(e.avisos ? { avisos: e.avisos } : {}) };
|
|
704
|
+
E.registrar({ id: p.id, assunto: args.assunto, caminho: r.video, formato: r.formato, duracao: r.duracao, assinatura: r.assinatura, entrega: e.dir });
|
|
705
|
+
} else r.entrega = { erro: e.error };
|
|
706
|
+
} catch (err) { r.entrega = { erro: err.message }; }
|
|
707
|
+
}
|
|
708
|
+
|
|
709
|
+
/** A máquina de motion: assunto + cenas em JSON viram o mp4 (maquina.js), com sons, trilha e voz opcionais. */
|
|
710
|
+
async function ferramentaMotion(args) {
|
|
711
|
+
const p = args.id ? projeto.ler(args.id) : null;
|
|
712
|
+
if (!args.id || !p) return semProjeto(args.id);
|
|
713
|
+
let receita = null;
|
|
714
|
+
if (args.receita) {
|
|
715
|
+
const r = require('./projetos.js').ver(args.receita);
|
|
716
|
+
if (!r.ok) return r;
|
|
717
|
+
receita = r.projeto;
|
|
718
|
+
}
|
|
719
|
+
return require('./cota.js').comCota(() => renderMotion(args, p, receita));
|
|
720
|
+
}
|
|
721
|
+
|
|
722
|
+
async function renderMotion(args, p, receita) {
|
|
723
|
+
const narrar = async (texto, mp3, voz) => rodarPython('narrar.py', ['falar', '--texto', texto, '--saida', mp3, '--voz', String(voz || 'francisca')], { timeout: 5 * 60000 });
|
|
724
|
+
// Kit de marca ativo: cores, fontes e logo entram onde o JSON não disse; o logo vai no CTA (última cena).
|
|
725
|
+
const kitM = marcaKit.preencher(args.marca, { pastas: [p.pasta, process.cwd()] });
|
|
726
|
+
if (kitM && kitM.kit) {
|
|
727
|
+
args = { ...args, marca: kitM };
|
|
728
|
+
if (kitM.logo && Array.isArray(args.cenas) && args.cenas.length) {
|
|
729
|
+
args.cenas = args.cenas.map((c, i) => (i === args.cenas.length - 1 && c && !c.logo ? { ...c, logo: kitM.logo } : c));
|
|
730
|
+
}
|
|
731
|
+
}
|
|
732
|
+
const r = await require('./maquina.js').motion(args, { pasta: p.pasta, receita, deps: { narrar } });
|
|
733
|
+
if (r.ok) projeto.anotar(p.id, 'motion', `${r.duracao}s, ${r.cenas.length} cenas, ${r.lufs} LUFS`);
|
|
734
|
+
if (r.ok) entregar(args, p, r);
|
|
735
|
+
return r.ok ? { ...r, nota: 'Abra os quadros (png em ae/) para conferir. Se algo ficou torto, mude o JSON e rode de novo.' } : r;
|
|
736
|
+
}
|
|
737
|
+
|
|
738
|
+
// ── estudio_editar ───────────────────────────────────────────────────────
|
|
739
|
+
|
|
740
|
+
/** O editor por comando: reabre o plano da máquina de motion, aplica as mudanças e guarda a versão (editor.js). */
|
|
741
|
+
async function ferramentaEditar(args) {
|
|
742
|
+
const id = args.id_video || args.id;
|
|
743
|
+
const p = id ? projeto.ler(id) : null;
|
|
744
|
+
if (!p) return semProjeto(id);
|
|
745
|
+
const r = await require('./editor.js').editar(args, { pasta: p.pasta });
|
|
746
|
+
if (r.ok && r.versao && !args.listar) projeto.anotar(p.id, 'editar', `v${r.versao}: ${(r.feitas || [r.nota || '']).join('; ').slice(0, 120)}`);
|
|
747
|
+
return r.ok && r.video ? { ...r, nota: r.nota || 'Mostre o vídeo. Se não era isso, mude de novo ou use voltar_para.' } : r;
|
|
748
|
+
}
|
|
749
|
+
|
|
665
750
|
// ── estudio_narrar ───────────────────────────────────────────────────────
|
|
666
751
|
|
|
667
752
|
async function ferramentaNarrar(args) {
|
|
@@ -887,7 +972,7 @@ async function ferramentaVideo(args, ctx = {}) {
|
|
|
887
972
|
ok: true, proposta: camadas.propor(palavras, m.segundos), duracao: m.segundos,
|
|
888
973
|
comoUsar: 'é uma SUGESTÃO pela transcrição. Decida você: mude as formas, junte ou separe batidas, '
|
|
889
974
|
+ 'escreva a cena de motion de cada ideia (componentes/x.jsx, recebe {el, t, fps}; el.dados traz largura/altura do espaço livre, '
|
|
890
|
-
+ 'palavras com t, destaque, cores e fontes) ou use um efeito de fábrica pelo nome (estudio_midia acao:"efeitos"), '
|
|
975
|
+
+ 'palavras com t, destaque, cores e fontes; a LEGENDA da fala já está no quadro, então a cena NÃO escreve a fala: desenha a ideia) ou use um efeito de fábrica pelo nome (estudio_midia acao:"efeitos"), '
|
|
891
976
|
+ 'e chame de novo com batidas:[{de, ate, rosto, cena?, destaque?, canto?, dados?}].',
|
|
892
977
|
};
|
|
893
978
|
}
|
|
@@ -1177,6 +1262,35 @@ async function narrarComGemini(lista, mp3, { voz, direcao } = {}) {
|
|
|
1177
1262
|
}
|
|
1178
1263
|
}
|
|
1179
1264
|
|
|
1265
|
+
/* A VOZ DO VOICESTUDIO (15/10): o app local fala o roteiro inteiro, e o resto
|
|
1266
|
+
é o caminho do Gemini — volume de Reels, a transcrição para achar as partes.
|
|
1267
|
+
Fechado ou falhando, devolve ok:false e a cadeia segue para o Gemini. */
|
|
1268
|
+
async function narrarComVoiceStudio(lista, mp3, { voz } = {}) {
|
|
1269
|
+
if (process.env.PRIMOCODE_SEM_VOICESTUDIO) return { ok: false, indisponivel: true, error: 'voicestudio desligado' };
|
|
1270
|
+
try {
|
|
1271
|
+
const texto = lista.map((x) => x.texto).join('\n\n');
|
|
1272
|
+
// A voz do Gemini ("Kore", "Charon") não existe lá: só um perfil do próprio app.
|
|
1273
|
+
const perfil = /^vs:/i.test(String(voz || '')) ? String(voz).slice(3) : undefined;
|
|
1274
|
+
const r = await voicestudio.falar(texto, { voz: perfil });
|
|
1275
|
+
if (!r.ok) return r;
|
|
1276
|
+
const bruto = mp3.replace(/\.mp3$/, '-vs.mp3');
|
|
1277
|
+
fs.writeFileSync(bruto, r.audio);
|
|
1278
|
+
const c = await video.rodar(video.ffmpeg(), ['-y', '-i', bruto, '-af', 'loudnorm=I=-14:TP=-1.5:LRA=9', '-c:a', 'libmp3lame', '-q:a', '3', mp3], { timeout: 120000 });
|
|
1279
|
+
try { fs.unlinkSync(bruto); } catch { /* fica */ }
|
|
1280
|
+
if (!c.ok) return { ok: false, error: 'voicestudio: não consegui converter a voz' };
|
|
1281
|
+
const med = await video.medir(mp3);
|
|
1282
|
+
const chars = lista.reduce((n, x) => n + x.texto.length, 0);
|
|
1283
|
+
if (med.segundos < chars / 22) return { ok: false, error: `voicestudio: a voz veio cortada (${med.segundos.toFixed(1)} s para ${chars} caracteres)` };
|
|
1284
|
+
const cfg = require('../config').loadConfig();
|
|
1285
|
+
const tr = await require('../api').requestTranscricao(cfg.server, { token: cfg.token, audio: fs.readFileSync(mp3).toString('base64'), nome: 'voz.mp3', idioma: 'pt' });
|
|
1286
|
+
const palavras = (tr && tr.palavras) || [];
|
|
1287
|
+
if (!palavras.length) return { ok: false, error: 'voicestudio: sem a transcrição da voz para achar as partes' };
|
|
1288
|
+
return { ok: true, voz: `voicestudio ${perfil || 'default'}`, segundos: med.segundos, partes: alinharPartes(lista, palavras, med.segundos) };
|
|
1289
|
+
} catch (e) {
|
|
1290
|
+
return { ok: false, error: 'voicestudio: ' + e.message };
|
|
1291
|
+
}
|
|
1292
|
+
}
|
|
1293
|
+
|
|
1180
1294
|
/* Onde estão os rostos em cada foto (studio/rostos.py, pelo uv). Guardado no
|
|
1181
1295
|
projeto: a mesma foto não é analisada duas vezes. */
|
|
1182
1296
|
async function acharRostos(p, srcs) {
|
|
@@ -1270,7 +1384,9 @@ async function narrarComCache(lista, mp3, { voz, direcao } = {}) {
|
|
|
1270
1384
|
if (fs.existsSync(cm) && fs.existsSync(cj)) { fs.copyFileSync(cm, mp3); return { ok: true, ...JSON.parse(fs.readFileSync(cj, 'utf8')) }; }
|
|
1271
1385
|
// A voz local pedida (voz: 'kokoro'): direto nela, sem gastar a cota do Gemini.
|
|
1272
1386
|
if (kokoro.querKokoro(voz)) return kokoro.narrar(lista, mp3, { voz, uv: acharUv() });
|
|
1273
|
-
|
|
1387
|
+
// O VoiceStudio local primeiro (15/10); fechado ou falhando, o Gemini.
|
|
1388
|
+
let v = await narrarComVoiceStudio(lista, mp3, { voz });
|
|
1389
|
+
if (!v.ok) v = await narrarComGemini(lista, mp3, { voz, direcao });
|
|
1274
1390
|
if (v.ok) { try { fs.mkdirSync(dir, { recursive: true }); fs.copyFileSync(mp3, cm); fs.writeFileSync(cj, JSON.stringify({ voz: v.voz, segundos: v.segundos, partes: v.partes })); } catch { /* sem cache */ } }
|
|
1275
1391
|
return v;
|
|
1276
1392
|
}
|
|
@@ -1289,6 +1405,7 @@ async function produzirNecessidade(p, roteiro, pedido, provedores) {
|
|
|
1289
1405
|
direção dele), o Kokoro local e o Edge. A falha de uma passa para a próxima. */
|
|
1290
1406
|
function provedoresDeVoz(lista, mp3, arq, voz, vozEdge, { soEdge = false, gemini, escolha } = {}) {
|
|
1291
1407
|
const todos = {
|
|
1408
|
+
voicestudio: () => narrarComVoiceStudio(lista, mp3, { voz }),
|
|
1292
1409
|
gemini: () => gemini(),
|
|
1293
1410
|
kokoro: () => kokoro.narrar(lista, mp3, { voz, uv: acharUv() }),
|
|
1294
1411
|
edge: () => {
|
|
@@ -1307,7 +1424,7 @@ function provedoresDeVoz(lista, mp3, arq, voz, vozEdge, { soEdge = false, gemini
|
|
|
1307
1424
|
/* A VOZ DE RESERVA, quando o Gemini falha: o Kokoro (local, sem cota) e
|
|
1308
1425
|
depois o Edge. A falha de uma passa para a próxima, nunca derruba. */
|
|
1309
1426
|
function narrarReserva(lista, mp3, arq, voz, vozEdge, { soEdge = false, semKokoro = false } = {}) {
|
|
1310
|
-
const passos = kokoro.ordem(voz, process.env, { soEdge }).filter((n) => n !== 'gemini' && !(semKokoro && n === 'kokoro'));
|
|
1427
|
+
const passos = kokoro.ordem(voz, process.env, { soEdge }).filter((n) => n !== 'gemini' && n !== 'voicestudio' && !(semKokoro && n === 'kokoro'));
|
|
1311
1428
|
return kokoro.corrente(passos, {
|
|
1312
1429
|
kokoro: () => kokoro.narrar(lista, mp3, { voz, uv: acharUv() }),
|
|
1313
1430
|
edge: () => rodarPython('narrar.py', ['roteiro', '--arquivo', arq, '--saida', mp3, '--voz', kokoro.vozNoEdge(voz, vozEdge)], { timeout: 10 * 60000 }),
|
|
@@ -1457,6 +1574,10 @@ async function prepararRoteiro(p, args) {
|
|
|
1457
1574
|
const novas = referencias.imagens().filter((f) => !jaTem.has(f));
|
|
1458
1575
|
for (const f of novas) { try { importarReferencia(p, f); } catch (e) { projeto.anotar(p.id, 'referencia', `não importou ${path.basename(f)}: ${e.message}`); } }
|
|
1459
1576
|
if (novas.length) p = projeto.ler(p.id) || p;
|
|
1577
|
+
/* O KIT DE MARCA ativo (lib/marca-kit.js) vale mais que a marca lida do
|
|
1578
|
+
site: a pessoa criou uma vez e quer em todo vídeo. O roteiro ainda ganha. */
|
|
1579
|
+
const kitM = marcaKit.preencher({}, { pastas: [p.pasta, process.cwd()] });
|
|
1580
|
+
if (kitM.kit) { p = { ...p, marca: kitM }; }
|
|
1460
1581
|
if (roteiro.marca) {
|
|
1461
1582
|
/* A do roteiro por cima da do site, CAMPO A CAMPO: antes o "cores" em
|
|
1462
1583
|
lista do agente apagava o {fundo, destaque} lido do site (13/10). */
|
|
@@ -2567,7 +2688,7 @@ async function ferramentaSite(args) {
|
|
|
2567
2688
|
|
|
2568
2689
|
module.exports = { proporcaoDoPedido,
|
|
2569
2690
|
vazamentoNoComeco, variarIcones, objetosDoRoteiro,
|
|
2570
|
-
ferramentaProjeto, ferramentaPlano, ferramentaMidia, ferramentaNarrar,
|
|
2691
|
+
ferramentaProjeto, ferramentaPlano, ferramentaMidia, ferramentaAE, ferramentaMotion, ferramentaEditar, ferramentaNarrar,
|
|
2571
2692
|
ferramentaVideo, ferramentaRender, ferramentaSite,
|
|
2572
2693
|
projeto, plano, remotion, assets, video, identidade, slides, python, rodarPython, alinharPartes, prepararRoteiro, roteiroValido, juntarVozes,
|
|
2573
2694
|
};
|
|
@@ -295,6 +295,21 @@ function geometria(a, b, L, P) {
|
|
|
295
295
|
for (let i = 0; i < N; i++) { const q = -2.3 + (i / (N - 1)) * Math.PI * 2 * 1.1; const e = 1 + (i / N) * 0.07; pts.push([ccx + Math.cos(q) * rx * e, ccy + Math.sin(q) * ry * e]); }
|
|
296
296
|
return { pts, larg: Math.max(4 * base, cx.s * 0.03), alfa: 1, frente: true, cx: ccx, cy: ccy };
|
|
297
297
|
}
|
|
298
|
+
if (f === 'visto') {
|
|
299
|
+
/* O ✓ de caneta (15/10, as referências): depois do círculo, ao lado da
|
|
300
|
+
palavra, em dois traços; se não cabe à direita, encosta na margem. */
|
|
301
|
+
const pw = alvoPalavra();
|
|
302
|
+
const s = cx.s, cy0 = cx.y + cx.h * 0.5;
|
|
303
|
+
const A = [pw.x + pw.w + s * 0.16, cy0], B = [pw.x + pw.w + s * 0.27, cy0 + s * 0.2], C = [pw.x + pw.w + s * 0.52, cy0 - s * 0.3];
|
|
304
|
+
const dx = Math.min(0, P.largura - 24 * base - C[0]);
|
|
305
|
+
const q = 0.3;
|
|
306
|
+
for (let i = 0; i < N; i++) {
|
|
307
|
+
const k = i / (N - 1);
|
|
308
|
+
const [p0, p1, u] = k < q ? [A, B, k / q] : [B, C, (k - q) / (1 - q)];
|
|
309
|
+
pts.push([lerp(p0[0], p1[0], u) + dx, lerp(p0[1], p1[1], u)]);
|
|
310
|
+
}
|
|
311
|
+
return { pts, larg: Math.max(5 * base, s * 0.045), alfa: 1, frente: true, tampa: 'round', cx: B[0] + dx, cy: B[1] };
|
|
312
|
+
}
|
|
298
313
|
if (f === 'barra') {
|
|
299
314
|
// O vão da barra é o respiro do vídeo (margem.js): colada, ela riscava a primeira letra.
|
|
300
315
|
// A deriva da vida abre as letras até 3% da linha para fora: a barra recua junto.
|