// Base do kit tutorial-tela (v2): tour de produto com cara de gravação de tela profissional. // Cores, fontes, curvas (rampa de velocidade), medidas da janela. Todo número visual sai daqui. import {continueRender, delayRender} from 'remotion'; import jakarta from './fontes/jakarta.woff2'; import jbmono from './fontes/jbmono.woff2'; export const LARGURA = 1080, ALTURA = 1920, FPS = 30; export const SEGURA = {topo: 168, base: 1330, lado: 88}; /** onde a câmera põe o alvo na tela (o centro óptico do tutorial) */ export const CENTRO: [number, number] = [540, 820]; /** a janela do app, em unidades dela (a câmera escala) */ export const JANELA = {l: 1400, a: 940, barra: 56, lateral: 300}; // ---------- cor (ver regras/cor.md) ---------- export const COR = { chao: '#ECEEF2', chaoFundo: '#DCE0E7', tela: '#FFFFFF', lateral: '#F6F7F9', linha: '#E4E7EC', tinta: '#14161A', apagado: '#6B7280', /** o único acento: o controle da vez, o cursor clicando, o número do passo */ acento: '#FF5B14', acentoClaro: '#FFE4D6', ok: '#17A05D', }; // ---------- fonte ---------- export const FONTE = '"TS Jakarta", system-ui, sans-serif'; export const MONO = '"TS JetBrains Mono", ui-monospace, monospace'; if (typeof document !== 'undefined' && !(globalThis as Record).__k_tutorial2) { (globalThis as Record).__k_tutorial2 = true; const h = delayRender('tutorial-tela: fontes'); Promise.all([['TS Jakarta', jakarta, '500 800'], ['TS JetBrains Mono', jbmono, '500 700']].map(([nome, url, peso]) => new FontFace(nome, `url(${url}) format('woff2')`, {weight: peso, style: 'normal'}).load().then((ff) => {document.fonts.add(ff);}).catch(() => undefined))) .then(() => continueRender(h)); } // ---------- tempo e curva ---------- export const c01 = (t: number) => Math.max(0, Math.min(1, t)); export const seg = (f: number, a: number, b: number) => (b <= a ? (f >= b ? 1 : 0) : c01((f - a) / (b - a))); export const lerp = (a: number, b: number, t: number) => a + (b - a) * t; /** rampa de velocidade: arranca devagar, voa no meio, freia longo (easeInOutQuint) */ export const rampa = (t: number) => {const x = c01(t); return x < 0.5 ? 16 * x ** 5 : 1 - (-2 * x + 2) ** 5 / 2;}; export const e5 = (t: number) => 1 - Math.pow(1 - c01(t), 5); export const mola = (t: number, s = 1.7) => {const x = c01(t) - 1; return x * x * ((s + 1) * x + s) + 1;}; /** batida da trilha (108 bpm) em quadros */ export const BATIDA = 16.7; /** chaves {em, ...valores} → valor interpolado com a rampa */ export const chave = (f: number, ks: ({em: number} & Partial>)[], k: K, padrao: number): number => { const v = ks.filter((c) => c[k] !== undefined) as ({em: number} & Record)[]; if (!v.length) return padrao; if (f <= v[0].em) return v[0][k]; for (let i = 1; i < v.length; i++) if (f <= v[i].em) return lerp(v[i - 1][k], v[i][k], rampa(seg(f, v[i - 1].em, v[i].em))); return v[v.length - 1][k]; }; /** entrada com mola em 12 quadros a partir de `inicio`, saída em 8 a partir de `fim` (−1 = fica) */ export const entradaSaida = (f: number, inicio: number, fim: number) => { const t = mola(seg(f, inicio, inicio + 12)); const s = fim < 0 ? 0 : seg(f, fim, fim + 8); return {t, s, op: f < inicio ? 0 : Math.min(1, seg(f, inicio, inicio + 5) * 1) * (1 - s)}; };