primocode 10.3.0 → 10.4.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.
- package/README.md +29 -2
- package/bin/primocode.js +111 -41
- package/lib/act.js +19 -5
- package/lib/catalogo.js +10 -4
- package/lib/entrada.js +261 -67
- package/lib/estudio/acervo.js +21 -1
- package/lib/estudio/estilo.js +12 -5
- package/lib/estudio/gerativo.js +18 -0
- package/lib/estudio/index.js +35 -3
- package/lib/estudio/kit/gerativo.jsx +62 -14
- package/lib/estudio/kit/index.jsx +2 -1
- package/lib/estudio/kit/personagem.jsx +582 -0
- package/lib/estudio/kit.js +3 -1
- package/lib/estudio/lancamento.js +5 -2
- package/lib/estudio/margem.js +235 -0
- package/lib/estudio/personagem.js +232 -0
- package/lib/estudio/print-site.js +190 -1
- package/lib/tela.js +223 -0
- package/lib/ui.js +70 -88
- package/package.json +2 -2
package/lib/estudio/index.js
CHANGED
|
@@ -47,6 +47,7 @@ const assets = require('./assets.js');
|
|
|
47
47
|
const video = require('./video.js');
|
|
48
48
|
const batida = require('./batida.js');
|
|
49
49
|
const revisor = require('./revisor.js');
|
|
50
|
+
const margem = require('./margem.js');
|
|
50
51
|
const assinatura = require('./assinatura.js');
|
|
51
52
|
const identidade = require('./identidade.js');
|
|
52
53
|
const slides = require('./slides.js');
|
|
@@ -64,6 +65,7 @@ const vox = require('./vox.js');
|
|
|
64
65
|
const kokoro = require('./kokoro.js');
|
|
65
66
|
const lancamento = require('./lancamento.js');
|
|
66
67
|
const glifos = require('./glifos.js');
|
|
68
|
+
const personagem = require('./personagem.js');
|
|
67
69
|
const { escolherEstilo, LEVES } = require('./estilo.js');
|
|
68
70
|
const sonsLeves = require('./sons-leves.js');
|
|
69
71
|
const ende = require('./ende.js');
|
|
@@ -277,7 +279,12 @@ function roteiroValido(r) {
|
|
|
277
279
|
if (!Array.isArray(partes) || partes.length < 2) return null;
|
|
278
280
|
const CINEMA = ['frase', 'montagem', 'numeros', 'escada', 'dia', 'depoimento', 'climax', 'final'];
|
|
279
281
|
const NOVOS = ['logo', 'cores', 'produto']; // vox.js e lancamento.js
|
|
280
|
-
|
|
282
|
+
/* A FALA do personagem (personagem.js) não tem tipo: é {falante, texto}. Sem
|
|
283
|
+
isto, o roteiro de diálogo caía no roteirista do servidor, que reescrevia
|
|
284
|
+
tudo com um apresentador só — e as duas vozes sumiam (10/10). */
|
|
285
|
+
const conversa = (x && !Array.isArray(x) && String(x.estilo || '').toLowerCase() === 'personagem') || partes.some((pt) => pt && typeof pt.falante === 'string' && pt.falante.trim());
|
|
286
|
+
const fala = (pt) => conversa && !pt.tipo && typeof (pt.texto || pt.fala) === 'string' && String(pt.texto || pt.fala).trim();
|
|
287
|
+
if (!partes.every((pt) => pt && (composicao.TIPOS.includes(pt.tipo) || CINEMA.includes(pt.tipo) || NOVOS.includes(pt.tipo) || fala(pt)))) return null;
|
|
281
288
|
// Duas vozes: roteiro.vozes e parte.falante, limpos (falantes.js). Sem eles, nada muda.
|
|
282
289
|
const obj = falantes.normalizar(Array.isArray(x) ? { partes } : x);
|
|
283
290
|
return partes.some((pt) => CINEMA.includes(pt.tipo)) && !obj.estilo ? { ...obj, estilo: 'cinema' } : obj;
|
|
@@ -470,6 +477,17 @@ async function ferramentaMidia(args) {
|
|
|
470
477
|
return r;
|
|
471
478
|
}
|
|
472
479
|
|
|
480
|
+
/* O ELEMENTO do site, tirado pelo código (print-site.js): a lista das peças
|
|
481
|
+
(logo, botão, cartão, título…) e uma peça sozinha, com o fundo transparente. */
|
|
482
|
+
if (acao === 'elementos') return printSite.elementosDoSite(args.url || args.site || args.termo, { celular: !!args.celular });
|
|
483
|
+
if (acao === 'elemento') {
|
|
484
|
+
if (!p) return { ok: false, error: 'para tirar o elemento é preciso dizer em qual projeto (id).' };
|
|
485
|
+
const r = await printSite.capturarElemento(args.url || args.site, { pasta: p.pasta, seletor: args.seletor, texto: args.texto || args.termo,
|
|
486
|
+
celular: !!args.celular, transparente: args.transparente !== false, margem: args.margem });
|
|
487
|
+
if (r.ok) projeto.anotar(p.id, 'midia', `elemento de ${r.url} (${args.seletor || args.texto || args.termo}): ${r.src}`);
|
|
488
|
+
return r;
|
|
489
|
+
}
|
|
490
|
+
|
|
473
491
|
// O catálogo de efeitos que a IA escreveu (efeitos.js): guardar, listar, reusar.
|
|
474
492
|
if (acao === 'efeitos') return { ok: true, efeitos: efeitos.cardapio() };
|
|
475
493
|
if (acao === 'guardar-efeito' || acao === 'usar-efeito') {
|
|
@@ -1113,7 +1131,7 @@ async function prepararRoteiro(p, args) {
|
|
|
1113
1131
|
/* "O vídeo deve ter um 3D do fone" (30/09): pedido de 3D vira o gerativo
|
|
1114
1132
|
com o produto modelado girando numa batida (kit/tres.jsx) — a menos que
|
|
1115
1133
|
o agente tenha escolhido outro estilo pelo nome. */
|
|
1116
|
-
if (/\b3\s?d\b|tridimensional/i.test(pedidoTxt) && (!args.estilo || estilo === 'gerativo' || estilo === 'lancamento')) {
|
|
1134
|
+
if (/\b3\s?d\b|tridimensional/i.test(pedidoTxt) && estilo !== 'personagem' && (!args.estilo || estilo === 'gerativo' || estilo === 'lancamento')) {
|
|
1117
1135
|
// O 3D mora numa batida do gerativo; o lançamento antigo, só pelo nome.
|
|
1118
1136
|
if (!args.estilo && estilo !== 'lancamento') estilo = 'gerativo';
|
|
1119
1137
|
if (!roteiro.modelo3d) roteiro.modelo3d = variacao3d.modeloDoPedido(pedidoTxt);
|
|
@@ -1485,6 +1503,9 @@ async function prepararRoteiro(p, args) {
|
|
|
1485
1503
|
// O fluido é o vídeo de produto: voz limpa e segura, e rápida ("mais rápido", 06/10).
|
|
1486
1504
|
: estilo === 'fluido' ? 'Leia em português do Brasil como narrador de vídeo de produto premium: seguro, próximo e RÁPIDO, '
|
|
1487
1505
|
+ 'frases limpas e contínuas, quase sem pausa entre elas. Nunca arraste, nunca leia devagar; sem tom de anúncio.'
|
|
1506
|
+
// O personagem CONVERSA: voz de gente falando com gente, não de locutor.
|
|
1507
|
+
: estilo === 'personagem' ? 'Fale em português do Brasil como alguém conversando de verdade num podcast: natural, próximo, '
|
|
1508
|
+
+ 'com as pausas e a entonação de quem está pensando junto. Sem voz de locutor, sem leitura.'
|
|
1488
1509
|
: estilo === 'impacto' ? 'Leia em português do Brasil como locutor de comercial agressivo e vendedor: energia alta, ritmo rápido, '
|
|
1489
1510
|
+ 'voz encorpada, ênfase forte nas palavras de impacto, pausas curtas e secas entre as frases, sorrindo na voz.'
|
|
1490
1511
|
// "A narração tá lenta, deixa mais viva" (29/09): todo estilo fala com energia de reels.
|
|
@@ -1508,7 +1529,7 @@ async function prepararRoteiro(p, args) {
|
|
|
1508
1529
|
áudio acelera 1,12× (1,3× ficou corrido demais, 29/09; atempo não muda o tom) e cada tempo de palavra
|
|
1509
1530
|
acompanha; `roteiro.ritmoVoz` ajusta (1 desliga). */
|
|
1510
1531
|
// O fluido corre mais ("mais rápido", 06/10): 1,22× por padrão.
|
|
1511
|
-
const ritmo = Math.max(1, Math.min(1.5, Number(roteiro.ritmoVoz || args.ritmoVoz) || (estilo === 'fluido' ? 1.22 : 1.12)));
|
|
1532
|
+
const ritmo = Math.max(1, Math.min(1.5, Number(roteiro.ritmoVoz || args.ritmoVoz) || (estilo === 'fluido' ? 1.22 : estilo === 'personagem' ? 1.06 : 1.12)));
|
|
1512
1533
|
if (ritmo > 1.01) {
|
|
1513
1534
|
const rap = mp3.replace(/\.mp3$/, '-r.mp3');
|
|
1514
1535
|
const c = await video.rodar(video.ffmpeg(), ['-y', '-i', mp3, '-filter:a', `atempo=${ritmo.toFixed(3)}`, rap], { timeout: 120000 });
|
|
@@ -1697,6 +1718,11 @@ async function prepararRoteiro(p, args) {
|
|
|
1697
1718
|
if (r.ok) conferirAssinatura(p, r, roteiro.assinatura || 'fluido');
|
|
1698
1719
|
return r;
|
|
1699
1720
|
}
|
|
1721
|
+
if (estilo === 'personagem' && modo === 'video') {
|
|
1722
|
+
const r = personagem.montarPersonagem({ roteiro, largura, altura, tempos, narracao, sons, trilha });
|
|
1723
|
+
if (r.ok) projeto.anotar(p.id, 'plano', `estilo personagem: ${r.resumo.elenco.join(' e ')} no set ${r.resumo.cenario}, ${r.resumo.planos} planos, ${r.resumo.segundos}s`);
|
|
1724
|
+
return r;
|
|
1725
|
+
}
|
|
1700
1726
|
if (estilo === 'motion' && modo === 'video') {
|
|
1701
1727
|
const r = motion.montarMotion({ roteiro, largura, altura, tempos, narracao, sons, trilha, imagens });
|
|
1702
1728
|
if (r.ok) projeto.anotar(p.id, 'plano', `estilo motion: ${r.resumo.segundos}s contínuos, ${r.resumo.partes} partes, ${r.resumo.fps} fps`);
|
|
@@ -1788,6 +1814,12 @@ async function ferramentaRender(args, ctx = {}) {
|
|
|
1788
1814
|
if (revisao.consertos.length) projeto.anotar(args.id, 'revisao', revisao.consertos.join('; '));
|
|
1789
1815
|
if (revisao.avisos.length) projeto.anotar(args.id, 'revisao', 'avisos: ' + revisao.avisos.join('; '));
|
|
1790
1816
|
|
|
1817
|
+
/* A ÁREA SEGURA E O RESPIRO (margem.js): nada a menos de 6%/7% da borda,
|
|
1818
|
+
nada colado em nada. É conta, não pedido: o elemento que o modelo pôs
|
|
1819
|
+
encostado entra, o texto largo encolhe, o colado se afasta. */
|
|
1820
|
+
const guarda = margem.guardarPlano(pl);
|
|
1821
|
+
if (guarda.consertos.length) projeto.anotar(args.id, 'margem', guarda.consertos.slice(0, 12).join('; '));
|
|
1822
|
+
|
|
1791
1823
|
// Os ícones vêm ANTES do render: um render que busca ícone na internet
|
|
1792
1824
|
// falha no meio, depois de vinte minutos.
|
|
1793
1825
|
const { mapa, faltaram } = await assets.iconesDoPlano(pl, p.pasta);
|
|
@@ -147,6 +147,38 @@ function useMedidas(P) {
|
|
|
147
147
|
return medidas;
|
|
148
148
|
}
|
|
149
149
|
|
|
150
|
+
/* ── a área segura: o bloco MEDIDO cabe em b.seguro ──────────────────────
|
|
151
|
+
b.seguro vem do planner (margem.limitesNaCamera): é onde, no mundo, o
|
|
152
|
+
bloco pode ficar para não encostar na borda da tela com a câmera daquela
|
|
153
|
+
batida. Largo demais: encolhe tudo junto (fonte e posição) em volta do
|
|
154
|
+
centro; fora: anda para dentro. A barra do acento mora à esquerda do bloco
|
|
155
|
+
e o ponto final à direita: contam como parte dele. Partitura antiga (sem
|
|
156
|
+
b.seguro): como antes. */
|
|
157
|
+
function encaixar(b, caixas) {
|
|
158
|
+
const seg = b.seguro;
|
|
159
|
+
const cs = Object.values(caixas);
|
|
160
|
+
if (!seg || !cs.length) return;
|
|
161
|
+
const sMax = Math.max(...cs.map((c) => c.s));
|
|
162
|
+
const temBarra = (b.acento || []).some((a) => a.forma === 'barra');
|
|
163
|
+
const x0 = Math.min(...cs.map((c) => c.x)), y0 = Math.min(...cs.map((c) => c.y));
|
|
164
|
+
const x1 = Math.max(...cs.map((c) => c.x + c.w)), y1 = Math.max(...cs.map((c) => c.y + c.h));
|
|
165
|
+
const deriva = b.vida === 'deriva' ? (x1 - x0) * 0.03 : 0;
|
|
166
|
+
const esq = (temBarra ? Math.max(18, (b.vao || 0) * 0.7, (y1 - y0) * 0.08) + 8 : 0) + sMax * 0.04 + deriva, dir = sMax * 0.22 + deriva;
|
|
167
|
+
const k = Math.min(1, (seg.x1 - seg.x0) / (x1 - x0 + esq + dir), (seg.y1 - seg.y0) / (y1 - y0));
|
|
168
|
+
const ox = (x0 + x1) / 2, oy = (y0 + y1) / 2;
|
|
169
|
+
const nx0 = ox + (x0 - ox) * k - esq * k, nx1 = ox + (x1 - ox) * k + dir * k;
|
|
170
|
+
const ny0 = oy + (y0 - oy) * k, ny1 = oy + (y1 - oy) * k;
|
|
171
|
+
const dx = nx0 < seg.x0 ? seg.x0 - nx0 : nx1 > seg.x1 ? seg.x1 - nx1 : 0;
|
|
172
|
+
const dy = ny0 < seg.y0 ? seg.y0 - ny0 : ny1 > seg.y1 ? seg.y1 - ny1 : 0;
|
|
173
|
+
if (k > 0.999 && !dx && !dy) return;
|
|
174
|
+
const X = (x) => ox + (x - ox) * k + dx, Y = (y) => oy + (y - oy) * k + dy;
|
|
175
|
+
for (const c of cs) {
|
|
176
|
+
c.x = X(c.x); c.y = Y(c.y); c.w *= k; c.h *= k; c.s *= k;
|
|
177
|
+
c.palavras = c.palavras.map((p) => ({ x: X(p.x), w: p.w * k }));
|
|
178
|
+
c.letras = c.letras.map((q) => ({ x: X(q.x), w: q.w * k }));
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
|
|
150
182
|
// ── o leiaute: da medida às caixas no mundo ─────────────────────────────
|
|
151
183
|
function leiaute(P, med) {
|
|
152
184
|
const W = P.largura, H = P.altura;
|
|
@@ -210,6 +242,7 @@ function leiaute(P, med) {
|
|
|
210
242
|
const s = aspas.tamanho;
|
|
211
243
|
caixas[aspas.id] = { x: cp.x - s * 0.04, y: cp.y - s * 0.62, w: s * 0.5, h: s, s, palavras: [{ x: cp.x, w: s * 0.5 }], letras: [{ x: cp.x, w: s * 0.5 }] };
|
|
212
244
|
}
|
|
245
|
+
encaixar(b, caixas);
|
|
213
246
|
// O bloco inteiro (para a barra e a moldura).
|
|
214
247
|
const cs = Object.values(caixas);
|
|
215
248
|
const bx = { x: Math.min(...cs.map((c) => c.x)), y: Math.min(...cs.map((c) => c.y)), x1: Math.max(...cs.map((c) => c.x + c.w)), y1: Math.max(...cs.map((c) => c.y + c.h)) };
|
|
@@ -260,8 +293,16 @@ function geometria(a, b, L, P) {
|
|
|
260
293
|
return { pts, larg: Math.max(4 * base, cx.s * 0.03), alfa: 1, frente: true, cx: ccx, cy: ccy };
|
|
261
294
|
}
|
|
262
295
|
if (f === 'barra') {
|
|
263
|
-
|
|
264
|
-
|
|
296
|
+
// O vão da barra é o respiro do vídeo (margem.js): colada, ela riscava a primeira letra.
|
|
297
|
+
// A deriva da vida abre as letras até 3% da linha para fora: a barra recua junto.
|
|
298
|
+
const x0 = lay.bloco.x - Math.max(18 * base, (b.vao || 0) * 0.7, (lay.bloco.y1 - lay.bloco.y) * 0.08) - (b.vida === 'deriva' ? (lay.bloco.x1 - lay.bloco.x) * 0.03 : 0);
|
|
299
|
+
/* O texto mora na batida, que chega ~80 px mais perto da lente enquanto se
|
|
300
|
+
lê; o traço, não. Sem esta conta, o texto crescia por cima da barra (a
|
|
301
|
+
primeira letra riscada, 10/10): a barra vai para onde o texto É VISTO. */
|
|
302
|
+
const D = Math.round(Math.max(P.largura, P.altura) * 0.85), kz = D / (D - 80);
|
|
303
|
+
const X = (q) => P.largura / 2 + (q - P.largura / 2) * kz, Y = (q) => P.altura / 2 + (q - P.altura / 2) * kz;
|
|
304
|
+
const x = X(x0);
|
|
305
|
+
for (let i = 0; i < N; i++) { const k = i / (N - 1); pts.push([x, Y(lerp(lay.bloco.y + 4, lay.bloco.y1 - 4, k))]); }
|
|
265
306
|
return { pts, larg: Math.max(8 * base, 10 * base), alfa: 1, frente: true, cx: x, cy: (lay.bloco.y + lay.bloco.y1) / 2 };
|
|
266
307
|
}
|
|
267
308
|
if (f === 'moldura') {
|
|
@@ -959,9 +1000,11 @@ export function Gerativo({ el, t, fps }) {
|
|
|
959
1000
|
if (x.heroi.modo === 'campo') return null; // desenhado atrás, antes do produto
|
|
960
1001
|
const R = Math.min(W, H) * (W >= H ? 0.2 : 0.17);
|
|
961
1002
|
let slot = null;
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
1003
|
+
// A área segura (margem.js), com o vão do bloco; partitura antiga: a margem do mundo.
|
|
1004
|
+
const S = x.seguro || { x0: M, y0: M * 1.4, x1: W - M, y1: H - M * 1.4 }, V = x.vao || 0;
|
|
1005
|
+
if (S.x1 - bl.x1 - V >= R * 2.3) slot = { cx: bl.x1 + V + (S.x1 - bl.x1 - V) / 2, cy: (bl.y + bl.y1) / 2, R };
|
|
1006
|
+
else if (bl.y - V - S.y0 >= R * 2.2) slot = { cx: W / 2, cy: S.y0 + (bl.y - V - S.y0) / 2, R };
|
|
1007
|
+
else if (S.y1 - bl.y1 - V >= R * 2.2) slot = { cx: W / 2, cy: bl.y1 + V + (S.y1 - bl.y1 - V) / 2, R };
|
|
965
1008
|
// Sem vazio, não entra (09/10): o anel no meio do texto era enfeite que ninguém pediu.
|
|
966
1009
|
else return null;
|
|
967
1010
|
return <Heroi b={x} t={t} P={P} slot={slot} />;
|
|
@@ -972,16 +1015,21 @@ export function Gerativo({ el, t, fps }) {
|
|
|
972
1015
|
(ic.lados, gerativo.js: direita, esquerda, acima, abaixo ou canto);
|
|
973
1016
|
sem espaço lá, tenta o próximo; sem nenhum, não entra — nunca
|
|
974
1017
|
por cima do texto. Partitura antiga (sem lados): direita ou acima. */
|
|
975
|
-
const ic = x.icone3d,
|
|
976
|
-
|
|
977
|
-
|
|
1018
|
+
const ic = x.icone3d, bl = lay.bloco;
|
|
1019
|
+
/* A área segura do ícone (margem.js): ele vive mais perto da lente que o
|
|
1020
|
+
texto, então o limite dele é mais apertado; e fica a um vão (4% do lado
|
|
1021
|
+
curto) do bloco. Partitura antiga: a margem do mundo, como antes. */
|
|
1022
|
+
const M = P.margem, S = x.seguroIcone || { x0: M, y0: M, x1: W - M, y1: H - M }, V = x.vao || 8;
|
|
1023
|
+
const tam = Math.min(ic.tamanho, (S.x1 - S.x0) * 0.4, (S.y1 - S.y0) * 0.6);
|
|
1024
|
+
const xTopo = Math.min(S.x1 - tam, Math.max(S.x0, x.bloco.alinha === 'centro' ? (bl.x + bl.x1) / 2 - tam / 2 : bl.x - tam * 0.08));
|
|
1025
|
+
const fora = (qx, qy) => qx + tam <= bl.x - V || qx >= bl.x1 + V || qy + tam <= bl.y - V || qy >= bl.y1 + V;
|
|
978
1026
|
const LUGAR = {
|
|
979
|
-
'direita': () => (
|
|
980
|
-
'esquerda': () => (bl.x -
|
|
981
|
-
'acima': () => (bl.y -
|
|
982
|
-
'abaixo': () => (
|
|
1027
|
+
'direita': () => (S.x1 - bl.x1 - V >= tam ? [Math.min(S.x1 - tam, bl.x1 + V + (S.x1 - bl.x1 - V - tam) / 2), Math.min(S.y1 - tam, Math.max(S.y0, (bl.y + bl.y1) / 2 - tam / 2))] : null),
|
|
1028
|
+
'esquerda': () => (bl.x - V - S.x0 >= tam ? [Math.max(S.x0, S.x0 + (bl.x - V - S.x0 - tam) / 2), Math.min(S.y1 - tam, Math.max(S.y0, (bl.y + bl.y1) / 2 - tam / 2))] : null),
|
|
1029
|
+
'acima': () => (bl.y - V - S.y0 >= tam ? [xTopo, Math.max(S.y0, bl.y - V - tam)] : null),
|
|
1030
|
+
'abaixo': () => (S.y1 - bl.y1 - V >= tam ? [xTopo, Math.min(S.y1 - tam, bl.y1 + V)] : null),
|
|
983
1031
|
// O canto livre mais longe do texto: o ícone pequeno, de assinatura.
|
|
984
|
-
'canto': () => [[
|
|
1032
|
+
'canto': () => [[S.x1 - tam, S.y0], [S.x1 - tam, S.y1 - tam], [S.x0, S.y0], [S.x0, S.y1 - tam]].find(([qx, qy]) => fora(qx, qy)) || null,
|
|
985
1033
|
};
|
|
986
1034
|
const ordem = ic.lados || [ic.lado, 'acima'];
|
|
987
1035
|
const achou = ordem.map((l) => LUGAR[l] && LUGAR[l]()).find(Boolean);
|
|
@@ -995,7 +1043,7 @@ export function Gerativo({ el, t, fps }) {
|
|
|
995
1043
|
transform: 'translateZ(120px) scale(' + (0.6 + 0.4 * k).toFixed(4) + ') rotate(' + ((1 - k) * -8).toFixed(2) + 'deg)', transformOrigin: '50% 60%' }}
|
|
996
1044
|
dangerouslySetInnerHTML={{ __html: ic.svg }} />;
|
|
997
1045
|
}
|
|
998
|
-
return <div style={{ position: 'absolute', inset: 0, transform: 'translateZ(150px)' }}><Icone3D el={{ ...ic, x: Math.round(px), y: Math.round(py) }} t={t} /></div>;
|
|
1046
|
+
return <div style={{ position: 'absolute', inset: 0, transform: 'translateZ(150px)' }}><Icone3D el={{ ...ic, tamanho: tam, x: Math.round(px), y: Math.round(py) }} t={t} /></div>;
|
|
999
1047
|
})()}
|
|
1000
1048
|
{x.linhas.map((l, li) => {
|
|
1001
1049
|
const cx = lay.caixas[l.id];
|
|
@@ -9,6 +9,7 @@ import { Papel } from './base';
|
|
|
9
9
|
import { TRES } from './tres';
|
|
10
10
|
import { GERATIVO } from './gerativo';
|
|
11
11
|
import { FLUIDO } from './fluido';
|
|
12
|
+
import { PERSONAGEM } from './personagem';
|
|
12
13
|
|
|
13
|
-
export const KIT = { ...VOX, ...MARCA, ...TRES, ...GERATIVO, ...FLUIDO, papel: Papel };
|
|
14
|
+
export const KIT = { ...VOX, ...MARCA, ...TRES, ...GERATIVO, ...FLUIDO, ...PERSONAGEM, papel: Papel };
|
|
14
15
|
export { Filtros, Acabamento, Hud, CURVAS_KIT, bolhaCaminho } from './base';
|