Sanjay Kumar

Shape

Component 14

About

One shape studio: twelve compatible living contours, layered artwork and the complete original mask inventory. Compose it here, then take the SVG or React code.

Built with React and Tailwind. Copy the prompt and paste it into Claude Code, Cursor or Lovable: your agent adds Shape to your project and fits it to your theme.

Code

How Shape is used: the demo's code. The component's own source comes with a free account.

Usage.tsx

"use client";

import * as React from "react";
import { ShapeMorph, signatureShapeNames, type SignatureShapeName } from "@/components/ui/shape";

const tones = ["var(--v-pink)", "var(--v-yellow)", "var(--v-olive)", "var(--v-blue)"];

/** The demo brings its own 000h canvas, so it looks right on any host page (the component package sets nothing global). */
function DemoSurface({ children }: { children: import("react").ReactNode }) {
  return <div className="grid min-h-screen w-full place-items-center bg-[var(--v-canvas)] p-4 font-[family-name:var(--font-text)] text-[length:var(--fs-body)] leading-[var(--lh-body)] text-[var(--v-text)]">{children}</div>;
}

export default function Demo() {
  const [name, setName] = React.useState<SignatureShapeName>("daisy-12");
  const [variant, setVariant] = React.useState<"fill" | "outline">("fill");
  const tone = tones[Math.max(0, signatureShapeNames.indexOf(name)) % tones.length];
  return (
    <DemoSurface>
      <div className="mx-auto grid w-full max-w-3xl items-center gap-8 p-8 sm:grid-cols-[minmax(0,1fr)_minmax(0,1.2fr)]">
        <div className="mx-auto aspect-square w-full max-w-60" style={{ color: tone }}>
          <ShapeMorph name={name} variant={variant} label={`${name} silhouette`} className="h-full w-full overflow-visible" />
        </div>
        <div className="grid gap-4">
          <p className="text-sm text-[var(--v-text-2)]">Twelve fixed-topology silhouettes. Choosing another one retargets the visible path, so the shape morphs instead of swapping.</p>
          <div role="group" aria-label="Shape" className="grid grid-cols-4 gap-2">
            {signatureShapeNames.map((option, index) => (
              <button
                key={option}
                type="button"
                aria-pressed={name === option}
                aria-label={option}
                onClick={() => setName(option)}
                className="grid aspect-square place-items-center rounded-2xl border border-[var(--v-border)] bg-[var(--v-paper)] p-2 transition-colors hover:bg-[var(--v-beige)] aria-pressed:border-[var(--v-ink)] aria-pressed:bg-[var(--v-beige)]"
                style={{ color: tones[index % tones.length] }}
              >
                <ShapeMorph name={option} variant="fill" className="h-full w-full overflow-visible" />
              </button>
            ))}
          </div>
          <div role="group" aria-label="Treatment" className="flex gap-2">
            {(["fill", "outline"] as const).map((option) => (
              <button
                key={option}
                type="button"
                aria-pressed={variant === option}
                onClick={() => setVariant(option)}
                className="rounded-full border border-[var(--v-border)] bg-[var(--v-paper)] px-4 py-2 text-sm font-medium capitalize text-[var(--v-text)] transition-colors hover:bg-[var(--v-beige)] aria-pressed:border-[var(--v-ink)] aria-pressed:bg-[var(--v-ink)] aria-pressed:text-[var(--v-on-ink)]"
              >
                {option}
              </button>
            ))}
          </div>
        </div>
      </div>
    </DemoSurface>
  );
}

Dependencies

More by Sanjay Kumar

View all
  • Prompt Bond

    Prompt Bond

    95
  • Agent State

    Agent State

    47
  • Bento Grid

    Bento Grid

    34
  • Theme Toggle

    Theme Toggle

    23
  • Variable Proximity

    Variable Proximity

    18
  • Dock

    Dock

    15
  • Meta Balls

    Meta Balls

    12
  • Animated Icon

    Animated Icon

    11

Explore more

Part of 000h — browse the full library on 21st.dev.