// @ts-nocheck // ============================================================================ // MOTION GRAPHICS · OBSIDIAN ORBIT — Scene 09 / DROP THE SCRIPT (11s, 330f) // // "Keynote object-worship". ONE hero artifact: the EPISODE-FOLDER slab — a thick // glass slab whose FACE is an episode workspace (a folder header + an empty // dropzone). A raw ".txt" script card DROPS onto its face from above and docks // with a pop; a scan-line then SWEEPS across the text as the UI reads it, // lighting each line in turn; a READY check pulses on once the read completes. // The WORLD orbits (never the camera) in slow hold→ease arcs; spec Callouts // billboard on drawn leader lines at waypoints ("DROP SCRIPT", "AUTO-READ"); // the angle-tracked sheen rakes the turn. A riser builds into the settle where // the slab LOCKS straight-on with an impact + shockwave as the ready-check // lands — the payoff — then idles, 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}
); }; /* ============================================================================ DROP THE SCRIPT. Hero = the EPISODE-FOLDER artifact. A raw .txt card drops onto the slab face, a scan-line reads the text line-by-line, a ready-check pulses on. The world orbits in, callouts fire, then the slab LOCKS front-on with an impact as the read completes. ========================================================================== */ export const MgOrbitScene09DropScript: React.FC = () => { const frame = useCurrentFrame(); const { fps } = useVideoConfig(); const t = frame / fps; const LOCK = 8.0; // the settle / payoff beat (seconds) // --- face choreography ------------------------------------------------- const folderP = beat(frame, fps, 0.5, 1.6, EASE.out); // workspace fades in const DROP = 2.4; // the .txt card docks onto the face (seconds) const dropSpring = springAt(frame, fps, DROP, SPRING.SNAPPY); // card settle const dropIn = clamp01((t - (DROP - 0.7)) / 0.7); // card travel/visibility const dropY = mix(-360, 0, clamp01(dropSpring)); // falls from above to dock const dropScale = mix(1.12, 1, clamp01(dropSpring)); // slight overshoot // scan-line read: sweeps top→bottom across the docked card's text. const SCAN_START = 3.3; const SCAN_END = 6.0; const scanP = beat(frame, fps, SCAN_START, SCAN_END, EASE.inOut); // 0→1 sweep // ready-check: pulses on once the read finishes, lands hard on the lock. const checkSpring = springAt(frame, fps, LOCK, SPRING.HEAVY); // weighty pop-in const checkP = clamp01(checkSpring); const checkPulse = 0.5 + 0.5 * osc(t, 2.2); // --- the lock-in: a weighty spring settle on the payoff ----------------- const stamp = springAt(frame, fps, LOCK, SPRING.HEAVY); // 0→1 weighty settle const stampScale = mix(1.1, 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); // hold→ease orbit so the slab reads its face on the way in, then a final arc // that settles to centre (0°) right at the lock — 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.5, travel: 1.8 }, // lands ~0° near LOCK ]; // the script card's text lines — each lights as the scan-line crosses it. const scriptLines = [0.9, 0.66, 0.84, 0.5, 0.74, 0.58]; const HeroFace = (
{/* episode folder header — the workspace identity */}
{/* folder glyph */}
Episode 09
Motion Graphics
{/* the dropzone — where the .txt card docks */}
{/* idle dropzone hint — fades as the card arrives */}
drop .txt here
{/* the raw .txt script card — falls in and docks */}
{/* card filename */}
script.txt
{/* the text lines — each lights as the scan-line passes it */}
{scriptLines.map((w, i) => { const lineFrac = (i + 0.5) / scriptLines.length; const read = clamp01((scanP - lineFrac) * 6 + 1); // lit once passed return (
0.01 ? `linear-gradient(90deg, ${withAlpha( C.accent2, mix(0.2, 0.85, read), )}, ${withAlpha("#ffffff", mix(0.1, 0.35, read))})` : withAlpha("#ffffff", 0.18), boxShadow: read > 0.4 ? `0 0 12px ${withAlpha(C.accent, 0.4 * read)}` : "none", }} /> ); })} {/* the scan-line sweeping down the text as the UI reads it */}
0.001 && scanP < 0.999 ? 1 : clamp01((t - SCAN_START) / 0.2) * clamp01((SCAN_END + 0.15 - t) / 0.2), }} />
{/* read-progress bar at the card's foot */}
{/* the READY check — pulses on once the read completes */}
{/* check mark */}
Ready
{/* the lock ring that snaps tight on the payoff beat */}
); return ( Drop The Script {/* riser glow swelling behind the hero into the payoff */} {/* impact flash + shockwave on the ready/lock payoff */} {HeroFace} {/* billboarded spec callouts firing at orbit waypoints */} {/* flat masked mirror sibling — re-renders the hero, simplified & matte */} {HeroFace} ); }; export default MgOrbitScene09DropScript;