All demos

Vercel — Introducing Vercel

Install this video

Adds the full composition, its remocn dependencies, and the prompt to your Remotion project via the shadcn registry.

$ pnpm dlx shadcn@latest add kapishdima/remocn-demo/introducing-vercel

Render it locally

Renders the MP4 on your machine with the Remotion CLI.

$ pnpm dlx remotion render introducing-vercel out/introducing-vercel.mp4 --scale=2 --crf=15 --x264-preset=slower --jpeg-quality=95 --gl=angle

The prompt

Reconstructed draft

A reconstruction of the prompt this video was generated from.

The code

The exact source the AI wrote — the same files the install command puts in your project.

import React, { useMemo } from "react";
import {
  AbsoluteFill,
  Easing,
  Sequence,
  interpolate,
  spring,
  useCurrentFrame,
  useVideoConfig,
} from "remotion";
import {
  TransitionSeries,
  linearTiming,
  type TransitionPresentation,
  type TransitionPresentationComponentProps,
} from "@remotion/transitions";
import { fade } from "@remotion/transitions/fade";
import { loadFont as loadSans } from "@remotion/google-fonts/Geist";
import { loadFont as loadMono } from "@remotion/google-fonts/GeistMono";

import { ShaderGrainGradient } from "@/components/remocn/shader-grain-gradient";
import { ShaderGodRays } from "@/components/remocn/shader-god-rays";
import { ScaleDownFade } from "@/components/remocn/scale-down-fade";

import { trianglePortal } from "./triangle-portal";
import { seamlessZoom, type ZoomRect } from "./seamless-zoom";
import { PrismSpin } from "./prism-spin";

// Vercel speaks Geist: 400–600 for everything spoken, Geist Mono 400 only for
// shell commands and URLs-as-chrome.
const { fontFamily: SANS_FAMILY } = loadSans("normal", {
  subsets: ["latin"],
  weights: ["400", "500", "600"],
});
const { fontFamily: MONO_FAMILY } = loadMono("normal", {
  subsets: ["latin"],
  weights: ["400"],
});

const SANS = `${SANS_FAMILY}, -apple-system, BlinkMacSystemFont, sans-serif`;
const MONO = `${MONO_FAMILY}, ui-monospace, SFMono-Regular, monospace`;

// Register sampled from vercel.com + the official OG hero. The spec allows
// Vercel blue #0070f3 in at most two moments IF verifiable against their live
// design-system tokens — it was not verifiable at build time (only a hover
// #0B7BFE surfaces; token definitions aren't exposed), so per the spec's own
// fallback this cut ships fully monochrome.
const BG = "#000000";
const INK = "#ededed";
const BRIGHT = "#fafafa";
const MUTED = "#a1a1a1";
const CARD = "#111111";
const HAIRLINE = "rgba(237,237,237,0.14)";

const clampOpts = {
  extrapolateLeft: "clamp" as const,
  extrapolateRight: "clamp" as const,
};
const easeOut = Easing.out(Easing.cubic);
const easeSoft = Easing.bezier(0.2, 0.8, 0.2, 1);

// ---------------------------------------------------------------------------
// Scene timings (frames @ 30fps). ONE continuous camera flight — there are no
// hard cuts anywhere; every transition below is a camera move. The flight:
// eclipse → through the triangle (portal) → terminal → into the cursor
// (match-cut) → preview browser → into the favicon (portal) → edge field →
// pull-back onto a prism face → creed → the void carries two crossfades →
// drift back out to the eclipse we started at.
// ---------------------------------------------------------------------------
const S_ECLIPSE = 92; //   the OG hero rebuilt live + the pain line
const S_DEVELOP = 140; //  terminal alone in space, git push types itself
const S_PREVIEW = 146; //  browser card, preview URL, comment pin
const S_SHIP = 148; //     the page multiplying across the edge field
const S_CREED = 136; //    prism spin + Develop. Preview. Ship.
const S_AGENTS = 108; //   AI SDK / Sandbox / Gateway block
const S_PROOF = 112; //    Zapier + Notion receipts
const S_RETURN = 152; //   back at the eclipse; the lockup settles

const T_PORTAL_1 = 26; //  fly through the triangle
const T_CURSOR = 26; //    match-cut into the block cursor
const T_PORTAL_2 = 26; //  fly through the favicon
const T_PULLBACK = 28; //  the Ship world recedes onto its prism face
const T_FADE_1 = 16; //    the void is one world
const T_FADE_2 = 14;
const T_DRIFT = 30; //     the monolith was behind us all along

export const INTRODUCING_VERCEL_DURATION =
  S_ECLIPSE +
  S_DEVELOP +
  S_PREVIEW +
  S_SHIP +
  S_CREED +
  S_AGENTS +
  S_PROOF +
  S_RETURN -
  (T_PORTAL_1 +
    T_CURSOR +
    T_PORTAL_2 +
    T_PULLBACK +
    T_FADE_1 +
    T_FADE_2 +
    T_DRIFT);

