// skeleton-reveal — slack-promo 4–15s combined // three-stage reveal: a full-screen hand-drawn rough-brush doodle placeholder (round-tipped blob line // art, boiling jitter) → replaced within one beat by a gray-bar skeleton UI window → the skeleton // message list rolls in, and as the camera pushes in the gray bars "develop" line by line into // avatar + text content (the last word of the last line arrives half a beat late). import React from 'react'; import { AbsoluteFill, useCurrentFrame, useVideoConfig, interpolate, spring, Easing, } from 'remotion'; const mulberry32 = (a: number) => () => { let t = (a += 0x6d2b79f5); t = Math.imul(t ^ (t >>> 15), t | 1); t ^= t + Math.imul(t ^ (t >>> 7), t | 61); return ((t ^ (t >>> 14)) >>> 0) / 4294967296; }; const INK = '#2f2f2f'; const PAPER = '#f2f0ea'; // ——— hand-drawn doodle helpers: jitter polylines/circles with a seed and stroke them thick with round caps ——— const wobbleLine = ( x1: number, y1: number, x2: number, y2: number, seed: number, amp = 7, segs = 8, ) => { const rnd = mulberry32(seed); const pts: string[] = []; for (let i = 0; i <= segs; i++) { const t = i / segs; const jx = (rnd() - 0.5) * amp * 2; const jy = (rnd() - 0.5) * amp * 2; pts.push(`${i === 0 ? 'M' : 'L'} ${x1 + (x2 - x1) * t + jx} ${y1 + (y2 - y1) * t + jy}`); } return pts.join(' '); }; const wobbleBlobRect = ( x: number, y: number, w: number, h: number, seed: number, amp = 10, r = 70, ) => { // round-tipped blob rect: edges jitter mid-segment, corners are large arcs const rnd = mulberry32(seed); const j = () => (rnd() - 0.5) * amp * 2; return [ `M ${x + r + j()} ${y + j()}`, `L ${x + w / 2 + j()} ${y + j()}`, `L ${x + w - r + j()} ${y + j()}`, `Q ${x + w + j()} ${y + j()} ${x + w + j()} ${y + r + j()}`, `L ${x + w + j()} ${y + h / 2 + j()}`, `L ${x + w + j()} ${y + h - r + j()}`, `Q ${x + w + j()} ${y + h + j()} ${x + w - r + j()} ${y + h + j()}`, `L ${x + w / 2 + j()} ${y + h + j()}`, `L ${x + r + j()} ${y + h + j()}`, `Q ${x + j()} ${y + h + j()} ${x + j()} ${y + h - r + j()}`, `L ${x + j()} ${y + h / 2 + j()}`, `L ${x + j()} ${y + r + j()}`, `Q ${x + j()} ${y + j()} ${x + r + j()} ${y + j()}`, ].join(' '); }; const wobbleCircle = (cx: number, cy: number, r: number, seed: number, amp = 6) => { const rnd = mulberry32(seed); const n = 14; const pts: string[] = []; for (let i = 0; i <= n; i++) { const a = (i / n) * Math.PI * 2; const rr = r + (rnd() - 0.5) * amp * 2; pts.push(`${i === 0 ? 'M' : 'L'} ${cx + Math.cos(a) * rr} ${cy + Math.sin(a) * rr}`); } return pts.join(' ') + ' Z'; }; const Doodle: React.FC<{ boil: number }> = ({ boil }) => { const S = boil * 977; // each boil swaps in a fresh set of jitter seeds const stroke = { fill: 'none' as const, stroke: INK, strokeLinecap: 'round' as const, strokeLinejoin: 'round' as const, }; return ( ); }; // ——— skeleton/content message rows ——— const NAMES = ['Ana', 'Ben', 'Kai', 'Mia']; const AVA = ['#5a5a58', '#7a7a78', '#4a4a48', '#8f8f8d']; const MSGS = [ 'Morning! Kicking off the rebrand today', 'Logo drafts are ready for review', 'Nice — shipping the deck this afternoon', 'Love it. Can we make it pink?', ]; const Row: React.FC<{ i: number; dev: number; wordAt: (w: number, n: number) => number }> = ({ i, dev, wordAt, }) => { const words = MSGS[i].split(' '); return (