// Camera: leva o monitor do plano aberto (z 0: o aparelho inteiro, em 3/4) ao plano fechado (z 1: a tela // ocupa o vídeo). Entre as chaves a câmera anda devagar e com precisão; por baixo, uma deriva que não para. // z acima de 1 aproxima de verdade (1.3 = tela 30% maior), pra mirar num pedaço da interface. // `chaves`: [{em, z, x?, y?}] em quadros absolutos; x/y deslocam o foco em px da tela (positivo = olhar pra direita/baixo). import React from 'react'; import {AbsoluteFill, useCurrentFrame} from 'remotion'; import {CENTRO_VIDEO, e3, lerp} from '../base'; export type ChaveCamera = {em: number; z: number; x?: number; y?: number}; export type CameraProps = {chaves?: ChaveCamera[]; children: React.ReactNode}; export const posCamera = (f: number, chaves: ChaveCamera[]) => { const ks = chaves.length ? [...chaves].sort((a, b) => a.em - b.em) : [{em: 0, z: 1}]; let z = ks[0].z, x = ks[0].x ?? 0, y = ks[0].y ?? 0; for (let i = 0; i < ks.length - 1; i++) { const a = ks[i], b = ks[i + 1]; if (f >= a.em) { const t = e3((f - a.em) / Math.max(1, b.em - a.em)); z = lerp(a.z, b.z, t); x = lerp(a.x ?? 0, b.x ?? 0, t); y = lerp(a.y ?? 0, b.y ?? 0, t); } } const zc = Math.min(1, z); const escala = (z <= 1 ? lerp(0.58, 1, z) : z) * (1 + 0.035 * Math.sin(f / 110) + 0.00018 * f); const rotY = lerp(-20, -9, zc) + 1.6 * Math.sin(f / 95); const rotX = lerp(6, 2.5, zc) + 0.8 * Math.cos(f / 120); const dx = Math.sin(f / 80) * 10 - x * escala, dy = Math.cos(f / 100) * 8 - y * escala + lerp(-40, 0, zc); return {escala, rotY, rotX, dx, dy}; }; export const Camera: React.FC = ({chaves = [], children}) => { const c = posCamera(useCurrentFrame(), chaves); return {children} ; };