// @ts-nocheck // ============================================================================ // MOTION GRAPHICS · OBSIDIAN ORBIT — Scene 15 / GENERATE → PREVIEW (13s, 390f) // // "Keynote object-worship". ONE hero artifact: the GENERATION slab. A thick // glass slab whose face is a render farm — a GRID of asset tiles that fill in // one-by-one as a progress bar climbs ("GENERATING…"). When the grid completes, // a "Launch Motion Studio" button lights up and is clicked; the face transitions // into a STUDIO PREVIEW where a play head scrubs across a row of scene // thumbnails. The WORLD orbits (never the camera) in slow hold→ease arcs; spec // Callouts billboard on drawn leader lines ("GENERATING…", "LAUNCH STUDIO", // "13s PREVIEW"); the angle-tracked sheen rakes the turn. A riser builds into // the launch where the slab LOCKS straight-on with an impact + shockwave — the // payoff — then settles into the scrubbing studio, sheen tracking the final turn. // // Built ENTIRELY on the Plinth module (mirrors ObsidianOrbit.tsx's contract) + // the shared Chronixel engine. CSS-3D only, deterministic, no WebGL. // ============================================================================ import React from "react"; import { AbsoluteFill, useCurrentFrame, useVideoConfig } from "remotion"; import { Plinth, OrbitWorld, Extrude, Callout, DustMotes, } from "../../plinth/plinth"; import { C, withAlpha, ACCENT_GRAD } from "../../chronixel/theme"; import { FONT, MONO } from "../../chronixel/fonts"; import { beat, clamp01, mix, osc, enter, springAt, EASE, SPRING, } from "../../chronixel/motion"; import { Shockwave, GlowPulse, LightSweep } from "../../chronixel/fx"; /* ---------------------------------------------------------------------------- A small mono eyebrow tag pinned top-left over the void — frames the beat. -------------------------------------------------------------------------- */ const Eyebrow: React.FC<{ at: number; children: React.ReactNode }> = ({ at, children, }) => { const frame = useCurrentFrame(); const { fps } = useVideoConfig(); return (
{children}
); }; /* ============================================================================ GENERATE → PREVIEW. Hero = the generation slab. A 4x3 grid of asset tiles fills in one-by-one while a progress bar climbs; at completion a "Launch Motion Studio" button is clicked and the face flips to a studio preview where a play head scrubs across scene thumbnails. World orbits in, callouts fire, slab LOCKS front-on at the launch, then settles into the scrubbing studio. ========================================================================== */ export const MgOrbitScene15Generate: React.FC = () => { const frame = useCurrentFrame(); const { fps } = useVideoConfig(); const t = frame / fps; const LOCK = 8.4; // the launch lock-in beat (seconds) — the payoff // --- generation grid: 12 tiles fill one-by-one ------------------------ const COLS = 4; const ROWS = 3; const TILES = COLS * ROWS; const GEN_START = 1.0; // first tile begins const GEN_STEP = 0.42; // seconds between tiles igniting const GEN_FILL = 0.5; // seconds for a tile to pop in // overall generation progress 0→1 (drives the bar + the "GENERATING…" %). const genLast = GEN_START + (TILES - 1) * GEN_STEP + GEN_FILL; const genProg = clamp01((t - GEN_START) / (genLast - GEN_START)); const genPct = Math.round(100 * genProg); const genDone = genProg >= 1; // --- launch button: lights once grid is full, clicked at the lock ------ const BTN_LIVE = genLast; // button becomes live when grid completes const btnIn = beat(frame, fps, BTN_LIVE, BTN_LIVE + 0.5, EASE.backOut); const btnGlow = 0.5 + 0.5 * osc(t, 1.4); const press = beat(frame, fps, LOCK - 0.18, LOCK, EASE.out); // click depress const pressScale = 1 - 0.06 * (press - clamp01((t - LOCK) / 0.18)); // --- studio preview: opens at the launch, play head scrubs ------------- const studioOpen = beat(frame, fps, LOCK, LOCK + 0.8, EASE.expoOut); // play head sweeps left→right across the thumbnail strip, looping gently. const scrubRaw = clamp01((t - (LOCK + 0.7)) / 3.4); const scrub = scrubRaw; // 0→1 across the strip const STUDIO_TILES = 5; // --- the lock-in: a weighty spring settle on the launch ---------------- const stamp = springAt(frame, fps, LOCK, SPRING.HEAVY); // 0→1 weighty settle const stampScale = mix(1.12, 1, clamp01(stamp)); // slams down to rest const flash = clamp01(1 - (t - LOCK) / 0.45) * (t >= LOCK ? 1 : 0); const riser = beat(frame, fps, LOCK - 1.4, LOCK, EASE.out); // build into apex const ringPulse = 0.5 + 0.5 * osc(t, 3); const lockRing = clamp01(stamp); // hold→ease orbit so the slab reads the grid filling, then a final arc that // settles to centre (0°) right at the launch — the snap-to-camera payoff. const legs = [ { arc: -18, hold: 0.6, travel: 2.6 }, { arc: 26, hold: 1.2, travel: 2.8 }, { arc: -8, hold: 0.6, travel: 1.8 }, // lands ~0° near LOCK ]; // deterministic per-tile "kind" so the grid reads like varied assets. const tileKind = (i: number) => i % 3; // 0 thumb, 1 wave, 2 chip const HeroFace = (
{/* the lock ring that snaps tight on the launch beat */}
{/* header row — title + GENERATING…/READY status pill */}
render · queue
{genDone ? "READY" : `GENERATING ${genPct}%`}
{/* the GRID of asset tiles — fills one-by-one */}
{Array.from({ length: TILES }, (_, i) => { const tAt = GEN_START + i * GEN_STEP; const fp = beat(frame, fps, tAt, tAt + GEN_FILL, EASE.backOut); const justLit = clamp01(1 - (t - (tAt + GEN_FILL)) / 0.4); const kind = tileKind(i); return (
0.02 ? `linear-gradient(135deg, ${withAlpha( C.accent2, 0.22, )}, ${withAlpha("#0a0e16", 0.9)})` : withAlpha("#0a0e16", 0.5), border: `1px solid ${withAlpha( C.accent, 0.18 + 0.4 * fp + 0.4 * justLit, )}`, opacity: mix(0.35, 1, fp), transform: `scale(${mix(0.84, 1, fp)})`, boxShadow: fp > 0.5 ? `0 6px 20px ${withAlpha("#000", 0.5)}, 0 0 ${( 18 * justLit ).toFixed(0)}px ${withAlpha(C.accent, 0.4 * justLit)}` : "none", }} > {/* tile content varies by kind to read as varied assets */} {kind === 0 && ( <>
)} {kind === 1 && (
{[0.4, 0.8, 0.55, 0.95, 0.65, 0.85].map((h, b) => (
))}
)} {kind === 2 && (
)} {/* ignition flash as the tile lands */}
); })} {/* STUDIO PREVIEW overlay — slides up over the grid on launch */}
{/* studio header — Motion Studio + 13s preview clock */}
Motion Studio
{`00:${String(Math.floor(scrub * 13)).padStart(2, "0")} / 00:13`}
{/* big preview viewport — the current scene under the play head */}
{/* play triangle */}
{/* thumbnail strip + scrubbing play head */}
{Array.from({ length: STUDIO_TILES }, (_, i) => { const active = Math.floor(scrub * STUDIO_TILES) === i ? 1 : 0; return (
); })}
{/* the play head line that scrubs across the strip */}
{/* progress bar + LAUNCH MOTION STUDIO button (hidden once studio opens) */}
{/* progress track */}
{/* launch button — lights up once the grid is full, then is clicked */}
0.4 ? "#1a0d03" : C.textDim, background: btnIn > 0.02 ? ACCENT_GRAD : withAlpha("#ffffff", 0.06), border: `1px solid ${withAlpha(C.accent, 0.4 + 0.4 * btnIn)}`, boxShadow: btnIn > 0.4 ? `0 0 ${(22 + 14 * btnGlow).toFixed( 0, )}px ${withAlpha(C.accent, 0.45 * btnGlow)}` : "none", opacity: mix(0.5, 1, btnIn), transform: `scale(${mix(0.94, 1, btnIn) * pressScale})`, }} > Launch Motion Studio
); return ( Generate · Preview {/* riser glow swelling behind the hero into the launch */} {/* impact flash + shockwave on the launch payoff */} {HeroFace} {/* billboarded spec callouts firing at orbit waypoints */} {/* flat masked mirror sibling — re-renders the hero, simplified & matte */} {HeroFace} ); }; export default MgOrbitScene15Generate;