// ---------------------------------------------------------------------------
// Shared flight geometry. The transitions ARE the camera moves, so the rects
// they dive into are named constants, not magic numbers.
// ---------------------------------------------------------------------------

// The terminal window (frame 2) and its block cursor after "git push ".
const TERM = { x: 190, y: 120, w: 900, h: 480, chrome: 40, pad: 24, fs: 22 };
const TERM_CHAR_W = TERM.fs * 0.6;
const TERM_LINE_H = 34;
const TERM_PROMPT = "$";
const TERM_CMD = "git push";
const CURSOR_W = TERM_CHAR_W;
const CURSOR_H = TERM.fs * 1.2;
const CURSOR_X =
  TERM.x +
  TERM.pad +
  (TERM_PROMPT.length + 1 + TERM_CMD.length) * TERM_CHAR_W +
  3;
const CURSOR_Y =
  TERM.y + TERM.chrome + TERM.pad + (TERM_LINE_H - CURSOR_H) / 2;
const CURSOR_RECT: ZoomRect = {
  x: CURSOR_X,
  y: CURSOR_Y,
  width: CURSOR_W,
  height: CURSOR_H,
};

// The browser card (frame 3): tab strip, address bar, then the light page —
// the page IS the surface the cursor match-cuts into, so they share a color.
const BROW = { x: 170, y: 64, w: 940, h: 530, tab: 36, address: 40 };
const PAGE_RECT: ZoomRect = {
  x: BROW.x,
  y: BROW.y + BROW.tab + BROW.address,
  width: BROW.w,
  height: BROW.h - BROW.tab - BROW.address,
};
const PAGE_BG = INK; // must equal the cursor ink for the invisible crossover
const FAVICON_CX = BROW.x + 8 + 14 + 7;
const FAVICON_CY = BROW.y + BROW.tab / 2;

// The prism (frame 5): the Ship world recedes onto its front face.
const PRISM_W = 520;
const PRISM_H = 300;
const PRISM_CX = 640;
const PRISM_CY = 302;

// ---------------------------------------------------------------------------
// Small shared pieces
// ---------------------------------------------------------------------------

// Barely-there push-in so no frame is ever static — the camera never rests.
const Drift: React.FC<{ children: React.ReactNode; grow?: number }> = ({
  children,
  grow = 0.03,
}) => {
  const frame = useCurrentFrame();
  const { durationInFrames } = useVideoConfig();
  const scale = interpolate(frame, [0, durationInFrames], [1, 1 + grow]);
  return (
    <AbsoluteFill style={{ transform: `scale(${scale})` }}>
      {children}
    </AbsoluteFill>
  );
};

// The narration line for a beat — words rise out of blur, muted, beneath the
// visual that acts them out.
const CaptionRise: React.FC<{
  text: string;
  y: number;
  delay?: number;
  fontSize?: number;
  color?: string;
}> = ({ text, y, delay = 0, fontSize = 26, color = MUTED }) => {
  const frame = useCurrentFrame();
  const words = text.split(" ");
  return (
    <div
      style={{
        position: "absolute",
        left: 0,
        right: 0,
        top: y,
        display: "flex",
        justifyContent: "center",
        whiteSpace: "pre",
      }}
    >
      <span
        style={{
          fontFamily: SANS,
          fontWeight: 400,
          fontSize,
          color,
          lineHeight: 1.3,
        }}
      >
        {words.map((word, i) => {
          const p = interpolate(frame - delay - i * 3, [0, 20], [0, 1], {
            ...clampOpts,
            easing: easeSoft,
          });
          return (
            <span
              key={i}
              style={{
                display: "inline-block",
                whiteSpace: "pre",
                opacity: p,
                transform: `translateY(${(1 - p) * 16}px)`,
                filter: p < 1 ? `blur(${(1 - p) * 6}px)` : undefined,
              }}
            >
              {word}
              {i < words.length - 1 ? " " : ""}
            </span>
          );
        })}
      </span>
    </div>
  );
};

// Odometer digits in Geist Mono — the register's own figures. Each column
// travels its own magnitude and lands EXACTLY on its final digit (the
// registry rolling-number math) — a naive `(current / pow) % 10` leaves
// higher columns resting between digits when the final value isn't a
// multiple of their place (38 would rest with its tens at 3.8).
const wrap10 = (v: number) => ((v % 10) + 10) % 10;

