All demos

remocn — Introducing remocn (shaders cut)

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-remocn

Render it locally

Renders the MP4 on your machine with the Remotion CLI.

$ pnpm dlx remotion render introducing-remocn out/introducing-remocn.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.

Build the first introduction video for remocn's own X account, and make it entirely out of remocn's own shaders and typography — nothing borrowed. Use the shipped brand: Manrope, warm obsidian background, a single lime accent, one quiet noise field running underneath the whole thing. Do a before/after/bridge arc — a couple of pain lines, a shader-swirl cover that winds open into "Meet remocn", the tagline "Cinematic video components for React", then "Like shadcn/ui, for video" building in kinetically. Hard-cut through six of our shader categories fullscreen (mesh-gradient, warp, voronoi, metaballs, god-rays, color-panels type stuff) as pure spectacle, then a short value block (110+ components, one command, code is yours), the install command typing itself, and a smoke-ring outro that assembles the remocn mark and remocn.dev.

The code

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

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

import { ScaleDownFade } from "@/components/remocn/scale-down-fade";
import { ShortSlideRight } from "@/components/remocn/short-slide-right";
import { KineticCenterBuild } from "@/components/remocn/kinetic-center-build";
import { LineByLineSlide } from "@/components/remocn/line-by-line-slide";

import { ShaderSimplexNoise } from "@/components/remocn/shader-simplex-noise";
import { ShaderSwirl } from "@/components/remocn/shader-swirl";
import { ShaderDithering } from "@/components/remocn/shader-dithering";
import { ShaderColorPanels } from "@/components/remocn/shader-color-panels";
import { ShaderWarp } from "@/components/remocn/shader-warp";
import { ShaderMeshGradient } from "@/components/remocn/shader-mesh-gradient";
import { ShaderVoronoi } from "@/components/remocn/shader-voronoi";
import { ShaderMetaballs } from "@/components/remocn/shader-metaballs";
import { ShaderGodRays } from "@/components/remocn/shader-god-rays";
import { ShaderSmokeRing } from "@/components/remocn/shader-smoke-ring";

// Bind Manrope to the CSS variable the remocn typography components read.
const { fontFamily: SANS_FAMILY } = loadSans("normal", {
  subsets: ["latin"],
  weights: ["400", "500", "600", "700", "800"],
});
const { fontFamily: MONO_FAMILY } = loadMono("normal", {
  subsets: ["latin"],
  weights: ["400", "500"],
});

const SANS =
  "var(--font-geist-sans), -apple-system, BlinkMacSystemFont, sans-serif";
const MONO = `${MONO_FAMILY}, ui-monospace, SFMono-Regular, monospace`;

// The shipped remocn.dev brand: warm obsidian + one lime accent.
const OBSIDIAN = "#141318";
const INK = "#f2f2f2";
const MUTED = "rgba(242,242,242,0.62)";
const FAINT = "rgba(242,242,242,0.4)";
const LIME = "#C3E88D";

const clampOpts = {
  extrapolateLeft: "clamp" as const,
  extrapolateRight: "clamp" as const,
};

// ---------------------------------------------------------------------------
// Scene timings (frames @ 30fps). Transitions overlap.
// Shader covers run fade-in (12f) → opaque hold (~500ms) → fade-out, so the
// shader itself gets read as a moment, not a flash.
// ---------------------------------------------------------------------------
const S_PAIN = 208; //     two scale-down-fade pain lines + room for the swirl
const S_MEET = 150; //     "Meet Remocn"
const S_TAGLINE = 76; //   "Cinematic video components for React"
const S_POS = 96; //       kinetic "Like shadcn/ui, for video"
const REG_BEAT = 26; //    one fullscreen shader per hard cut
const S_VALUE = 104; //    three value lines
const S_INSTALL_TITLE = 70; // "It lands in your repo"
const S_INSTALL_CMD = 176; //  typed command + 3D name rolodex
const S_OUTRO = 150; //    smoke ring blooms → mark + wordmark + url

