// scenes.jsx — Yohann Escher Motion 30s — v2 (cinematic)
const ASSETS = {
homem: 'https://imagedelivery.net/mYdfeAeRRdkIXG5w7XJhtQ/4107162a-97fa-4750-fcd6-b664090fd600/public',
emaranhado: 'https://imagedelivery.net/mYdfeAeRRdkIXG5w7XJhtQ/d3218d34-0d91-4586-dab5-b2664d041700/public',
cubo: 'https://imagedelivery.net/mYdfeAeRRdkIXG5w7XJhtQ/6895dfab-4fdb-4898-f8d8-0dbc8586ee00/public',
cerebroPress: 'https://imagedelivery.net/mYdfeAeRRdkIXG5w7XJhtQ/41b16920-7e66-4aa9-f3a2-6789a7beda00/public',
cerebro: 'https://imagedelivery.net/mYdfeAeRRdkIXG5w7XJhtQ/b653b8f9-354a-4901-3f85-daa03c10f800/public',
cabecaProgresso: 'https://imagedelivery.net/mYdfeAeRRdkIXG5w7XJhtQ/511ab5bf-2760-4610-4b62-b27717353e00/public',
cabecaCaos: 'https://imagedelivery.net/mYdfeAeRRdkIXG5w7XJhtQ/a3ef3c98-1613-4b2a-fe3f-deba90023d00/public',
nucleo: 'https://imagedelivery.net/mYdfeAeRRdkIXG5w7XJhtQ/9fd367fc-ecdd-424e-930b-1867b4095700/public',
};
const COLORS = {
graphite: '#101214',
graphiteDeep: '#0A0C0D',
graphiteCard: '#191C1E',
graphiteCard2: '#202325',
offwhite: '#F7EFE6',
cream: '#FFF8F0',
orange: '#FF6B1A',
orangeDeep: '#E9580C',
orangeBright: '#FF8540',
textLight: '#F7EFE6',
textDark: '#1E2224',
borderLight: 'rgba(255,255,255,0.12)',
borderDark: '#E6D9C7',
};
const FONT_SANS = '"Manrope", "Inter", system-ui, sans-serif';
const FONT_SERIF = '"Instrument Serif", "Cormorant Garamond", Georgia, serif';
const FONT_MONO = '"JetBrains Mono", ui-monospace, monospace';
// ═══════════════════════════════════════════════════════════════════════════
// BACKGROUND — animated, with grain & vignette
// ═══════════════════════════════════════════════════════════════════════════
function SceneBackground() {
const t = useTime();
let bg = COLORS.graphite;
let dark = true;
if (t >= 7 && t < 13) { bg = COLORS.offwhite; dark = false; }
else if (t >= 13 && t < 16) { bg = COLORS.graphiteDeep; dark = true; }
else if (t >= 16 && t < 20) { bg = COLORS.offwhite; dark = false; }
else if (t >= 20 && t < 24) { bg = COLORS.graphite; dark = true; }
else if (t >= 24 && t < 27) { bg = COLORS.cream; dark = false; }
if (t >= 27) {
const splitProgress = clamp((t - 27) / 0.6, 0, 1);
const splitX = Easing.easeOutCubic(splitProgress) * 100;
return (
);
}
return (
<>
>
);
}
function Vignette({ dark }) {
return (
);
}
// ═══════════════════════════════════════════════════════════════════════════
// TRANSITIONS — dramatic
// ═══════════════════════════════════════════════════════════════════════════
function CircularWipe({ start, fillColor = COLORS.orange, duration = 0.7 }) {
const t = useTime();
if (t < start - 0.2 || t > start + duration + 0.4) return null;
const phase1 = clamp((t - start) / duration, 0, 1); // expand
const phase2 = clamp((t - start - duration) / 0.4, 0, 1); // shrink reveal
const e1 = Easing.easeInOutCubic(phase1);
const e2 = Easing.easeInOutCubic(phase2);
const r1 = e1 * 2400;
const r2 = e2 * 2400;
return (
);
}
function FlashCut({ start, color = '#fff', duration = 0.18 }) {
const t = useTime();
if (t < start || t > start + duration) return null;
const local = (t - start) / duration;
const opacity = local < 0.3 ? local / 0.3 : 1 - (local - 0.3) / 0.7;
return (
);
}
function ScreenShake({ start, end, intensity = 8, children }) {
const t = useTime();
const active = t >= start && t <= end;
const shake = active
? { x: (Math.random() - 0.5) * intensity, y: (Math.random() - 0.5) * intensity }
: { x: 0, y: 0 };
return (
{children}
);
}
// ═══════════════════════════════════════════════════════════════════════════
// KINETIC TYPOGRAPHY — words ripping across screen
// ═══════════════════════════════════════════════════════════════════════════
function MarqueeText({ start, end, text, y, speed = 600, size = 120, color = COLORS.orange, italic = true, opacity = 1 }) {
const t = useTime();
if (t < start || t > end) return null;
const local = t - start;
const x = 1920 - (local * speed);
return (
{text}
);
}
// SplitText: word reveal with stagger and serif italic on accent
function SplitHeadline({ words, x = 960, y = 540, size = 64, dark = true, align = 'center', accentColor = COLORS.orange }) {
const { localTime, duration } = useSprite();
const exitDur = 0.4;
const exitStart = duration - exitDur;
return (
{words.map((w, i) => {
const delay = i * 0.07;
const entryT = clamp((localTime - delay) / 0.5, 0, 1);
const e = Easing.easeOutCubic(entryT);
let opacity = e;
let ty = (1 - e) * 24;
if (localTime > exitStart) {
const ex = Easing.easeInCubic(clamp((localTime - exitStart) / exitDur, 0, 1));
opacity *= 1 - ex;
ty -= ex * 12;
}
const isAccent = w.italic;
return (
{w.text}
);
})}
);
}
// ═══════════════════════════════════════════════════════════════════════════
// CHIPS & CARDS
// ═══════════════════════════════════════════════════════════════════════════
function Chip({ label, x, y, dark = true, rot = 0, delay = 0, accent = false, size = 'md', icon, exitAt }) {
const { localTime, duration } = useSprite();
const t = clamp((localTime - delay) / 0.45, 0, 1);
const e = Easing.easeOutBack(t);
let opacity = clamp(t * 1.4, 0, 1);
let extraY = 0;
let extraScale = 1;
// Optional collapse-on-exit
if (exitAt != null && localTime >= exitAt) {
const ex = clamp((localTime - exitAt) / 0.5, 0, 1);
const exE = Easing.easeInQuad(ex);
opacity *= 1 - exE;
extraScale = 1 - exE * 0.4;
// suck toward center
const cx = 960, cy = 540;
extraY = 0;
return (
{icon && {icon}}
{label}
);
}
return (
{icon && {icon}}
{label}
);
}
function HeroAsset({ src, x = 960, y = 540, size = 480, dark = true, rotate = 0, drift = 0, breathe = 0, kenBurns = 0 }) {
const { localTime, progress } = useSprite();
const entry = clamp(localTime / 0.7, 0, 1);
const e = Easing.easeOutCubic(entry);
const breatheS = breathe ? 1 + Math.sin(localTime * 1.2) * breathe : 1;
const kbS = kenBurns ? 1 + progress * kenBurns : 1;
const scale = (0.92 + 0.08 * e) * breatheS * kbS;
const opacity = e;
const driftY = Math.sin(localTime * 1.0) * drift;
return (
);
}
// Subtle moving grid background
function TechGrid({ dark = true, opacity = 0.08 }) {
const t = useTime();
const offset = (t * 30) % 80;
return (
);
}
// ═══════════════════════════════════════════════════════════════════════════
// SCENE 1 — 0–4s — Information overload — heavy chaos buildup
// ═══════════════════════════════════════════════════════════════════════════
function Scene1() {
const { localTime } = useSprite();
const chips = [
{ label: 'ChatGPT', x: 360, y: 220, rot: -4, delay: 0.05 },
{ label: 'Claude', x: 1560, y: 200, rot: 3, delay: 0.1 },
{ label: 'Prompts', x: 240, y: 460, rot: 5, delay: 0.15, accent: true },
{ label: 'Agentes', x: 1680, y: 480, rot: -3, delay: 0.2 },
{ label: 'n8n', x: 320, y: 720, rot: 4, delay: 0.25 },
{ label: 'APIs', x: 1620, y: 740, rot: -4, delay: 0.3 },
{ label: 'RAG', x: 460, y: 880, rot: 2, delay: 0.35 },
{ label: 'Embeddings', x: 1480, y: 900, rot: -3, delay: 0.4 },
{ label: 'Tutoriais', x: 200, y: 600, rot: -3, delay: 0.45 },
{ label: '+1 vídeo salvo', x: 1700, y: 620, rot: 4, delay: 0.5, accent: true },
{ label: '+1 prompt', x: 540, y: 120, rot: -3, delay: 0.55 },
{ label: '+1 ferramenta', x: 1380, y: 100, rot: 3, delay: 0.6, accent: true },
{ label: 'MCP', x: 720, y: 940, rot: -2, delay: 0.65 },
{ label: 'Cursor', x: 1240, y: 940, rot: 3, delay: 0.7 },
{ label: 'LangChain', x: 180, y: 320, rot: -5, delay: 0.75 },
{ label: 'Make', x: 1740, y: 340, rot: 4, delay: 0.8 },
];
const camShake = localTime > 2.8 ? Math.sin(localTime * 60) * 3 : 0;
return (
{/* Broken connector mess */}
{/* Pulsing chromatic aberration as chaos peaks */}
{localTime > 2.5 && (
)}
{chips.map((c, i) => )}
{/* Marquee word "INFORMAÇÃO" passing through */}
);
}
// ═══════════════════════════════════════════════════════════════════════════
// SCENE 2 — 4–7s — Brain under pressure — orbit + glitch
// ═══════════════════════════════════════════════════════════════════════════
function Scene2() {
const { localTime } = useSprite();
const dots = Array.from({ length: 18 }, (_, i) => {
const angle = (i / 18) * Math.PI * 2 + localTime * 0.7;
const r = 320 + Math.sin(localTime * 2.5 + i) * 40;
const x = 960 + Math.cos(angle) * r;
const y = 480 + Math.sin(angle) * r * 0.7;
const blink = (Math.sin(localTime * 5 + i * 1.3) + 1) / 2;
return { x, y, blink, key: i };
});
const orbiters = [
{ label: 'notif', x: 380, y: 260, rot: -3, delay: 0.15, icon: '●' },
{ label: 'inbox', x: 1540, y: 280, rot: 3, delay: 0.3, icon: '●' },
{ label: 'task', x: 360, y: 700, rot: 2, delay: 0.45, icon: '●' },
{ label: 'TODO', x: 1560, y: 720, rot: -2, delay: 0.55, icon: '●' },
{ label: 'pendente', x: 240, y: 480, rot: -4, delay: 0.65, accent: true },
{ label: 'urgente', x: 1700, y: 500, rot: 4, delay: 0.75, accent: true },
];
return (
<>
{dots.map(d => (
))}
{/* Lines feeding INTO brain (input) but never out */}
{orbiters.map((c, i) => )}
>
);
}
// ═══════════════════════════════════════════════════════════════════════════
// SCENE 3 — 7–10s — Inner chaos — head opens, fragments fly out
// ═══════════════════════════════════════════════════════════════════════════
function Scene3() {
const { localTime } = useSprite();
const items = ['Clareza', 'Método', 'Stack', 'Execução', 'Projeto'];
// Floating fragments coming OUT of head
const fragments = Array.from({ length: 14 }, (_, i) => {
const baseAngle = -Math.PI / 2 + (i / 14 - 0.5) * Math.PI * 0.8;
const dist = 80 + (i % 4) * 60 + localTime * 30;
const x = 620 + Math.cos(baseAngle) * dist;
const y = 380 + Math.sin(baseAngle) * dist - localTime * 40;
const opacity = clamp(1 - (localTime - 0.5) * 0.2 - (i % 5) * 0.1, 0, 1);
return { x, y, opacity, key: i, label: ['{}', '[]', '01', '<>', '⌘', '#'][i % 6] };
});
return (
<>
{fragments.map(f => (
{f.label}
))}
{/* Right column — cards lighting up sequentially */}
{items.map((label, i) => {
const delay = 0.4 + i * 0.18;
const t = clamp((localTime - delay) / 0.6, 0, 1);
const e = Easing.easeOutCubic(t);
const lit = localTime >= delay + 0.4;
return (
{label}
{String(i + 1).padStart(2, '0')}
);
})}
{/* Failed line trying to connect */}
>
);
}
// ═══════════════════════════════════════════════════════════════════════════
// SCENE 4 — 10–13s — The reset cycle
// ═══════════════════════════════════════════════════════════════════════════
function Scene4() {
const { localTime } = useSprite();
const cycle = (localTime % 1.3) / 1.3;
const progress = cycle < 0.85 ? Easing.easeOutQuad(cycle / 0.85) * 0.95 : (1 - (cycle - 0.85) / 0.15) * 0.12;
const pct = Math.floor(progress * 100);
const resetting = cycle >= 0.85;
const microTexts = [
{ text: 'vou estudar mais um pouco', x: 360, y: 300, delay: 0.2 },
{ text: 'só falta entender essa ferramenta', x: 1500, y: 260, delay: 0.5 },
{ text: 'depois eu começo', x: 320, y: 720, delay: 0.9 },
{ text: 'preciso ver mais um tutorial', x: 1520, y: 760, delay: 1.3 },
{ text: 'amanhã eu foco de verdade', x: 960, y: 200, delay: 1.7 },
];
return (
<>
{/* Progress bar with reset flash */}
{pct.toString().padStart(2, '0')}%
{resetting && ↺ reset}
100%
{microTexts.map((m, i) => {
const t = clamp((localTime - m.delay) / 0.4, 0, 1);
const fadeOut = clamp((localTime - m.delay - 1.2) / 0.4, 0, 1);
return (
"{m.text}"
);
})}
>
);
}
// ═══════════════════════════════════════════════════════════════════════════
// SCENE 5 — 13–16s — TANGLE — climax. tools trapped, dramatic
// ═══════════════════════════════════════════════════════════════════════════
function Scene5() {
const { localTime } = useSprite();
const rot = localTime * 6;
const trapped = [
{ label: 'IA', x: 540, y: 360, delay: 0.3 },
{ label: 'Conteúdo', x: 1380, y: 340, delay: 0.4 },
{ label: 'Automação', x: 500, y: 720, delay: 0.5 },
{ label: 'Código', x: 1420, y: 700, delay: 0.6 },
{ label: 'Dados', x: 720, y: 200, delay: 0.7 },
{ label: 'Vendas', x: 1200, y: 880, delay: 0.8 },
];
// Stuck dot trying to escape
const dotAngle = localTime * 1.2;
const dotR = 220 + Math.sin(localTime * 3) * 50;
const dotX = 960 + Math.cos(dotAngle * 1.3) * dotR;
const dotY = 540 + Math.sin(dotAngle * 2.1) * dotR * 0.7;
// Big background word
const bgWordOpacity = clamp((localTime - 0.2) / 0.5, 0, 1) * 0.06;
return (
<>
{/* Massive background word */}
CAOS
{/* Spotlight on tangle */}
{/* Stuck dot with trail */}
{trapped.map((c, i) => )}
{/* Text 1: "Não é falta de ferramenta." appears, then gets struck through */}
{/* Text 2: huge dramatic "É falta de ESTRUTURA" */}
>
);
}
function StrikethroughLine() {
const { localTime, duration } = useSprite();
const e = Easing.easeOutCubic(clamp(localTime / 0.4, 0, 1));
const strike = clamp((localTime - 0.9) / 0.3, 0, 1);
const exit = clamp((localTime - duration + 0.4) / 0.4, 0, 1);
return (
Não é falta de ferramenta.
);
}
function BigImpactText() {
const { localTime } = useSprite();
const e = Easing.easeOutBack(clamp(localTime / 0.5, 0, 1));
return (
É falta de{' '}
estrutura
.
);
}
// ═══════════════════════════════════════════════════════════════════════════
// SCENE 6 — 16–20s — Architecture forms
// ═══════════════════════════════════════════════════════════════════════════
function Scene6() {
const { localTime } = useSprite();
const labels = [
{ label: 'Fundamentos', angle: 0 },
{ label: 'Prompting', angle: 36 },
{ label: 'Claude Code', angle: 72 },
{ label: 'Automações', angle: 108 },
{ label: 'Agentes', angle: 144 },
{ label: 'APIs', angle: 180 },
{ label: 'Sistemas', angle: 216 },
{ label: 'Conteúdo', angle: 252 },
{ label: 'Produto', angle: 288 },
{ label: 'Execução', angle: 324 },
];
return (
<>
{/* Animated grid drawing in */}
{labels.map((l, i) => {
const delay = 0.5 + i * 0.09;
const t = clamp((localTime - delay) / 0.5, 0, 1);
const e = Easing.easeOutBack(t);
const rad = (l.angle * Math.PI) / 180;
const r = 400;
const x = 960 + Math.cos(rad) * r;
const y = 500 + Math.sin(rad) * r * 0.85;
return (
{l.label}
);
})}
{/* Lines from cube to each label */}
>
);
}
// ═══════════════════════════════════════════════════════════════════════════
// SCENE 7 — 20–24s — Steps lighting + flow
// ═══════════════════════════════════════════════════════════════════════════
function Scene7() {
const { localTime } = useSprite();
const steps = [
'Entender IA',
'Prompts com intenção',
'Usar Claude Code',
'Automatizar fluxos',
'Criar agentes',
'Construir sistemas',
'Aplicar em marketing',
'Transformar em oportunidade',
];
return (
<>
{/* Side brain (organized, lateral) */}
{/* Steps stack with active sweep */}
{steps.map((s, i) => {
const delay = 0.2 + i * 0.16;
const t = clamp((localTime - delay) / 0.45, 0, 1);
const e = Easing.easeOutCubic(t);
const active = localTime >= delay && localTime <= delay + 0.9;
const done = localTime > delay + 0.9;
return (
{String(i + 1).padStart(2, '0')}
{s}
{done && (
)}
);
})}
>
);
}
function MiniFlow() {
const { localTime } = useSprite();
const steps = ['Ideia', 'Prompt', 'Código', 'Automação', 'Sistema', 'Resultado'];
const W = 1300;
const stepW = W / (steps.length - 1);
const startX = (1920 - W) / 2;
const dotProgress = clamp(localTime / 1.6, 0, 1);
const dotE = Easing.easeInOutCubic(dotProgress);
const dotX = startX + dotE * W;
return (
<>
{steps.map((s, i) => {
const x = startX + i * stepW;
const reached = dotX >= x - 5;
return (
{s}
);
})}
>
);
}
// ═══════════════════════════════════════════════════════════════════════════
// SCENE 8 — 24–27s — Nucleus
// ═══════════════════════════════════════════════════════════════════════════
function Scene8() {
const { localTime } = useSprite();
const pulse = 1 + Math.sin(localTime * 3) * 0.04;
const modules = [
{ label: 'Estratégia', angle: -90 },
{ label: 'IA', angle: -30 },
{ label: 'Automação', angle: 30 },
{ label: 'Software', angle: 90 },
{ label: 'Marketing', angle: 150 },
{ label: 'Dados', angle: 210 },
];
return (
<>
{/* Soft radial gradient glow */}
{/* Concentric pulse rings */}
{[0, 0.4, 0.8].map((offset, i) => {
const phase = ((localTime + offset) % 1.2) / 1.2;
const r = 200 + phase * 320;
const op = (1 - phase) * 0.4;
return (
);
})}
{modules.map((m, i) => {
const delay = 0.3 + i * 0.12;
const t = clamp((localTime - delay) / 0.6, 0, 1);
const e = Easing.easeOutBack(t);
const rad = (m.angle * Math.PI) / 180;
const r = 380;
const x = 960 + Math.cos(rad) * r;
const y = 480 + Math.sin(rad) * r * 0.85;
return (
{m.label}
);
})}
>
);
}
// ═══════════════════════════════════════════════════════════════════════════
// SCENE 9 — 27–30s — Final
// ═══════════════════════════════════════════════════════════════════════════
function Scene9() {
const { localTime } = useSprite();
const pulse = 1 + Math.sin(localTime * 2.5) * 0.03;
const results = [
{ label: 'clareza', x: 360, y: 280, delay: 0.3, side: 'dark' },
{ label: 'projetos', x: 1560, y: 260, delay: 0.4, side: 'light' },
{ label: 'automações', x: 300, y: 540, delay: 0.5, side: 'dark' },
{ label: 'agentes', x: 1620, y: 540, delay: 0.6, side: 'light' },
{ label: 'sistemas', x: 360, y: 800, delay: 0.7, side: 'dark' },
{ label: 'execução', x: 1560, y: 800, delay: 0.8, side: 'light' },
];
return (
<>
{/* Cube faded behind */}
{/* Nucleus */}
{/* Connector lines */}
{results.map((r, i) => {
const t = clamp((localTime - r.delay) / 0.5, 0, 1);
const e = Easing.easeOutBack(t);
const onDark = r.side === 'dark';
return (
{r.label}
);
})}
>
);
}
function FinalText({ text, accent, post }) {
const { localTime } = useSprite();
const t = clamp(localTime / 0.4, 0, 1);
const e = Easing.easeOutCubic(t);
return (
{text}
{accent && (
{accent}
)}
{post}
);
}
function CTA() {
const { localTime } = useSprite();
const t = clamp(localTime / 0.5, 0, 1);
const e = Easing.easeOutBack(t);
const glow = 0.5 + Math.sin(localTime * 4) * 0.3;
const tweaks = (typeof window !== 'undefined' && window.__tweaks) || {};
const label = tweaks.ctaLabel || 'Entrar na mentoria';
const accent = tweaks.accentColor || COLORS.orange;
return (
);
}
// ═══════════════════════════════════════════════════════════════════════════
// CROSS-SCENE KINETIC OVERLAY — Words sweeping the entire timeline
// ═══════════════════════════════════════════════════════════════════════════
function KineticOverlay() {
return (
<>
{/* SCENE 5 lead-in — big tension words flying */}
{/* SCENE 6 reveal word */}
{/* SCENE 7 momentum */}
{/* SCENE 8 build */}
{/* SCENE 9 finale ribbon */}
>
);
}
// ═══════════════════════════════════════════════════════════════════════════
// TIME LABEL
// ═══════════════════════════════════════════════════════════════════════════
function TimeLabel() {
const t = useTime();
React.useEffect(() => {
const sec = Math.floor(t);
const stage = document.querySelector('[data-screen-label]');
if (stage) stage.setAttribute('data-screen-label', `${sec}s`);
}, [Math.floor(t)]);
return null;
}
// ═══════════════════════════════════════════════════════════════════════════
// MAIN
// ═══════════════════════════════════════════════════════════════════════════
function MotionVideo({ tweaks }) {
return (
{/* Dramatic transitions */}
{/* Brand mark */}
YOHANN ESCHER · MENTORIA
{/* Time code badge */}
{/* Grain overlay */}
);
}
function TimeCode() {
const t = useTime();
return (
● REC {t.toFixed(2).padStart(5, '0')}s / 30.00s
);
}
Object.assign(window, { MotionVideo, COLORS, ASSETS, FONT_SANS, FONT_SERIF });