primocode 9.8.0-beta.10 → 9.8.0-beta.12

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.
@@ -212,6 +212,7 @@ function Elemento({ el, t, dados }) {
212
212
  transform: [base.transform, move].filter(Boolean).join(' '),
213
213
  filter: filtroDe(a) || undefined,
214
214
  mixBlendMode: el.mistura || undefined,
215
+ transformOrigin: el.origem || undefined,
215
216
  };
216
217
 
217
218
  if (el.vidro) {
@@ -294,7 +295,7 @@ function Elemento({ el, t, dados }) {
294
295
  // O SVG foi baixado para a pasta do projeto (estudio/assets.js): render
295
296
  // que busca ícone na internet falha no meio, depois de tudo pronto.
296
297
  return (
297
- <div style={{ ...estilo, width: medida(el.tamanho, '96px'), height: medida(el.tamanho, '96px'), color: el.cor || '#fff' }}
298
+ <div style={{ ...estilo, width: medida(el.tamanho, '96px'), height: medida(el.tamanho, '96px'), fontSize: medida(el.tamanho, '96px'), lineHeight: 0, color: el.cor || '#fff' }}
298
299
  dangerouslySetInnerHTML={{ __html: dados.icones[el.nome] || '' }} />
299
300
  );
300
301
 
@@ -302,6 +303,55 @@ function Elemento({ el, t, dados }) {
302
303
  const fala = (el.fala || []).find((f) => t >= f.de && t <= f.ate);
303
304
  if (!fala) return null;
304
305
  const e = el.estilo || {};
306
+ /* LEGENDA DE VIDEOMAKER: com o tempo de cada palavra, elas entram uma a
307
+ uma, no instante em que são ditas, com um salto curto. A que está
308
+ sendo dita ganha a cor de destaque; a palavra forte (a ideia da
309
+ frase) ganha a cor dela e fica maior. Sem "palavras", a frase entra
310
+ inteira, como antes. */
311
+ if (Array.isArray(fala.palavras) && fala.palavras.length) {
312
+ const destaque = e.destaque || '#FFD400';
313
+ const forte = e.corForte || '#00E0A4';
314
+ const soUma = e.modo === 'palavra';
315
+ const visiveis = soUma
316
+ ? fala.palavras.filter((p, i, l) => t >= p.de && (i === l.length - 1 || t < l[i + 1].de)).slice(-1)
317
+ : fala.palavras.filter((p) => t >= p.de - 0.02);
318
+ return (
319
+ <div style={{
320
+ ...estilo,
321
+ display: 'flex', flexWrap: 'wrap', justifyContent: 'center', alignItems: 'baseline',
322
+ gap: '0 0.34em', maxWidth: medida(e.largura, '86%'),
323
+ fontFamily: e.fonte ? '"' + e.fonte + '", system-ui, sans-serif' : 'system-ui, sans-serif',
324
+ fontSize: medida(e.tamanho, '64px'),
325
+ fontWeight: e.peso || 900,
326
+ textTransform: e.caixa || undefined,
327
+ lineHeight: 1.1,
328
+ }}>
329
+ {visiveis.map((p, i) => {
330
+ const idade = t - p.de;
331
+ const entra = Math.min(1, Math.max(0, idade / 0.14));
332
+ const salto = entra < 1 ? 0.7 + 0.42 * CURVAS.saida(entra) : 1.12 - 0.12 * Math.min(1, (idade - 0.14) / 0.12);
333
+ const falando = t >= p.de && t <= p.ate + 0.05;
334
+ const cor = p.forte ? forte : (falando ? destaque : (e.cor || '#fff'));
335
+ return (
336
+ <span key={i} style={{
337
+ display: 'inline-block',
338
+ // A palavra forte é MAIOR na fonte, não na escala: escala não
339
+ // abre espaço, e ela cresceria por cima da vizinha.
340
+ fontSize: p.forte ? '1.22em' : undefined,
341
+ transform: 'scale(' + salto + ') translateY(' + (1 - entra) * 18 + 'px)',
342
+ opacity: entra,
343
+ color: cor,
344
+ textShadow: e.sombra || '0 6px 22px rgba(0,0,0,.6), 0 2px 0 rgba(0,0,0,.35)',
345
+ WebkitTextStroke: e.contorno || '2px rgba(0,0,0,.55)',
346
+ paintOrder: 'stroke fill',
347
+ background: falando && e.fundoAtivo ? e.fundoAtivo : undefined,
348
+ borderRadius: '0.18em', padding: falando && e.fundoAtivo ? '0 0.12em' : undefined,
349
+ }}>{p.texto}{p.emoji ? ' ' + p.emoji : ''}</span>
350
+ );
351
+ })}
352
+ </div>
353
+ );
354
+ }
305
355
  return (
306
356
  <div style={{
307
357
  ...estilo,
@@ -366,7 +416,7 @@ export function Cena({ cena, dados }) {
366
416
  </AbsoluteFill>
367
417
  );
368
418
  }
369
- ";`;
419
+ `;
370
420
 
371
421
  const RAIZ_JSX = String.raw`import React from 'react';
372
422
  import { AbsoluteFill, Audio, Sequence, staticFile, useCurrentFrame, useVideoConfig, interpolate } from 'remotion';
@@ -428,6 +478,7 @@ export const Video = () => {
428
478
  <Audio
429
479
  src={staticFile(plano.audio.trilha.src || plano.audio.trilha)}
430
480
  volume={plano.audio.trilha.volume ?? 0.18}
481
+ loop={plano.audio.trilha.loop !== false}
431
482
  />
432
483
  )}
433
484
  {(plano.audio && plano.audio.efeitos ? plano.audio.efeitos : []).map((e, i) => (
@@ -438,7 +489,7 @@ export const Video = () => {
438
489
  </AbsoluteFill>
439
490
  );
440
491
  };
441
- ";`;
492
+ `;
442
493
 
443
494
  function rootJsx(plano) {
444
495
  const f = plano.formato || {};
@@ -513,12 +564,25 @@ para este projeto, não para o PrimoCode.
513
564
  * @param {object} op.plano
514
565
  * @param {object} op.icones { "lucide:zap": "<svg…>" } já baixados
515
566
  */
567
+ const TSCONFIG = JSON.stringify({
568
+ compilerOptions: {
569
+ target: 'ES2018', module: 'commonjs', jsx: 'react-jsx', strict: false, noEmit: true,
570
+ lib: ['es2015', 'dom'], esModuleInterop: true, skipLibCheck: true, forceConsistentCasingInFileNames: true,
571
+ },
572
+ exclude: ['remotion.config.ts'],
573
+ }, null, 2) + '\n';
574
+
516
575
  function montar({ pasta, titulo, plano, icones = {} }) {
517
576
  const raiz = path.join(pasta, 'remotion');
518
577
  const src = path.join(raiz, 'src');
519
578
 
520
579
  escrever(path.join(raiz, 'package.json'), pkgJson(titulo || 'video'));
521
580
  escrever(path.join(raiz, 'remotion.config.ts'), REMOTION_CONFIG);
581
+ /* O remotion.config.ts é TypeScript, e o Remotion 4 recusa renderizar sem
582
+ um tsconfig.json na raiz ("Could not find a tsconfig.json"). Medido em
583
+ 25/09: o vídeo que saiu bom só saiu porque o modelo criou este arquivo à
584
+ mão depois do erro — um modelo grátis travaria ali. */
585
+ escrever(path.join(raiz, 'tsconfig.json'), TSCONFIG);
522
586
  escrever(path.join(raiz, 'README.md'), readme(titulo || 'Vídeo', plano));
523
587
  escrever(path.join(src, 'index.js'), INDEX_JS);
524
588
  escrever(path.join(src, 'Root.jsx'), rootJsx(plano));