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-remocnRender 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=angleThe prompt
Reconstructed draftA 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, Img, Sequence, Series, interpolate, 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/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 real brand asset from remocn.dev/logo.svg,
// downloaded to public/remocn-logo.svg.
// ===========================================================================
const RemocnMark: React.FC<{ size: number }> = ({ size }) => (
<Img
src={demoAsset("remocn-logo.svg")}
style={{ width: size, height: size, display: "block" }}
/>
);
// 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",
];
const CMD_START = 10;
const FLIP_START = 56; // first flip, after the typed command has settled
const FLIP_PER = 24; // one name every 24 frames
const FLIP_DUR = 10; // the 3D flip itself
const InstallCmdScene: React.FC = () => {
const frame = useCurrentFrame();
const full = CMD + PKG_NAMES[0];
const typed = Math.max(
0,
Math.min(full.length, Math.floor((frame - CMD_START) * 1.5)),
);
const visible = full.slice(0, typed);
const cmdOpacity = interpolate(
frame,
[CMD_START - 4, CMD_START],
[0, 1],
clampOpts,
);
const typingDone = typed >= full.length;
const caretOn = typingDone ? Math.floor(frame / 15) % 2 === 0 : true;Showing the first 400 of 858 lines. View the full file on GitHub.