// Paced like the paper-shaders OutroScene: unwind ~34f, hold ~22f, wind ~38f.
const T_SWIRL = 104; //    shader-swirl cover (twist 1→0 → hold → 0→1)
const T_DITHER = 40; //    lime dither dissolve (held mid-frame)
const T_X = 14; //         crossfade
const T_BLUR = 16; //      blur crossfade

// ===========================================================================
// The remocn mark — the R letterform from remocn.dev/logo-mark.svg, inlined
// so the outro can draw it on: `draw` runs the outline (pathLength-normalized
// dashoffset), `fill` lets the solid letter catch up behind it.
// ===========================================================================
const MARK_VIEWBOX = "0 0 124.06 134.26";
const MARK_RATIO = 124.06 / 134.26;
const MARK_PATH =
  "M 0.01 0.81 C 0.01 1.73, 0.36 2.79, 1.09 4.13 C 4.91 11.04, 13.45 17.16, 21.7 18.9 C 22.94 19.16, 23.18 19.16, 51.39 19.27 C 76.07 19.36, 80.02 19.4, 81.32 19.57 C 89.89 20.69, 96.2 24.68, 99.38 31.01 C 103.19 38.56, 102.53 50.1, 97.91 57.07 C 94.66 61.96, 89.68 64.99, 83.26 66 C 82.81 66.07, 70.18 66.83, 55.2 67.69 C 24.82 69.43, 27.03 69.23, 24.18 70.4 C 19.9 72.15, 14.84 75.7, 10.65 79.89 C 4.86 85.68, 1.3 91.91, 0.25 98.13 C 0.12 98.85, 0.08 103.13, 0.04 116.66 L 0 134.26 9.5 134.26 L 19 134.26 19.05 119.41 C 19.1 103.27, 19.08 103.82, 19.82 101.04 C 21.79 93.65, 27.86 88.75, 36.45 87.63 C 37.23 87.53, 39.41 87.5, 43.57 87.53 C 50.12 87.59, 50.75 87.65, 53.22 88.45 C 56.61 89.56, 59.67 91.86, 62.02 95.07 C 62.52 95.76, 69.35 103.85, 77.2 113.07 C 85.04 122.28, 91.63 130.04, 91.85 130.32 C 92.07 130.59, 92.5 131.34, 92.82 131.97 C 93.52 133.35, 94.11 133.93, 95.06 134.13 C 95.5 134.23, 98.97 134.26, 106.36 134.23 L 117.01 134.19 100.82 113.07 C 91.91 101.45, 84.52 91.78, 84.39 91.57 C 83.36 89.89, 83.66 87.53, 85.09 86 C 85.79 85.25, 86.36 84.94, 88.07 84.38 C 96.18 81.72, 104.15 76.62, 109.97 70.36 C 120.59 58.93, 124.06 44.32, 119.44 30.43 C 114.59 15.81, 101.93 4.02, 87.64 0.83 C 83.93 0.01, 88.09 0.08, 41.85 0.04 L 0.01 0 0.01 0.81 Z";

const RemocnMark: React.FC<{ size: number; draw?: number; fill?: number }> = ({
  size,
  draw = 1,
  fill = 1,
}) => (
  <svg
    viewBox={MARK_VIEWBOX}
    width={size * MARK_RATIO}
    height={size}
    style={{ display: "block", color: INK, overflow: "visible" }}
  >
    <path
      d={MARK_PATH}
      pathLength={1}
      fill="currentColor"
      fillOpacity={fill}
      stroke="currentColor"
      strokeWidth={2}
      strokeLinejoin="round"
      strokeDasharray={1}
      strokeDashoffset={1 - draw}
    />
  </svg>
);

// Readability scrim over a backdrop shader.
const Scrim: React.FC<{ strength?: number }> = ({ strength = 1 }) => (
  <AbsoluteFill
    style={{
      background: `radial-gradient(120% 120% at 50% 42%, rgba(20,19,24,${
        0.3 * strength
      }) 0%, rgba(20,19,24,${0.78 * strength}) 100%)`,
    }}
  />
);

