// FormaMorph: a única forma do vídeo, sempre em cobalto, de 560 px, que nasce de um ponto e vira outra forma a cada chave // (círculo, quadrado, pílula, anel, meia-lua), mudando largura, altura, raio, contorno e giro ao mesmo tempo. É o herói. import React from 'react'; import {useCurrentFrame} from 'remotion'; import {COR, e5, lerp, ov, seg} from '../base'; export type TipoForma = 'circulo' | 'quadrado' | 'pilula' | 'anel' | 'meia'; export type FormaMorphProps = { /** cada item vale a partir do quadro `de` (na cena): a forma se transforma em 18 quadros */ formas: {de: number; tipo: TipoForma; rot?: number}[]; /** centro vertical, px */ y: number; /** tamanho de referência, px (herói: 520–600) */ tamanho?: number; cor?: string; inicio?: number; fim?: number; }; // [largura, altura, raio, contorno, preenchido (1) ou só contorno (0)] em múltiplos de T const GEO = (t: TipoForma, T: number): number[] => { switch (t) { case 'circulo': return [T, T, T / 2, 0, 1]; case 'quadrado': return [T * 0.88, T * 0.88, T * 0.1, 0, 1]; case 'pilula': return [T * 1.5, T * 0.52, T * 0.26, 0, 1]; case 'anel': return [T, T, T / 2, T * 0.17, 0]; case 'meia': return [T * 1.1, T * 0.55, T * 0.55, 0, 1]; } }; export const FormaMorph: React.FC = ({formas, y, tamanho = 560, cor = COR.cobalto, inicio = 0, fim = 1e9}) => { const f = useCurrentFrame(); if (f < inicio - 1 || f > fim + 12) return null; const nasce = ov(seg(f, inicio, inicio + 20)), sai = e5(seg(f, fim, fim + 10)); let atual = 0; formas.forEach((s, i) => { if (f >= s.de) atual = i; }); const ant = Math.max(0, atual - 1), p = atual === 0 ? 1 : ov(seg(f, formas[atual].de, formas[atual].de + 18)); const a = GEO(formas[ant].tipo, tamanho), b = GEO(formas[atual].tipo, tamanho); const g = a.map((v, i) => lerp(v, b[i], p)); const rot = lerp(formas[ant].rot ?? 0, formas[atual].rot ?? 0, p) + Math.sin(f / 40) * 2; const escala = Math.max(0, nasce) * (1 - sai * 0.3); return
0.5 ? cor : 'transparent', border: g[3] > 1 ? `${g[3]}px solid ${cor}` : 'none', boxSizing: 'border-box', transform: `rotate(${rot}deg) scale(${escala})`, opacity: 1 - sai}} />; };