// Cena: a janela de tempo de um plano. Dentro dela, useCurrentFrame() começa em 0 e useDuracaoCena() devolve a duração. // Entra com movimento (subir, zoom, lados) e sai cruzando 10 quadros com a próxima. `entrada="nenhuma"` é corte seco. import React, {createContext, useContext} from 'react'; import {AbsoluteFill, Sequence, useCurrentFrame} from 'remotion'; export type Entrada = 'subir' | 'zoom' | 'direita' | 'esquerda' | 'nenhuma'; export const SOBREPOE = 10; const CenaCtx = createContext({duracao: 60}); export const useDuracaoCena = () => useContext(CenaCtx).duracao; const seg = (f: number, a: number, b: number) => Math.min(1, Math.max(0, (f - a) / Math.max(1, b - a))); const e5 = (t: number) => 1 - Math.pow(1 - t, 5); export type CenaProps = {de: number; ate: number; entrada?: Entrada; ultima?: boolean; children: React.ReactNode}; const Janela: React.FC<{duracao: number; entrada: Entrada; ultima: boolean; children: React.ReactNode}> = ({duracao, entrada, ultima, children}) => { const f = useCurrentFrame(); const en = entrada === 'nenhuma' ? 0 : 1 - e5(seg(f, 0, 12)); const xo = ultima ? 0 : e5(seg(f, duracao, duracao + SOBREPOE)); let tf = ''; if (entrada === 'subir') tf += `translateY(${en * 300}px) `; if (entrada === 'zoom') tf += `scale(${1 + en * 0.9}) `; if (entrada === 'direita') tf += `translateX(${en * 900}px) `; if (entrada === 'esquerda') tf += `translateX(${-en * 900}px) `; tf += `translateY(${-xo * 220}px)`; return {children}; }; export const Cena: React.FC = ({de, ate, entrada = 'subir', ultima = false, children}) => { const duracao = ate - de; return {children} ; };