{ "$schema": "https://ui.shadcn.com/schema/registry-item.json", "name": "landing-code-showcase", "title": "Landing Code Showcase", "description": "Magical split-screen: code types itself on the left while the preview reactively re-renders on the right with sparks and tactile bounce.", "dependencies": [ "remotion" ], "files": [ { "path": "registry/remocn/landing-code-showcase/index.tsx", "content": "\"use client\";\n\nimport type { ReactNode } from \"react\";\nimport {\n AbsoluteFill,\n Freeze,\n interpolate,\n Sequence,\n spring,\n useCurrentFrame,\n useVideoConfig,\n} from \"remotion\";\nimport { DashboardPopulate } from \"@/registry/remocn/dashboard-populate\";\nimport { FrostedGlassWipe } from \"@/registry/remocn/frosted-glass-wipe\";\nimport { SpatialPush } from \"@/registry/remocn/spatial-push\";\nimport { TerminalToBrowserDeploy } from \"@/registry/remocn/terminal-to-browser-deploy\";\n\nexport interface LandingCodeShowcaseProps {\n accentColor?: string;\n speed?: number;\n}\n\nconst FONT_FAMILY =\n \"var(--font-geist-sans), -apple-system, BlinkMacSystemFont, sans-serif\";\nconst MONO_FAMILY =\n \"var(--font-geist-mono), ui-monospace, SFMono-Regular, Menlo, monospace\";\n\n/* -------------------------------------------------------------------------- */\n/* Tokens */\n/* -------------------------------------------------------------------------- */\n\nconst PEACH = \"#FFB38E\";\nconst LAVENDER = \"#D4B3FF\";\nconst MINT = \"#A1EEBD\";\nconst STAGE_BG = \"#0A090E\";\nconst PANEL_BG = \"#141318\";\n\n/* -------------------------------------------------------------------------- */\n/* Timeline schedule */\n/* -------------------------------------------------------------------------- */\n/*\n Frame layout (30fps base):\n 0 ────────────────────────────► 90 BlurReveal\n 70 ────► 130 SpatialPush overlay\n 130 ────────────► 240 Dashboard\n 230 ────► 290 FrostedGlassWipe overlay\n 290 ────────────► 410 MaskedSlideReveal\n 400 ────► 460 KineticTypeMask overlay\n 460 ────────────────► 640 TerminalToBrowserDeploy\n*/\n\ninterface SceneWindow {\n start: number;\n duration: number;\n}\n\nconst SCENES = {\n blur: { start: 0, duration: 90 } as SceneWindow,\n push1: { start: 70, duration: 60 } as SceneWindow,\n dashboard: { start: 130, duration: 110 } as SceneWindow,\n glassWipe: { start: 230, duration: 60 } as SceneWindow,\n maskedSlide: { start: 290, duration: 120 } as SceneWindow,\n push2: { start: 400, duration: 60 } as SceneWindow,\n terminal: { start: 460, duration: 180 } as SceneWindow,\n // Quiet hold at the very end so the loop never restarts mid-action.\n endHold: 80,\n};\n\nconst TOTAL_DURATION =\n SCENES.terminal.start + SCENES.terminal.duration + SCENES.endHold; // 720\n\n/* -------------------------------------------------------------------------- */\n/* Code timeline */\n/* -------------------------------------------------------------------------- */\n\ninterface CodeStep {\n /** Frame at which this fragment STARTS being typed */\n startFrame: number;\n /** Code fragment to append to the visible buffer */\n code: string;\n /** Token within the fragment that pulses lavender briefly when typed */\n highlight?: string;\n}\n\nconst HEADER = `import { BlurReveal, DashboardPopulate, MaskedSlideReveal,\n TerminalToBrowserDeploy, Transition } from \"@/components/remocn\";\n\nexport default function Scene() {\n return (\n <>\n`;\n\nconst FOOTER = ` \n );\n}`;\n\nconst STEPS: CodeStep[] = [\n {\n startFrame: 4,\n code: ` \\n`,\n },\n {\n startFrame: SCENES.push1.start,\n code: ` \\n`,\n highlight: \"spatial-push\",\n },\n {\n startFrame: SCENES.dashboard.start,\n code: ` \\n`,\n },\n {\n startFrame: SCENES.glassWipe.start,\n code: ` \\n`,\n highlight: \"glass-wipe\",\n },\n {\n startFrame: SCENES.maskedSlide.start,\n code: ` \\n`,\n },\n {\n startFrame: SCENES.push2.start,\n code: ` \\n`,\n highlight: \"spatial-push\",\n },\n {\n startFrame: SCENES.terminal.start,\n code: ` \\n`,\n },\n];\n\nconst CHARS_PER_FRAME = 2.2;\n\ninterface BuiltStep extends CodeStep {\n endFrame: number;\n}\n\nconst BUILT_STEPS: BuiltStep[] = STEPS.map((s) => ({\n ...s,\n endFrame: s.startFrame + Math.ceil(s.code.length / CHARS_PER_FRAME),\n}));\n\n/* -------------------------------------------------------------------------- */\n/* Syntax highlight */\n/* -------------------------------------------------------------------------- */\n\ninterface Token {\n text: string;\n color: string;\n glow?: boolean;\n}\n\nfunction tokenizeLine(\n line: string,\n accentColor: string,\n highlightedToken: string | null,\n): Token[] {\n const tokens: Token[] = [];\n const regex =\n /(\\bimport\\b|\\bfrom\\b|\\bexport\\b|\\bdefault\\b|\\bfunction\\b|\\breturn\\b|\\bconst\\b)|(\"[^\"]*\")|(\\b[A-Z][a-zA-Z0-9_]*)|(\\b[a-zA-Z_][a-zA-Z0-9_]*)(?==)|(\\{|\\}|\\(|\\)|<|>|\\/|;)|([0-9]+)/g;\n let lastIndex = 0;\n let m: RegExpExecArray | null = regex.exec(line);\n while (m !== null) {\n if (m.index > lastIndex) {\n tokens.push({\n text: line.slice(lastIndex, m.index),\n color: \"#e4e4e7\",\n });\n }\n if (m[1]) tokens.push({ text: m[1], color: LAVENDER });\n else if (m[2]) {\n // String literal — check if it matches the active highlight\n const inner = m[2].slice(1, -1);\n if (highlightedToken && inner === highlightedToken) {\n tokens.push({ text: m[2], color: LAVENDER, glow: true });\n } else {\n tokens.push({ text: m[2], color: MINT });\n }\n } else if (m[3]) tokens.push({ text: m[3], color: PEACH });\n else if (m[4]) tokens.push({ text: m[4], color: accentColor });\n else if (m[5]) tokens.push({ text: m[5], color: \"#71717a\" });\n else if (m[6]) tokens.push({ text: m[6], color: \"#fbbf24\" });\n lastIndex = regex.lastIndex;\n m = regex.exec(line);\n }\n if (lastIndex < line.length) {\n tokens.push({ text: line.slice(lastIndex), color: \"#e4e4e7\" });\n }\n return tokens;\n}\n\n/* -------------------------------------------------------------------------- */\n/* Code editor */\n/* -------------------------------------------------------------------------- */\n\nfunction CodeEditor({\n frame,\n accentColor,\n}: {\n frame: number;\n accentColor: string;\n}) {\n // Compose the visible code: header + per-step typed amounts + footer (only when fully typed)\n const dynamicChunks: string[] = [];\n let activeHighlight: string | null = null;\n\n for (const step of BUILT_STEPS) {\n if (frame < step.startFrame) break;\n const elapsed = frame - step.startFrame;\n const charsTyped = Math.min(\n step.code.length,\n Math.floor(elapsed * CHARS_PER_FRAME),\n );\n dynamicChunks.push(step.code.slice(0, charsTyped));\n\n // Lavender pulse: active for ~24 frames after fragment finishes typing\n if (step.highlight) {\n const sinceStart = frame - step.startFrame;\n if (sinceStart >= 0 && sinceStart < 60) {\n activeHighlight = step.highlight;\n }\n }\n }\n\n const allTyped = dynamicChunks.join(\"\");\n const lastStep = BUILT_STEPS[BUILT_STEPS.length - 1];\n const showFooter = frame > lastStep.endFrame + 4;\n const visibleCode = HEADER + allTyped + (showFooter ? FOOTER : \"\");\n const lines = visibleCode.split(\"\\n\");\n const lastLineIdx = lines.length - 1;\n const caretOn = Math.floor(frame / 12) % 2 === 0;\n\n return (\n \n \n {/* Title bar */}\n \n {[\"#ff5f57\", \"#febc2e\", \"#28c840\"].map((c) => (\n \n ))}\n \n scene.tsx\n \n \n\n {/* Code body */}\n \n {lines.map((line, i) => {\n const tokens = tokenizeLine(line, accentColor, activeHighlight);\n const isLast = i === lastLineIdx;\n return (\n \n \n {i + 1}\n \n \n {tokens.length === 0 ? (\n \n ) : (\n tokens.map((t, j) => (\n \n {t.text}\n \n ))\n )}\n {isLast && caretOn && (\n \n )}\n \n \n );\n })}\n \n \n \n );\n}\n\n/* -------------------------------------------------------------------------- */\n/* Soft pastel scene wrappers */\n/* -------------------------------------------------------------------------- */\n\n/** Warm pastel canvas — the dark stage every scene sits on */\nfunction PastelStage({\n background = STAGE_BG,\n children,\n}: {\n background?: string;\n children: ReactNode;\n}) {\n return (\n \n \n {children}\n \n );\n}\n\n/* -------------------------------------------------------------------------- */\n/* Scene factories */\n/* -------------------------------------------------------------------------- */\n/*\n Note: BlurReveal and MaskedSlideReveal primitives bake in a `background:\n white` div. To keep the warm-dark stage we re-implement just the visual\n here (not a fork — both effects are simple text + filter). The orchestrator\n advertises the primitives in code; the rendered output is faithful to them.\n*/\n\nfunction BlurRevealScene() {\n const frame = useCurrentFrame();\n const opacity = interpolate(frame, [0, 50], [0, 1], {\n extrapolateRight: \"clamp\",\n });\n const blurAmount = interpolate(frame, [0, 50], [22, 0], {\n extrapolateRight: \"clamp\",\n });\n return (\n \n \n Build faster.\n \n \n );\n}\n\nfunction DashboardScene() {\n return (\n
\n \n
\n );\n}\n\nfunction MaskedSlideScene() {\n const frame = useCurrentFrame();\n const { fps } = useVideoConfig();\n const words = \"Ship to production.\".split(\" \");\n return (\n \n \n {words.map((word, i) => {\n const t = spring({\n frame: frame - i * 4,\n fps,\n config: { damping: 18, stiffness: 120 },\n });\n return (\n \n \n {word}\n \n \n );\n })}\n \n \n );\n}\n\nfunction TerminalScene() {\n return (\n
\n \n
\n );\n}\n\n/* -------------------------------------------------------------------------- */\n/* Right pane */\n/* -------------------------------------------------------------------------- */\n\nfunction RightPane() {\n return (\n \n {/* ── BASE LAYER: each scene runs in its own Sequence so its\n internal useCurrentFrame() starts at 0 within the window. ── */}\n\n \n \n \n \n \n\n \n \n \n \n \n\n \n \n \n \n \n\n \n \n \n \n \n\n {/* ── TRANSITION OVERLAYS: each one displays the previous scene's\n end-state (Freeze) while wiping in the next scene's start-state. ── */}\n\n \n \n \n \n \n \n }\n to={\n \n \n \n \n \n }\n />\n \n\n \n \n \n \n \n \n }\n to={\n \n \n \n \n \n }\n />\n \n\n \n \n \n \n \n \n }\n to={\n \n \n \n \n \n }\n />\n \n \n );\n}\n\n/* -------------------------------------------------------------------------- */\n/* Main */\n/* -------------------------------------------------------------------------- */\n\nexport function LandingCodeShowcase({\n accentColor = \"#FFB38E\",\n speed = 1,\n}: LandingCodeShowcaseProps) {\n const rawFrame = useCurrentFrame();\n const frame = rawFrame * speed;\n\n /* ---- Final \"deploy success\" glow on both panes ---- */\n const successGlow = interpolate(\n frame,\n [SCENES.terminal.start + 70, SCENES.terminal.start + 100],\n [0, 1],\n { extrapolateLeft: \"clamp\", extrapolateRight: \"clamp\" },\n );\n\n return (\n \n {/* Backdrop wash */}\n \n\n {/* ---------------- LEFT: code editor ---------------- */}\n \n \n \n\n {/* ---------------- RIGHT: live preview ---------------- */}\n \n {/* Preview label */}\n \n \n \n Preview · HMR\n \n \n\n \n \n \n \n \n );\n}\n\n// Re-export the schedule so config.ts (or callers) can read the canonical\n// total length without duplicating constants.\nexport const LANDING_CODE_SHOWCASE_DURATION = TOTAL_DURATION;\n", "type": "registry:component", "target": "components/remocn/landing-code-showcase.tsx" } ], "type": "registry:component" }