// ===========================================================================
// Scene 1 — Pain. Two lines land solo on the shared backdrop.
// ===========================================================================
const PainScene: React.FC = () => (
  <AbsoluteFill>
    <Sequence durationInFrames={60}>
      <ScaleDownFade
        text="Every launch needs a video"
        fontSize={54}
        fontWeight={400}
        color={INK}
      />
    </Sequence>
    <Sequence from={60} durationInFrames={60}>
      <ScaleDownFade
        text="Yours shouldn't take a week"
        fontSize={54}
        fontWeight={400}
        color={INK}
      />
    </Sequence>
  </AbsoluteFill>
);

// ===========================================================================
// Scene 2 — Meet Remocn. The text itself is static on entry (the swirl
// cover's exit reveals it with a z-axis scale), then it plays its own exit —
// fading up and out — so the tagline never overlaps it.
// ===========================================================================
const MeetScene: React.FC = () => {
  const frame = useCurrentFrame();
  const { durationInFrames } = useVideoConfig();

  const exitP = interpolate(
    frame,
    [durationInFrames - 18, durationInFrames - 2],
    [0, 1],
    { ...clampOpts, easing: Easing.in(Easing.cubic) },
  );

  return (
    <AbsoluteFill style={{ alignItems: "center", justifyContent: "center" }}>
      <span
        style={{
          fontFamily: SANS,
          fontWeight: 400,
          fontSize: 76,
          letterSpacing: "-0.03em",
          color: INK,
          opacity: 1 - exitP,
          transform: `translateY(${exitP * -10}px) scale(${1 - exitP * 0.05})`,
          filter: `blur(${exitP * 6}px)`,
        }}
      >
        Meet Remocn
      </span>
    </AbsoluteFill>
  );
};

// ===========================================================================
// Scene 3 — Tagline. Enters via short-slide-right only after Meet Remocn
// has fully exited (hard cut between the scenes, no overlap).
// ===========================================================================
const TaglineScene: React.FC = () => (
  <AbsoluteFill>
    <ShortSlideRight
      text="Cinematic video components for React"
      fontSize={48}
      fontWeight={400}
      color={INK}
    />
  </AbsoluteFill>
);

// ===========================================================================
// Scene 4 — Positioning. The mental model assembles word by word.
// ===========================================================================
const PositioningScene: React.FC = () => (
  <AbsoluteFill>
    <Sequence from={24}>
      <KineticCenterBuild
        text="Like shadcn/ui, for video"
        fontSize={62}
        fontWeight={400}
        color={INK}
      />
    </Sequence>
  </AbsoluteFill>
);

// ===========================================================================
// Scene 5 — The registry montage. Six shaders hard-cut, one category each.
// ===========================================================================
type RegistryBeat = { label: string; node: React.ReactNode };

const REGISTRY_BEATS: RegistryBeat[] = [
  {
    label: "Text animations",
    node: (
      <ShaderColorPanels
        speed={2}
        colorBack={OBSIDIAN}
        colors={["#39364d", "#55506e", "#7d76a0", "#a49dcb"]}
        density={3}
        length={1.1}
      />
    ),
  },
  {
    label: "Transitions",
    node: (
      <ShaderWarp
        speed={2}
        colors={["#141318", "#2c2a38", "#5b5773", "#b9b4d6"]}
        swirl={0.6}
      />
    ),
  },
  {
    label: "Backgrounds",
    node: (
      <ShaderMeshGradient
        speed={2}
        colors={["#141318", "#2b2a3a", "#565170", "#8f88ae"]}
        distortion={0.8}
        swirl={0.2}
      />
    ),
  },
  {
    label: "UI blocks",
    node: (
      <ShaderVoronoi
        speed={2}
        colors={["#232130", "#3d3a52", "#6b6590", "#a9a2cf"]}
        colorGap="#0d0c10"
        glow={0.1}
      />
    ),
  },
  {
    label: "UI primitives",
    node: (
      <ShaderMetaballs
        speed={2}
        colorBack={OBSIDIAN}
        colors={["#4a4661", "#7d76a0", "#C3E88D", "#e6e2f5"]}
      />
    ),
  },
  {
    label: "Shaders",
    node: (
      <ShaderGodRays
        speed={2}
        colorBack="#0d0d10"
        colorBloom="#48522f"
        colors={["#C3E88D", "#e8f2d0", "#6a7550", "#39412a"]}
        intensity={0.9}
        bloom={0.5}
      />
    ),
  },
];

