Blockforge

Command Palette

Search for a command to run...

Documentation

Three ways to get a block into your project: copy-paste, the shadcn CLI, or your AI editor via MCP.

Requirements

Blocks are plain React + Tailwind. You need a project with React 19, Tailwind CSS v4 and shadcn/ui initialized (`npx shadcn init`). Every block is standalone TypeScript — no runtime, no wrapper library.

1. Copy-paste

Open any block in the catalog, switch to the Code tab, copy, paste. Free blocks are open; pro blocks unlock after signing in with your purchase email.

2. shadcn CLI

Every block installs through the @blockforge namespace — dependencies and ui components resolve automatically:

terminal
npx shadcn@latest add @blockforge/hero-centered

One-time setup: add the registry to your components.json — the token from your account (exported as BLOCKFORGE_TOKEN) unlocks the pro blocks; free blocks need no token:

components.json
{
  "registries": {
    "@blockforge": {
      "url": "https://blockforge.terravidhal.me/r/{name}.json",
      "headers": {
        "Authorization": "Bearer ${BLOCKFORGE_TOKEN}"
      }
    }
  }
}

Raw URLs work too, without any setup — handy for one-off installs of free blocks:

terminal
npx shadcn@latest add https://blockforge.terravidhal.me/r/hero-centered.json

3. MCP — for AI editors

Claude Code, Cursor and friends can search blocks, read source and install pages without leaving the editor.

Claude Code
claude mcp add --transport http blockforge https://blockforge.terravidhal.me/mcp
Full MCP guide: the seven tools, every editor, pro tokens

Theming

Every block uses semantic shadcn tokens only — bg-background, text-muted-foreground, border-border… Change your CSS variables once and every block follows, dark mode included. No hard-coded colors, anywhere.

CSS utilities

Some blocks use Blockforge's signature utilities (blueprint grids, marquee, orbit, border beam…). Installing via the shadcn CLI injects the needed ones automatically. If you copy-paste instead, append what you need from the full set below to your global CSS:

blockforge-utilities.css
@utility bg-grid-lg {
  background-image: linear-gradient(to right, color-mix(in oklab, var(--foreground) 9%, transparent) 1px, transparent 1px), linear-gradient(to bottom, color-mix(in oklab, var(--foreground) 9%, transparent) 1px, transparent 1px);
  background-size: 96px 96px;
}
@utility bg-grid-sm {
  background-image: linear-gradient(to right, color-mix(in oklab, var(--foreground) 4%, transparent) 1px, transparent 1px), linear-gradient(to bottom, color-mix(in oklab, var(--foreground) 4%, transparent) 1px, transparent 1px);
  background-size: 24px 24px;
}
@utility bg-dots {
  background-image: radial-gradient(circle, color-mix(in oklab, var(--foreground) 16%, transparent) 1px, transparent 1px);
  background-size: 14px 14px;
}
@utility bg-stripes {
  background-image: repeating-linear-gradient(-45deg, color-mix(in oklab, var(--foreground) 5%, transparent) 0 1px, transparent 1px 7px);
}
@utility animate-marquee {
  animation: marquee 32s linear infinite;
  @media (prefers-reduced-motion: reduce) {
    animation: none;
  }
}
@utility animate-marquee-reverse {
  animation: marquee 32s linear infinite reverse;
  @media (prefers-reduced-motion: reduce) {
    animation: none;
  }
}
@utility animate-caret {
  animation: caret-blink 1.1s steps(1) infinite;
  @media (prefers-reduced-motion: reduce) {
    animation: none;
  }
}
@utility animate-status {
  animation: status-pulse 2.4s ease-out infinite;
  @media (prefers-reduced-motion: reduce) {
    animation: none;
  }
}
@utility animate-orbit {
  animation: orbit 40s linear infinite;
  @media (prefers-reduced-motion: reduce) {
    animation: none;
  }
}
@utility animate-orbit-reverse {
  animation: orbit 40s linear infinite reverse;
  @media (prefers-reduced-motion: reduce) {
    animation: none;
  }
}
@utility animate-word-cycle {
  animation: word-cycle var(--cycle-duration, 8s) infinite;
  animation-delay: var(--cycle-delay, 0s);
  animation-fill-mode: both;
  @media (prefers-reduced-motion: reduce) {
    animation: none;
    opacity: 0;
    &:first-child {
      opacity: 1;
      transform: none;
    }
  }
}
@utility border-beam {
  position: relative;
  &::after {
    content: "";
    position: absolute;
    inset: -1px;
    border-radius: inherit;
    padding: 1px;
    background: conic-gradient(from var(--beam-angle), transparent 0deg 300deg, color-mix(in oklab, var(--foreground) 90%, transparent) 350deg, transparent 360deg);
    mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
    mask-composite: exclude;
    animation: beam-rotate 3.2s linear infinite;
    pointer-events: none;
  }
  @media (prefers-reduced-motion: reduce) {
    &::after {
      display: none;
    }
  }
}
@utility beam-hover {
  &::after {
    opacity: 0;
    transition: opacity 0.25s ease-out;
    animation-play-state: paused;
  }
  &:hover::after, &:focus-within::after {
    opacity: 1;
    animation-play-state: running;
  }
}
@utility flux-x {
  position: absolute;
  height: 1px;
  width: 9rem;
  background: linear-gradient(90deg, transparent, color-mix(in oklab, var(--foreground) 65%, transparent), transparent);
  animation: flux-x var(--flux-duration, 8s) linear infinite;
  animation-delay: var(--flux-delay, 0s);
}
@utility flux-y {
  position: absolute;
  width: 1px;
  height: 9rem;
  background: linear-gradient(180deg, transparent, color-mix(in oklab, var(--foreground) 65%, transparent), transparent);
  animation: flux-y var(--flux-duration, 9s) linear infinite;
  animation-delay: var(--flux-delay, 0s);
}
@keyframes marquee {
  to {
    transform: translateX(-50%);
  }
}
@keyframes caret-blink {
  50% {
    opacity: 0;
  }
}
@keyframes status-pulse {
  0% {
    box-shadow: 0 0 0 0 color-mix(in oklab, currentColor 45%, transparent);
  }
  70%, 100% {
    box-shadow: 0 0 0 6px transparent;
  }
}
@keyframes orbit {
  to {
    transform: rotate(360deg);
  }
}
@keyframes word-cycle {
  0%, 3% {
    transform: translateY(110%);
    opacity: 0;
  }
  7%, 24% {
    transform: translateY(0);
    opacity: 1;
  }
  29%, 100% {
    transform: translateY(-110%);
    opacity: 0;
  }
}
@property --beam-angle {
  syntax: "<angle>";
  initial-value: 0deg;
  inherits: false;
}
@keyframes beam-rotate {
  to {
    --beam-angle: 360deg;
  }
}
@keyframes flux-x {
  from {
    transform: translateX(-10rem);
  }
  to {
    transform: translateX(82rem);
  }
}
@keyframes flux-y {
  from {
    transform: translateY(-10rem);
  }
  to {
    transform: translateY(56rem);
  }
}