All demos

shieldcn — Everything for your README

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/shieldcn

Render it locally

Renders the MP4 on your machine with the Remotion CLI.

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

Make a product demo for shieldcn — it's the shields.io alternative that turns README badges, charts, and headers into real shadcn/ui components. Use the shadcn zinc look plus their badge green as the accent, and run a before/after/bridge arc: open on "someone just opened your repo" and a wall of dated pixel badges as the pain, then introduce shieldcn with a self-drawing shield mark and the creed. Walk through the variants, sizes, and icons grid, show a live star-history chart along with header and sponsor-wall examples, and demo installing it as an agent skill in a terminal (npx skills add jal-co/shieldcn). Add proof pills for MIT and the Vercel OSS program plus a rolling star count past 500, and close on the shield-mark lockup with shieldcn.dev. Build it with remocn components.

The code

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

import React, { type ReactNode } from "react";
import { AbsoluteFill, Easing, Img, Sequence, Series, interpolate, interpolateColors, spring, useCurrentFrame, useVideoConfig } from "remotion";
import { demoAsset } from "@/lib/demo-assets";
import {
  TransitionSeries,
  linearTiming,
  type TransitionPresentation,
  type TransitionPresentationComponentProps,
} from "@remotion/transitions";
import { loadFont as loadSans } from "@remotion/google-fonts/Geist";
import { loadFont as loadMono } from "@remotion/google-fonts/GeistMono";

import { RemocnUIProvider } from "@/lib/remocn-ui";
import { ShortSlideRight } from "@/components/remocn/short-slide-right";
import { TerminalSimulator } from "@/components/remocn/terminal-simulator";
import {
  GitHubStars,
  type Stargazer,
} from "@/components/remocn/github-stars";
import { BlurIn } from "@/components/remocn/blur-in";
import { useBlurInTransition } from "@/components/remocn/use-blur-in-transition";
import { ShaderGrainGradient } from "@/components/remocn/shader-grain-gradient";
import { StarIcon } from "lucide-react";

// shieldcn speaks shadcn's language: Geist Sans for copy, Geist Mono for every
// URL and command.
const { fontFamily: SANS_FAMILY } = loadSans("normal", {
  subsets: ["latin"],
  weights: ["400", "500", "600", "700"],
});
const { fontFamily: MONO_FAMILY } = loadMono("normal", {
  subsets: ["latin"],
  weights: ["400", "500", "700"],
});

const SANS =
  "var(--font-geist-sans), -apple-system, BlinkMacSystemFont, sans-serif";
const MONO = "var(--font-geist-mono), ui-monospace, SFMono-Regular, monospace";

// shieldcn palette — the shadcn zinc register plus the one liberty the brand
// takes: badge-value green. The dated shields colors live ONLY in the pain beat.
const BG = "#09090b"; //      zinc-950 canvas
const INK = "#fafafa"; //     zinc-50 text
const MUTED = "#a1a1aa"; //   zinc-400
const FAINT = "rgba(250,250,250,0.45)";
const BORDER = "rgba(255,255,255,0.10)";
const CARD = "rgba(255,255,255,0.03)";
const GREEN = "#22c55e"; //   the badge-value green
const GREEN_SOFT = "#4ade80";

// ---------------------------------------------------------------------------
// Scene timings (frames @ 30fps), one per beat. Transitions overlap.
// ---------------------------------------------------------------------------
const S_HOOK = 120; //     stacked slide-in lines, README marker-highlighted
const S_PAIN = 120; //     counter-drifting marquee wall of dated badges
const S_INTRO = 185; //    Meet → shieldcn lockup → creed, on the shared Z axis
const S_TITLE = 55; //     interstitial section titles (short-slide-right)
const S_VARIANTS = 170; // ?variant= param morphs the live badge
const S_CHART = 140; //    spatial pan across chart / header / sponsor cards
const S_AGENT = 125; //    npx skills add jal-co/shieldcn
const S_PROOF = 120; //    stargazers card + proof pills
const S_CTA = 255; //      badge ballet (scatter → circle → spin → row → exit) + outro

const T_X = 14; //     crossfade
const T_SQ = 16; //    squeeze — snappy mechanical beat change
const T_ZOOM = 18; //  section turn (zoom-through)
const T_IRIS = 22; //  pill-shaped iris reveal

export const SHIELDCN_DURATION =
  S_HOOK +
  S_PAIN +
  S_INTRO +
  S_TITLE * 3 +
  S_VARIANTS +
  S_CHART +
  S_AGENT +
  S_PROOF +
  S_CTA -
  (T_SQ +
    T_IRIS +
    T_ZOOM +
    T_SQ +
    T_ZOOM +
    T_SQ +
    T_X +
    T_ZOOM +
    T_SQ +
    T_IRIS);

