// Base do kit retro-70: cores, fontes, curvas e medidas. Todo número visual sai daqui. // Os elementos importam só este arquivo, 'react' e 'remotion'. Nada de fora da pasta do kit. import {continueRender, delayRender} from 'remotion'; import fonte0 from './fontes/shrikhand.woff2'; import fonte1 from './fontes/fredoka.woff2'; // ---------- tela ---------- export const LARGURA = 1080, ALTURA = 1920, FPS = 30; // área segura (Reels/TikTok): o que se lê fica entre estas linhas export const SEGURA = {topo: 168, base: 1330, lado: 96}; export const LARGURA_UTIL = LARGURA - SEGURA.lado * 2; // 888 px // ---------- cor ---------- export const COR = { creme: '#F6E3B8', laranja: '#E8601C', mostarda: '#F2A900', tijolo: '#B8341B', marrom: '#4A2511' }; // ---------- fonte ---------- // Nome de família com o prefixo do kit ("R7 ..."), pra não colidir com outro kit no mesmo estúdio. export const FONTE = { titulo: '"R7 Shrikhand", Georgia, serif', apoio: '"R7 Fredoka", Arial Rounded MT Bold, Arial, sans-serif', }; type G = {__kit_retro_70?: boolean}; if (typeof document !== 'undefined' && !(globalThis as G).__kit_retro_70) { (globalThis as G).__kit_retro_70 = true; const h = delayRender('retro-70: fontes'); Promise.all([ new FontFace('R7 Shrikhand', `url(${fonte0}) format('woff2')`, {weight: '400', style: 'normal'}).load(), new FontFace('R7 Fredoka', `url(${fonte1}) format('woff2')`, {weight: '500 700', style: 'normal'}).load(), ]).then((fs) => {fs.forEach((ff) => document.fonts.add(ff)); continueRender(h);}).catch(() => continueRender(h)); } // ---------- tempo e curva ---------- export const c01 = (t: number) => Math.max(0, Math.min(1, t)); /** progresso 0..1 de f entre a e b */ export const seg = (f: number, a: number, b: number) => c01((f - a) / (b - a)); /** saída rápida e pouso longo, parecida com cubic-bezier(.2,.8,.2,1) */ export const e5 = (t: number) => 1 - Math.pow(1 - c01(t), 5); /** easeOutBack: passa do destino em ~10% e volta (toda entrada tem overshoot) */ export const eb = (t: number, s = 1.70158) => {const x = c01(t) - 1; return 1 + (s + 1) * x * x * x + s * x * x;}; export const lerp = (a: number, b: number, t: number) => a + (b - a) * t; /** uma batida da trilha do kit (104 bpm) em quadros */ export const BATIDA = 17.31; // ---------- medida de texto ---------- let canvas: HTMLCanvasElement | null = null; const cache = new Map(); export const larguraTexto = (texto: string, tamanho: number, peso = 400, trackingEm = 0, familia = 'R7 Shrikhand'): number => { const chave = `${texto}|${tamanho}|${peso}|${trackingEm}|${familia}`; const c = cache.get(chave); if (c !== undefined) return c; if (typeof document === 'undefined') return texto.length * tamanho * 0.58; canvas = canvas || document.createElement('canvas'); const ctx = canvas.getContext('2d'); if (!ctx) return texto.length * tamanho * 0.58; const fonte = `${peso} ${tamanho}px "${familia}"`; ctx.font = fonte; const w = ctx.measureText(texto).width + texto.length * trackingEm * tamanho; if (document.fonts.check(fonte)) cache.set(chave, w); return w; }; /** o maior tamanho até `tamanho` em que o texto cabe em `largura` (nunca palavra cortada) */ export const caber = (texto: string, tamanho: number, largura = LARGURA_UTIL, peso = 400, trackingEm = 0, familia = 'R7 Shrikhand') => { const w = larguraTexto(texto, tamanho, peso, trackingEm, familia); return w > largura ? Math.floor(tamanho * (largura / w)) : tamanho; }; /** tira os asteriscos de destaque: "Usar *IA*" -> "Usar IA" */ export const textoLimpo = (t: string) => t.replace(/\*/g, ''); /** quebra "a *b* c" em pedaços {t, d}: d = true quando estava entre asteriscos */ export const pedacos = (t: string) => t.split(/(\*[^*]+\*)/).filter(Boolean).map((p) => p.startsWith('*') ? {t: p.slice(1, -1), d: true} : {t: p, d: false});