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/shieldcnRender 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=angleThe prompt
Reconstructed draftA 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.