// ---------------------------------------------------------------------------
// Reveal — blur-in wrapper driven by useBlurInTransition.
// ---------------------------------------------------------------------------
const Reveal: React.FC<{
  children: ReactNode;
  delay?: number;
  distance?: number;
  blur?: number;
  duration?: number;
  display?: React.CSSProperties["display"];
}> = ({
  children,
  delay = 0,
  distance = 16,
  blur = 10,
  duration = 20,
  display = "block",
}) => {
  const style = useBlurInTransition(
    [{ at: delay, state: "revealed", duration }],
    { direction: "up", distance, blur },
  );
  return (
    <BlurIn style={style} display={display}>
      {children}
    </BlurIn>
  );
};

// ---------------------------------------------------------------------------
// SlideLine — a short-slide-right line stacked inside a flex column.
// SlideRich — the same motion for rich content (marker highlights etc.).
// ---------------------------------------------------------------------------
const SlideLine: React.FC<{
  text: string;
  at: number;
  fontSize: number;
  color?: string;
  fontWeight?: number;
}> = ({ text, at, fontSize, color = INK, fontWeight = 600 }) => (
  <div
    style={{
      position: "relative",
      width: "100%",
      height: Math.round(fontSize * 1.35),
    }}
  >
    <Sequence from={at} layout="none">
      <ShortSlideRight
        text={text}
        fontSize={fontSize}
        color={color}
        fontWeight={fontWeight}
      />
    </Sequence>
  </div>
);

const SlideRich: React.FC<{ at: number; children: ReactNode }> = ({
  at,
  children,
}) => {
  const frame = useCurrentFrame();
  const easing = Easing.bezier(0.2, 0.8, 0.2, 1);
  const t = frame - at;
  const x = interpolate(t, [0, 16], [-24, 0], {
    extrapolateLeft: "clamp",
    extrapolateRight: "clamp",
    easing,
  });
  const opacity = interpolate(t, [0, 10], [0, 1], {
    extrapolateLeft: "clamp",
    extrapolateRight: "clamp",
    easing,
  });
  const blurVal = interpolate(t, [0, 16], [1.2, 0], {
    extrapolateLeft: "clamp",
    extrapolateRight: "clamp",
    easing,
  });
  return (
    <div
      style={{
        transform: `translateX(${x}px)`,
        opacity,
        filter: `blur(${blurVal}px)`,
      }}
    >
      {children}
    </div>
  );
};

// ---------------------------------------------------------------------------
// Mark — a green marker sweep behind a phrase; the text flips dark.
// ---------------------------------------------------------------------------
const Mark: React.FC<{ children: string; startFrame?: number }> = ({
  children,
  startFrame = 8,
}) => {
  const frame = useCurrentFrame();
  const { fps } = useVideoConfig();
  const scaleX = spring({
    frame: frame - startFrame,
    fps,
    config: { damping: 15, mass: 0.8 },
  });
  const textColor = interpolateColors(
    interpolate(scaleX, [0.45, 0.85], [0, 1], {
      extrapolateLeft: "clamp",
      extrapolateRight: "clamp",
    }),
    [0, 1],
    [INK, "#052e16"],
  );
  return (
    <span
      style={{
        position: "relative",
        display: "inline-block",
        whiteSpace: "nowrap",
      }}
    >
      <span
        aria-hidden
        style={{
          position: "absolute",
          inset: "-0.04em -0.14em",
          background: GREEN,
          borderRadius: 8,
          transformOrigin: "left center",
          transform: `scaleX(${scaleX})`,
          zIndex: 0,
        }}
      />
      <span style={{ position: "relative", zIndex: 1, color: textColor }}>
        {children}
      </span>
    </span>
  );
};

// ---------------------------------------------------------------------------
// SectionTitle — the block headline as its own interstitial beat: the line
// slides in, then a green rule draws itself underneath.
// ---------------------------------------------------------------------------
const SectionTitle: React.FC<{ text: string }> = ({ text }) => {
  const frame = useCurrentFrame();
  const off = interpolate(frame, [12, 30], [1, 0], {
    extrapolateLeft: "clamp",
    extrapolateRight: "clamp",
    easing: Easing.inOut(Easing.cubic),
  });
  return (
    <AbsoluteFill
      style={{
        alignItems: "center",
        justifyContent: "center",
        flexDirection: "column",
        gap: 18,
      }}
    >
      <div style={{ position: "relative", width: "100%", height: 74 }}>
        <ShortSlideRight
          text={text}
          fontSize={54}
          color={INK}
          fontWeight={600}
        />
      </div>
      <svg width={190} height={6} viewBox="0 0 190 6">
        <path
          d="M3 3 H187"
          pathLength={1}
          strokeDasharray={1}
          strokeDashoffset={off}
          stroke={GREEN}
          strokeWidth={3.5}
          strokeLinecap="round"
          fill="none"
        />
      </svg>
    </AbsoluteFill>
  );
};

