Skip to content
Motion
FreeIn reviewv1.0.0

Kinetic Type Hero

Poster-size type that rises word by word on load, with the photo in a corner or set wide beneath.

npx shadcn@latest add @vibebox/hero-kinetic-type

Controls

Variant
<HeroKineticType />

About

Rebuilds the site kit's fullscreen type hero on the library's Kinetic Headline: the words rise on load in CSS alone. For brands that lead with words: studios, venues, launches. It differs from hero-editorial (static serif) and the Pro hero-word-swap (rotating words).

Use it when

  • The headline is short and confident.
  • The brand wants energy without 3D.

Skip it when

  • The headline is long and explanatory: use hero-centered.
  • Motion is set to none for the brand: any static hero reads better.

Install

  1. 1Add the VibeBox registry to components.json:
    {
      "registries": {
        "@vibebox": "https://motion.vibeboxph.com/r/{name}.json"
      }
    }
  2. 2Add the block with the shadcn CLI:
    npx shadcn@latest add @vibebox/hero-kinetic-type
  3. 3Use it:
    import { HeroKineticType } from "@/components/vibebox/hero-kinetic-type";
    import { home } from "@/content/pages/home";
    
    <HeroKineticType content={home.hero} variant="poster" id="top" />

Code

2 files
components/vibebox/hero-kinetic-type/index.tsx
/**
 * VibeBox Motion · Kinetic Type Hero
 * Copyright (c) 2026 VibeBox. Licensed under the VibeBox Motion Free License:
 * https://motion.vibeboxph.com/license
 * Use it in unlimited personal, commercial and client projects.
 * Do not sell or redistribute it as a component, kit, template or builder.
 */
import { Actions, Container, Eyebrow, headingId, Media, REVEAL, Section, SlotText, type BlockProps } from "@/lib/vibebox/block-kit";
import { KineticHeadline, type KineticSegment } from "@/components/vibebox/kinetic-headline";
import type { Image } from "@/lib/vibebox/content";
import { cn } from "@/lib/utils";
import type { Content, Variant } from "./schema";

/*
 * Poster type: the headline set as large as the screen allows, each word rising into place on
 * load (Kinetic Headline, CSS only), with the photo tucked into a corner or set wide beneath.
 */

const FALLBACK_MEDIA: Image = { src: "scene:ribbon", alt: "", width: 1200, height: 900 };

/** `*word*` becomes the serif emphasis segment. */
function segments(heading: string): KineticSegment[] {
  return heading.split("*").flatMap((part, index): KineticSegment[] => (part ? [index % 2 === 1 ? { text: part, variant: "serif" } : part] : []));
}

export type HeroKineticTypeProps = BlockProps<Content, Variant>;

export function HeroKineticType({ content, variant = "poster", id, tone, className }: HeroKineticTypeProps) {
  const poster = variant === "poster";
  return (
    <Section
      slug="hero-kinetic-type"
      variant={variant}
      id={id}
      tone={tone}
      labelledBy={headingId(id)}
      spacing={false}
      className={cn("overflow-clip py-[clamp(48px,8vw,120px)]", className)}
    >
      <Container className={cn("grid grid-cols-[minmax(0,1fr)] gap-[clamp(32px,5vw,64px)]", poster && "lg:grid-cols-[minmax(0,1.65fr)_minmax(0,0.85fr)] lg:items-end")}>
        <div className="grid gap-7">
          <Eyebrow value={content.eyebrow} />
          <div data-slot="heading">
            <KineticHeadline
              as="h1"
              id={headingId(id)}
              segments={segments(content.heading)}
              className="font-display text-[clamp(2.9rem,1rem+7.6vw,8.5rem)] leading-[0.94] font-semibold tracking-[-0.05em]"
            />
          </div>
          <div className={cn("grid gap-6", !poster && "md:grid-cols-[minmax(0,1fr)_auto] md:items-end md:gap-12")}>
            <SlotText as="p" value={content.lead} path="lead" className="max-w-[52ch] text-[clamp(1.05rem,1.3vw,1.25rem)] leading-relaxed text-pretty text-muted-foreground" />
            <Actions primary={content.primaryAction} secondary={content.secondaryAction} size="lg" />
          </div>
        </div>
        <div className={cn("overflow-hidden rounded-xl ring-1 ring-border", poster ? "aspect-[4/3] lg:aspect-[3/4]" : "aspect-[16/7] sm:aspect-[21/8]", REVEAL)}>
          <Media image={content.media ?? FALLBACK_MEDIA} priority sizes={poster ? "(min-width: 1024px) 30vw, 100vw" : "100vw"} />
        </div>
      </Container>
    </Section>
  );
}
components/vibebox/hero-kinetic-type/schema.ts
/**
 * VibeBox Motion · Kinetic Type Hero
 * Copyright (c) 2026 VibeBox. Licensed under the VibeBox Motion Free License:
 * https://motion.vibeboxph.com/license
 * Use it in unlimited personal, commercial and client projects.
 * Do not sell or redistribute it as a component, kit, template or builder.
 */
import { sections, type z } from "@/lib/vibebox/content";

export const variants = ["poster", "stacked"] as const;

export type Variant = (typeof variants)[number];

export const content = sections.hero;

export type Content = z.infer<typeof content>;

Content

Typed slots from schema.ts. Facts (hours, prices, quotes, names) come only from the business; until then they render as fill-ins.

SlotLabelTypeLimitFact
eyebrowKickertext32 chars—
headingHeadlinetext80 chars—
leadIntrotext160 chars—
primaryActionMain buttonaction24 chars—
secondaryActionSecond buttonaction24 chars—
mediaImageimage——

Variants

  • Posterdefault

    poster

    Type on the left, a 3:4 photo bottom right on desktop.

  • Stacked

    stacked

    Type across the page, intro beside the actions, a wide photo band beneath.

Accessibility and motion

Keyboard
The actions, in reading order.
Screen readers
The h1 reads as one sentence; the word masks are layout only.
Touch
Nothing depends on hover.
Reduced motion
The words are in place at once; nothing rises.

Edge cases and limits

  • An 80-character headline wraps to four lines on phones.
  • No photo: a placeholder scene.
  • A large serif headline about bread beside a framed window scene with a caption fill-in

    A magazine opening: a large serif headline, the intro and actions, tags, and the photo framed tall or set as a band.

    Heroes block · Server

  • A headline reading Beautiful websites for clinics, with the last word in spectrum colour

    A headline that names each audience in turn, the last word melting into the next.

    Heroes block · Server

  • A headline about moving better beside a mosaic of a tile scene, a bloom scene and a class list

    The promise beside a three-tile mosaic: a tall photo, a second image and a card of what the business offers.

    Heroes block · Server

↑ ↓ to move↵ to openesc to close