// @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 */}
{/* 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;