// ---------------------------------------------------------------------------
// SazSwap — shared-axis-z motion (same curves as the remocn component) for
// arbitrary ReactNode content: outgoing scales up + fades, incoming scales in.
// ---------------------------------------------------------------------------
const SazSwap: React.FC<{
  from?: ReactNode;
  to: ReactNode;
  align?: "center" | "start";
}> = ({ from, to, align = "center" }) => {
  const frame = useCurrentFrame();
  const exitDur = 11;
  const enterDur = 16;
  const newStart = Math.max(0, exitDur - 3 + 1);
  const exitEasing = Easing.bezier(0.4, 0, 1, 1);
  const enterEasing = Easing.bezier(0.2, 0, 0, 1);

  const fromOpacity = interpolate(frame, [0, exitDur], [1, 0], {
    extrapolateLeft: "clamp",
    extrapolateRight: "clamp",
    easing: exitEasing,
  });
  const fromScale = interpolate(frame, [0, exitDur], [1, 1.06], {
    extrapolateLeft: "clamp",
    extrapolateRight: "clamp",
    easing: exitEasing,
  });
  const fromBlur = interpolate(frame, [0, exitDur], [0, 1], {
    extrapolateLeft: "clamp",
    extrapolateRight: "clamp",
    easing: exitEasing,
  });

  const local = frame - newStart;
  const toOpacity = interpolate(local, [0, enterDur], [0, 1], {
    extrapolateLeft: "clamp",
    extrapolateRight: "clamp",
    easing: enterEasing,
  });
  const toScale = interpolate(local, [0, enterDur], [0.9, 1], {
    extrapolateLeft: "clamp",
    extrapolateRight: "clamp",
    easing: enterEasing,
  });
  const toBlur = interpolate(local, [0, enterDur], [2, 0], {
    extrapolateLeft: "clamp",
    extrapolateRight: "clamp",
    easing: enterEasing,
  });

  // AbsoluteFill is a flex COLUMN — alignItems is the horizontal axis.
  const center: React.CSSProperties = {
    alignItems: align === "center" ? "center" : "flex-start",
    justifyContent: "center",
  };
  return (
    <AbsoluteFill>
      {from && (
        <AbsoluteFill
          style={{
            ...center,
            opacity: fromOpacity,
            transform: `scale(${fromScale})`,
            filter: `blur(${fromBlur}px)`,
          }}
        >
          {from}
        </AbsoluteFill>
      )}
      <AbsoluteFill
        style={{
          ...center,
          opacity: toOpacity,
          transform: `scale(${toScale})`,
          filter: `blur(${toBlur}px)`,
        }}
      >
        {to}
      </AbsoluteFill>
    </AbsoluteFill>
  );
};

// ---------------------------------------------------------------------------
// Badge — a shieldcn badge rendered the way the product renders it: as a real
// shadcn button. Split form carries a label segment and a green value segment.
// ---------------------------------------------------------------------------
type BadgeVariant =
  | "default"
  | "secondary"
  | "outline"
  | "ghost"
  | "destructive";
type BadgeSize = "xs" | "sm" | "default" | "lg";

const SIZE_STYLE: Record<
  BadgeSize,
  { height: number; fontSize: number; padX: number }
> = {
  xs: { height: 26, fontSize: 12.5, padX: 10 },
  sm: { height: 32, fontSize: 14, padX: 13 },
  default: { height: 38, fontSize: 15.5, padX: 16 },
  lg: { height: 46, fontSize: 18, padX: 20 },
};

const VARIANT_STYLE: Record<BadgeVariant, React.CSSProperties> = {
  default: { background: INK, color: "#09090b" },
  secondary: { background: "#27272a", color: INK },
  outline: {
    background: "transparent",
    color: INK,
    boxShadow: `inset 0 0 0 1px rgba(255,255,255,0.22)`,
  },
  ghost: { background: "transparent", color: MUTED },
  destructive: { background: "#dc2626", color: INK },
};

const Badge: React.FC<{
  children: ReactNode;
  variant?: BadgeVariant;
  size?: BadgeSize;
}> = ({ children, variant = "secondary", size = "default" }) => {
  const s = SIZE_STYLE[size];
  return (
    <span
      style={{

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