Spaces:
Running
Running
| // @ts-nocheck | |
| // ============================================================================ | |
| // MOTION GRAPHICS · OBSIDIAN ORBIT — Scene 10 / COPY DRAFT PROMPT (10s, 300f) | |
| // | |
| // "Keynote object-worship". ONE hero artifact: a glass slab whose face is the | |
| // "Copy Draft Prompt" panel. A solid monolithic script block sits on the face | |
| // under a primary CTA button. On the CLICK beat the button depresses, a prompt | |
| // token flies off + a clipboard pulse rings out ("Copied"), and the solid | |
| // script block FRACTURES — splitting along seams into a clean row of FOUR | |
| // numbered scene cards. The breakdown made literal: one block of intent → | |
| // discrete, ordered scenes. The WORLD orbits (never the camera) in slow | |
| // hold→ease arcs; billboarded spec Callouts fire on leader lines ("STEP 1", | |
| // "COPY DRAFT PROMPT", "4 SCENES"); the angle-tracked sheen rakes the turn; the | |
| // slab settles front-on for the payoff with an impact + shockwave as the cards | |
| // lock into their row. | |
| // | |
| // 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 ( | |
| <div | |
| style={{ | |
| position: "absolute", | |
| left: 120, | |
| top: 120, | |
| display: "flex", | |
| alignItems: "center", | |
| gap: 14, | |
| fontFamily: MONO, | |
| fontSize: 15, | |
| letterSpacing: 5, | |
| textTransform: "uppercase", | |
| color: C.accent2, | |
| ...enter(frame, fps, at, { from: "left", dist: 32, blur: 0 }), | |
| }} | |
| > | |
| <span | |
| style={{ | |
| width: 30, | |
| height: 2, | |
| background: ACCENT_GRAD, | |
| boxShadow: `0 0 12px ${C.accentGlow}`, | |
| }} | |
| /> | |
| {children} | |
| </div> | |
| ); | |
| }; | |
| /* ============================================================================ | |
| COPY DRAFT PROMPT. Hero = the "Copy Draft Prompt" slab. A solid script block | |
| under a primary CTA. On the CLICK the button depresses, a prompt token copies | |
| (clipboard pulse), and the block fractures into a row of 4 numbered scene | |
| cards — the breakdown made literal. World orbits, callouts fire, slab settles. | |
| ========================================================================== */ | |
| export const MgOrbitScene10CopyPrompt: React.FC = () => { | |
| const frame = useCurrentFrame(); | |
| const { fps } = useVideoConfig(); | |
| const t = frame / fps; | |
| const CLICK = 4.6; // the click beat (seconds) — button press + copy | |
| const LOCK = 7.8; // the apex lock-in beat — cards settle into their row | |
| // --- face choreography ------------------------------------------------- | |
| const blockIn = beat(frame, fps, 0.8, 2.0, EASE.out); // solid script block lands | |
| const btnIn = beat(frame, fps, 1.8, 2.8, EASE.backOut); // CTA button arrives | |
| const btnHint = 0.5 + 0.5 * osc(t, 1.4); // gentle pre-click pulse | |
| const press = beat(frame, fps, CLICK, CLICK + 0.18, EASE.out); // button depress | |
| const release = beat(frame, fps, CLICK + 0.18, CLICK + 0.4, EASE.out); | |
| const btnPress = press - release; // 0→1→0 quick depress | |
| // clipboard "copied" pulse ring + token fly | |
| const copyP = beat(frame, fps, CLICK, CLICK + 0.6, EASE.out); | |
| const copyLife = clamp01(1 - (t - CLICK) / 1.2) * (t >= CLICK ? 1 : 0); | |
| const tokenP = beat(frame, fps, CLICK + 0.02, CLICK + 0.55, EASE.expoOut); | |
| // the FRACTURE: the solid block splits into the 4-card row after the click. | |
| const fractureP = beat(frame, fps, CLICK + 0.18, CLICK + 1.6, EASE.expoOut); | |
| // --- the lock-in: a weighty spring settle on the apex ------------------- | |
| 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 lockRing = clamp01(stamp); | |
| const ringPulse = 0.5 + 0.5 * osc(t, 3); | |
| // hold→ease orbit: reads the face on the way in, a turn through the fracture, | |
| // then a final arc that settles to centre (0°) right at the lock — the payoff. | |
| const legs = [ | |
| { arc: -18, hold: 0.6, travel: 2.2 }, | |
| { arc: 24, hold: 1.0, travel: 2.4 }, | |
| { arc: -6, hold: 0.5, travel: 1.7 }, // lands ~0° near LOCK | |
| ]; | |
| const scriptLines = [0.9, 0.72, 0.86, 0.64, 0.8]; | |
| // the four scene cards the block fractures into. seam = where the block was | |
| // cut; offset = how far each shard slides out into its slot in the row. | |
| const cards = [ | |
| { n: 1, label: "INTRO" }, | |
| { n: 2, label: "PROBLEM" }, | |
| { n: 3, label: "DEMO" }, | |
| { n: 4, label: "OUTRO" }, | |
| ]; | |
| const HeroFace = ( | |
| <div | |
| style={{ | |
| position: "absolute", | |
| inset: 0, | |
| padding: 36, | |
| display: "flex", | |
| flexDirection: "column", | |
| gap: 22, | |
| transform: `scale(${stampScale})`, | |
| }} | |
| > | |
| {/* panel title bar */} | |
| <div | |
| style={{ | |
| display: "flex", | |
| alignItems: "center", | |
| justifyContent: "space-between", | |
| opacity: blockIn, | |
| }} | |
| > | |
| <div | |
| style={{ | |
| fontFamily: MONO, | |
| fontSize: 13, | |
| letterSpacing: 4, | |
| color: C.textDim, | |
| textTransform: "uppercase", | |
| }} | |
| > | |
| draft-prompt.txt | |
| </div> | |
| <div | |
| style={{ | |
| fontFamily: MONO, | |
| fontSize: 12, | |
| letterSpacing: 3, | |
| color: C.accent2, | |
| textTransform: "uppercase", | |
| }} | |
| > | |
| {fractureP > 0.5 ? "4 SCENES" : "1 BLOCK"} | |
| </div> | |
| </div> | |
| {/* the body region — holds the solid block, which fractures into cards */} | |
| <div style={{ position: "relative", flex: 1 }}> | |
| {/* SOLID SCRIPT BLOCK — one monolith of intent. Fades/contracts as it | |
| fractures so the row of cards takes its place. */} | |
| <div | |
| style={{ | |
| position: "absolute", | |
| inset: 0, | |
| borderRadius: 16, | |
| padding: 22, | |
| background: `linear-gradient(135deg, ${withAlpha( | |
| "#0c1018", | |
| 0.92, | |
| )}, ${withAlpha("#070a11", 0.92)})`, | |
| border: `1px solid ${C.glassBorder}`, | |
| display: "flex", | |
| flexDirection: "column", | |
| gap: 14, | |
| justifyContent: "center", | |
| opacity: blockIn * clamp01(1 - fractureP * 1.6), | |
| transform: `scale(${mix(1, 0.96, fractureP)})`, | |
| boxShadow: `inset 0 0 50px ${withAlpha("#000", 0.4)}`, | |
| }} | |
| > | |
| {scriptLines.map((w, i) => { | |
| const lp = clamp01((blockIn - i * 0.1) / 0.6); | |
| return ( | |
| <div | |
| key={i} | |
| style={{ | |
| height: 11, | |
| width: `${w * 100 * lp}%`, | |
| borderRadius: 6, | |
| background: | |
| i === 0 | |
| ? withAlpha(C.accent2, 0.6) | |
| : withAlpha("#ffffff", 0.18), | |
| }} | |
| /> | |
| ); | |
| })} | |
| </div> | |
| {/* the FRACTURED ROW — 4 numbered scene cards split out of the block. */} | |
| <div | |
| style={{ | |
| position: "absolute", | |
| inset: 0, | |
| display: "grid", | |
| gridTemplateColumns: "repeat(4, 1fr)", | |
| gap: 14, | |
| opacity: clamp01(fractureP * 1.4), | |
| }} | |
| > | |
| {cards.map((card, i) => { | |
| // each shard staggers out, sliding from the block centre to its slot | |
| // and dropping its fracture seam — reads as a clean split. | |
| const cp = clamp01((fractureP - i * 0.1) / 0.6); | |
| const fromCenter = (i - 1.5) * 24; // pull toward centre pre-split | |
| return ( | |
| <div | |
| key={card.n} | |
| style={{ | |
| borderRadius: 14, | |
| padding: 16, | |
| background: `linear-gradient(160deg, ${withAlpha( | |
| C.accent2, | |
| 0.16, | |
| )}, ${withAlpha("#0a0e16", 0.92)})`, | |
| border: `1px solid ${withAlpha(C.accent, 0.45)}`, | |
| display: "flex", | |
| flexDirection: "column", | |
| justifyContent: "space-between", | |
| opacity: cp, | |
| transform: `translateX(${(1 - cp) * -fromCenter}px) translateY(${ | |
| (1 - cp) * 14 | |
| }px) scale(${mix(0.86, 1, cp)})`, | |
| boxShadow: `0 8px 26px ${withAlpha("#000", 0.5)}, 0 0 ${( | |
| 16 * cp | |
| ).toFixed(0)}px ${withAlpha(C.accent, 0.2 * cp)}`, | |
| }} | |
| > | |
| {/* numbered index — the ordered breakdown */} | |
| <div | |
| style={{ | |
| fontFamily: FONT, | |
| fontWeight: 800, | |
| fontSize: 40, | |
| lineHeight: 0.9, | |
| letterSpacing: "-0.03em", | |
| background: ACCENT_GRAD, | |
| WebkitBackgroundClip: "text", | |
| backgroundClip: "text", | |
| color: "transparent", | |
| filter: `drop-shadow(0 0 12px ${withAlpha(C.accent, 0.4)})`, | |
| }} | |
| > | |
| {card.n} | |
| </div> | |
| <div style={{ display: "flex", flexDirection: "column", gap: 7 }}> | |
| <div | |
| style={{ | |
| height: 6, | |
| width: "78%", | |
| borderRadius: 3, | |
| background: withAlpha("#ffffff", 0.22), | |
| }} | |
| /> | |
| <div | |
| style={{ | |
| height: 6, | |
| width: "54%", | |
| borderRadius: 3, | |
| background: withAlpha("#ffffff", 0.14), | |
| }} | |
| /> | |
| <div | |
| style={{ | |
| fontFamily: MONO, | |
| fontSize: 11, | |
| letterSpacing: 2.5, | |
| color: C.accent2, | |
| textTransform: "uppercase", | |
| marginTop: 4, | |
| }} | |
| > | |
| {card.label} | |
| </div> | |
| </div> | |
| </div> | |
| ); | |
| })} | |
| </div> | |
| </div> | |
| {/* PRIMARY CTA — "Copy Draft Prompt". Depresses on the click beat; a | |
| prompt token flies off + a clipboard pulse rings out. */} | |
| <div | |
| style={{ | |
| position: "relative", | |
| display: "flex", | |
| alignItems: "center", | |
| justifyContent: "center", | |
| opacity: btnIn, | |
| }} | |
| > | |
| <div | |
| style={{ | |
| position: "relative", | |
| display: "flex", | |
| alignItems: "center", | |
| gap: 14, | |
| padding: "18px 34px", | |
| borderRadius: 16, | |
| background: ACCENT_GRAD, | |
| boxShadow: `0 ${(10 - btnPress * 8).toFixed( | |
| 0, | |
| )}px 30px ${withAlpha(C.accent, 0.45)}, inset 0 1px 0 ${withAlpha( | |
| "#ffffff", | |
| 0.4, | |
| )}, 0 0 ${(30 + 26 * btnHint * (1 - clamp01(t - CLICK))).toFixed( | |
| 0, | |
| )}px ${withAlpha(C.accent, 0.3 + 0.25 * btnHint * (t < CLICK ? 1 : 0))}`, | |
| transform: `translateY(${(btnPress * 4).toFixed( | |
| 1, | |
| )}px) scale(${mix(1, 0.97, btnPress)})`, | |
| }} | |
| > | |
| {/* clipboard glyph */} | |
| <div | |
| style={{ | |
| width: 22, | |
| height: 26, | |
| borderRadius: 5, | |
| border: `2.5px solid #1a0d03`, | |
| position: "relative", | |
| flexShrink: 0, | |
| }} | |
| > | |
| <div | |
| style={{ | |
| position: "absolute", | |
| top: -5, | |
| left: "50%", | |
| transform: "translateX(-50%)", | |
| width: 12, | |
| height: 6, | |
| borderRadius: 3, | |
| background: "#1a0d03", | |
| }} | |
| /> | |
| </div> | |
| <div | |
| style={{ | |
| fontFamily: FONT, | |
| fontWeight: 800, | |
| fontSize: 27, | |
| letterSpacing: "-0.01em", | |
| color: "#1a0d03", | |
| }} | |
| > | |
| {copyP > 0.4 && copyLife > 0.05 ? "Copied!" : "Copy Draft Prompt"} | |
| </div> | |
| </div> | |
| {/* clipboard pulse ring radiating from the button on copy */} | |
| <div | |
| style={{ | |
| position: "absolute", | |
| left: "50%", | |
| top: "50%", | |
| width: 120, | |
| height: 120, | |
| marginLeft: -60, | |
| marginTop: -60, | |
| borderRadius: "50%", | |
| border: `2px solid ${withAlpha(C.accent2, 0.7 * copyLife)}`, | |
| transform: `scale(${mix(0.4, 3.2, copyP)})`, | |
| opacity: copyLife * (1 - copyP * 0.4), | |
| pointerEvents: "none", | |
| }} | |
| /> | |
| {/* the prompt token copying out — a small chip flying up to the clipboard */} | |
| <div | |
| style={{ | |
| position: "absolute", | |
| left: "50%", | |
| top: "50%", | |
| transform: `translate(-50%, -50%) translateY(${( | |
| -tokenP * 70 | |
| ).toFixed(0)}px) scale(${mix(0.6, 1, tokenP)})`, | |
| padding: "5px 12px", | |
| borderRadius: 8, | |
| background: withAlpha("#0a0e16", 0.95), | |
| border: `1px solid ${withAlpha(C.accent, 0.6)}`, | |
| fontFamily: MONO, | |
| fontSize: 12, | |
| letterSpacing: 2, | |
| color: C.accent2, | |
| opacity: copyLife, | |
| boxShadow: `0 0 18px ${withAlpha(C.accent, 0.4)}`, | |
| pointerEvents: "none", | |
| whiteSpace: "nowrap", | |
| }} | |
| > | |
| PROMPT | |
| </div> | |
| </div> | |
| {/* the lock ring that snaps tight on the apex beat */} | |
| <div | |
| style={{ | |
| position: "absolute", | |
| inset: 18, | |
| borderRadius: 26, | |
| border: `2px solid ${withAlpha(C.accent, 0.3 + 0.45 * ringPulse)}`, | |
| opacity: lockRing, | |
| boxShadow: `0 0 30px ${withAlpha(C.accent, 0.3 * ringPulse)}`, | |
| pointerEvents: "none", | |
| }} | |
| /> | |
| </div> | |
| ); | |
| return ( | |
| <Plinth> | |
| <Eyebrow at={0.3}>Copy Draft Prompt</Eyebrow> | |
| {/* riser glow swelling behind the hero into the apex */} | |
| <AbsoluteFill style={{ pointerEvents: "none", zIndex: 1 }}> | |
| <GlowPulse | |
| size={1000} | |
| color={withAlpha(C.accent, 0.1 * riser)} | |
| strength={riser} | |
| /> | |
| </AbsoluteFill> | |
| {/* click flash + apex impact / shockwave */} | |
| <AbsoluteFill style={{ pointerEvents: "none", zIndex: 6 }}> | |
| <GlowPulse | |
| size={900} | |
| color={withAlpha(C.accent2, 0.16 * copyLife)} | |
| strength={copyLife} | |
| /> | |
| <GlowPulse | |
| size={1200} | |
| color={withAlpha(C.accent, 0.2 * flash)} | |
| strength={flash} | |
| /> | |
| <Shockwave at={CLICK} size={620} /> | |
| <Shockwave at={LOCK} size={820} /> | |
| <Shockwave at={LOCK + 0.08} size={1120} /> | |
| <LightSweep at={LOCK} dur={1.0} strength={0.16} /> | |
| </AbsoluteFill> | |
| <OrbitWorld legs={legs} perspective={2300} bobAmp={12}> | |
| <DustMotes layers={3} opacity={0.42} /> | |
| <Extrude w={820} h={520} depth={22} layers={16} radius={28}> | |
| {HeroFace} | |
| </Extrude> | |
| {/* billboarded spec callouts firing at orbit waypoints */} | |
| <Callout | |
| title="The Step" | |
| value="STEP 1" | |
| at={fps * 2.2} | |
| x={0} | |
| y={-330} | |
| leader={120} | |
| side="right" | |
| /> | |
| <Callout | |
| title="The Action" | |
| value="COPY DRAFT PROMPT" | |
| at={fps * (CLICK + 0.2)} | |
| x={480} | |
| y={150} | |
| leader={150} | |
| side="right" | |
| /> | |
| <Callout | |
| title="The Breakdown" | |
| value="4 SCENES" | |
| at={fps * (LOCK + 0.3)} | |
| x={-490} | |
| y={140} | |
| leader={160} | |
| side="left" | |
| /> | |
| </OrbitWorld> | |
| {/* flat masked mirror sibling — re-renders the hero, simplified & matte */} | |
| <Plinth.Reflection> | |
| <Extrude w={820} h={520} depth={22} layers={10} radius={28} sheen={false}> | |
| {HeroFace} | |
| </Extrude> | |
| </Plinth.Reflection> | |
| </Plinth> | |
| ); | |
| }; | |
| export default MgOrbitScene10CopyPrompt; |