const RollDigits: React.FC<{
  from: number;
  to: number;
  progress: number;
  fontSize: number;
  color?: string;
}> = ({ from, to, progress, fontSize, color = BRIGHT }) => {
  const current = from + (to - from) * progress;
  const up = to >= from;
  const diff = Math.abs(to - from);
  const places = String(Math.max(1, Math.round(Math.max(from, to)))).length;
  const cellH = fontSize * 1.08;
  const cols: React.ReactNode[] = [];
  for (let place = places - 1; place >= 0; place--) {
    const pow = 10 ** place;
    const startDigit = Math.floor(from / pow) % 10;
    const finalDigit = Math.floor(to / pow) % 10;
    const fullTurns = Math.floor(diff / (pow * 10));
    const step = up
      ? (finalDigit - startDigit + 10) % 10
      : (startDigit - finalDigit + 10) % 10;
    const travel = (fullTurns * 10 + step) * (up ? 1 : -1);
    const pos = wrap10(startDigit + progress * travel);
    const reveal =
      place === 0
        ? 1
        : interpolate(current, [pow * 0.92, pow], [0, 1], clampOpts);
    cols.push(
      <span
        key={place}
        style={{
          display: "inline-block",
          overflow: "hidden",
          height: cellH,
          width: reveal > 0.02 ? "0.62em" : 0,
          opacity: reveal,
          verticalAlign: "bottom",
          textAlign: "center",
        }}
      >
        <span
          style={{
            display: "flex",
            flexDirection: "column",
            transform: `translateY(${-pos * cellH}px)`,
          }}
        >
          {[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0].map((d, i) => (
            <span key={i} style={{ height: cellH, lineHeight: `${cellH}px` }}>
              {d}
            </span>
          ))}
        </span>
      </span>,
    );
  }
  return (
    <span
      style={{
        display: "inline-flex",
        fontFamily: MONO,
        fontWeight: 400,
        fontSize,
        color,
        fontVariantNumeric: "tabular-nums",
        lineHeight: 1.08,
      }}
    >
      {cols}
    </span>
  );
};

// The ▲ — one SVG triangle, filled.
const Triangle: React.FC<{
  size: number;
  color: string;
  style?: React.CSSProperties;
}> = ({ size, color, style }) => (
  <svg
    width={size}
    height={size * 0.882}
    viewBox="0 0 100 88.2"
    style={{ display: "block", ...style }}
  >
    <path d="M50 0 L100 88.2 L0 88.2 Z" fill={color} />
  </svg>
);

// ---------------------------------------------------------------------------
// The eclipse — the OG hero rebuilt live from shaders: god-rays behind a
// black triangle occluder over the grain. The rim light exists ONLY behind
// the occluder (the sanctioned lighting event); type is never backlit.
// ---------------------------------------------------------------------------
const Eclipse: React.FC<{
  /** triangle height in px */
  size: number;
  cx: number;
  cy: number;
  raysOpacity: number;
  glow: number;
  scale?: number;
}> = ({ size, cx, cy, raysOpacity, glow, scale = 1 }) => {
  const w = size / 0.882;
  return (
    <>
      <AbsoluteFill style={{ opacity: raysOpacity }}>
        <ShaderGodRays
          speed={0.3}
          colorBack={BG}
          colorBloom="#26262b"
          colors={["#3c3c44", "#55555e", "#e9e9ee", "#2b2b31"]}
          intensity={0.6}
          density={0.26}
          bloom={0.42}
        />
        {/* Keep the light an edge event — pull the field back to black. */}
        <AbsoluteFill
          style={{
            background:
              "radial-gradient(90% 90% at 50% 50%, rgba(0,0,0,0.28) 0%, rgba(0,0,0,0.92) 74%)",
          }}
        />
      </AbsoluteFill>
      <div
        style={{
          position: "absolute",
          left: cx,
          top: cy,
          transform: `translate(-50%, -50%) scale(${scale})`,
        }}
      >
        {/* Rim light hugging the edges — a blurred white copy just behind. */}
        <div
          style={{
            position: "absolute",
            left: "50%",
            top: "50%",
            transform: "translate(-50%, -50%) scale(1.045)",
            filter: `blur(${Math.max(6, size * 0.055)}px)`,
            opacity: glow,
          }}
        >
          <Triangle size={w} color="#f3f3f5" />
        </div>
        <div
          style={{
            position: "relative",
            transform: "translate(0, 0)",
          }}
        >
          <Triangle size={w} color="#000000" />
        </div>
      </div>
    </>
  );
};

// ===========================================================================
// Frame 1 — The eclipse. Black void, film grain, the backlit triangle, and
// one line landing solo beneath it.
// ===========================================================================
const ECLIPSE_CY = 308;

const EclipseScene: React.FC = () => {
  const frame = useCurrentFrame();
  const raysIn = interpolate(frame, [0, 20], [0, 1], {

Showing the first 400 of 1821 lines. View the full file on GitHub.