// The last beat carries the dither transition on top, so it gets its
// clean 26 frames back by absorbing the overlap.
const S_REGISTRY = REGISTRY_BEATS.length * REG_BEAT + T_DITHER;

const RegistryLabel: React.FC<{ label: string }> = ({ label }) => {
  const frame = useCurrentFrame();
  const opacity = interpolate(frame, [0, 7], [0, 1], clampOpts);
  const y = interpolate(frame, [0, 8], [10, 0], {
    ...clampOpts,
    easing: Easing.out(Easing.cubic),
  });
  const blur = interpolate(frame, [0, 7], [6, 0], clampOpts);
  return (
    <AbsoluteFill style={{ alignItems: "center", justifyContent: "center" }}>
      <span
        style={{
          fontFamily: SANS,
          fontWeight: 400,
          fontSize: 58,
          letterSpacing: "-0.03em",
          color: INK,
          opacity,
          transform: `translateY(${y}px)`,
          filter: `blur(${blur}px)`,
        }}
      >
        {label}
      </span>
    </AbsoluteFill>
  );
};

const RegistryScene: React.FC = () => (
  <AbsoluteFill style={{ background: OBSIDIAN }}>
    <Series>
      {REGISTRY_BEATS.map((beat, i) => (
        <Series.Sequence
          key={beat.label}
          durationInFrames={
            i === REGISTRY_BEATS.length - 1 ? REG_BEAT + T_DITHER : REG_BEAT
          }
        >
          <AbsoluteFill style={{ background: OBSIDIAN }}>
            {beat.node}
            <Scrim strength={0.7} />
            <RegistryLabel label={beat.label} />
          </AbsoluteFill>
        </Series.Sequence>
      ))}
    </Series>
  </AbsoluteFill>
);

// ===========================================================================
// Scene 6 — The numbers. Three claims accumulate as a block.
// ===========================================================================
const ValueScene: React.FC = () => (
  <AbsoluteFill>
    <Sequence from={24}>
      <LineByLineSlide
        text={"110+ components\nOne command to install\nThe code is yours"}
        fontSize={50}
        fontWeight={400}
        color={INK}
      />
    </Sequence>
  </AbsoluteFill>
);

// ===========================================================================
// Scene 7a — Install title. Its own typographic beat; plays its own exit so
// the command scene starts on an empty canvas.
// ===========================================================================
const InstallTitleScene: React.FC = () => {
  const frame = useCurrentFrame();
  const { durationInFrames } = useVideoConfig();

  const exitP = interpolate(
    frame,
    [durationInFrames - 18, durationInFrames - 2],
    [0, 1],
    { ...clampOpts, easing: Easing.in(Easing.cubic) },
  );

  return (
    <AbsoluteFill
      style={{
        opacity: 1 - exitP,
        transform: `translateY(${exitP * -10}px) scale(${1 - exitP * 0.05})`,
        filter: `blur(${exitP * 6}px)`,
      }}
    >
      <ShortSlideRight
        text="It lands in your repo"
        fontSize={50}
        fontWeight={400}
        color={INK}
      />
    </AbsoluteFill>
  );
};

// ===========================================================================
// Scene 7b — Install command. The command types itself; once typing lands,
// the package name becomes a 3D rolodex and flips through other registry
// components — any component, same command.
// ===========================================================================
const CMD = "npx shadcn add @remocn/";
const PKG_NAMES = [
  "kinetic-center-build",
  "per-character-rise",
  "shader-warp",
  "command-menu",
  "claude-chat",

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