A flag, banner or sheet of fabric printed with bold type, rippling in the wind: simulated folds that bend the letters, satin, cotton, velvet and mesh, lit like a fashion campaign. The pointer blows, a click sends a gust.

  • text
  • typography
  • cloth
  • fabric
  • flag
  • banner
  • wind
  • shader
  • webgl
  • campaign
Preset

Installation

Pro — coming soon

The source and installation instructions for this item ship with Kagadmodyaa Pro.

Usage

Use it like any other component. Choose a theme with preset; any prop you pass as well overrides the preset.

import { useRef } from 'react'
import { ClothType, type ClothTypeHandle } from '@/components/effects/cloth-type/cloth-type'

// 1. A hero banner: it fills its parent, so the parent sets the height.
export function Hero() {
  return (
    <div style={{ height: 560 }}>
      <ClothType preset="Campaign" text="Make some noise" subtext="Collection 07 · Autumn 2026" />
    </div>
  )
}

// 2. Your own cloth: fabric, colours, layout and weather. Any prop overrides the preset.
export function Festival() {
  return (
    <div style={{ height: 640 }}>
      <ClothType preset="Festival" layout="banner" fabric="cotton" cloth="#ff5a14" ink="#0d0b0a" text={'Open air\nfestival'} wind={1.2} />
    </div>
  )
}

// 3. Send a gust from code (the pointer and a click already blow on it).
export function Gusty() {
  const ref = useRef<ClothTypeHandle>(null)
  return (
    <div style={{ height: 480 }}>
      <ClothType ref={ref} preset="Signal" />
      <button onClick={() => ref.current?.gust(1.4)}>Gust</button>
    </div>
  )
}

// Presets: Campaign, Festival, Velvet, Linen, Signal. backdrop="none" gives a transparent canvas (cloth and soft shadow only).
// The stage above is <ClothTypeShowcase />, also exported: the cloth with a caption and a gust button.
<ClothType preset="Festival" text={"Make some noise"} />

Presets

  • Campaign
  • Festival
  • Velvet
  • Linen
  • Signal

Props

NameTypeDefaultDescription
preset'Campaign' | 'Festival' | 'Velvet' | 'Linen' | 'Signal'none (the defaults below)A named theme. Any prop you pass as well overrides the preset’s value.
text'Make some noise' | 'Open Air Festival' | 'New Season' | 'Sail Away''Make some noise'The headline printed on the cloth. ClothType itself takes any string; words wrap and scale to fill the cloth.
subtext'Collection 07 · Autumn 2026' | 'Three days · One field · Free entry' | 'Limited run · Made to order' | 'Spring / Summer 2027''Collection 07 · Autumn 2026'The small line under the headline, above a hairline rule. Empty for none.
font'display' | 'serif' | 'mono' | 'condensed''display'Typeface: the site sans, a serif, mono, or the sans condensed.
weightnumber800Font weight of the headline. Range 300 to 900.
uppercasebooleantrueSet the headline in capitals.
layout'flag' | 'banner' | 'sheet''flag'flag: pinned to a pole on the left, banner: hung from a rod, sheet: pinned at the two top corners.
fabric'satin' | 'cotton' | 'velvet' | 'mesh''satin'Satin (long glossy highlights), cotton (matte, woven), velvet (pile with a grazing sheen and gold foil print) or mesh (open knit with real holes).
clothstring'#131318'Colour of the cloth. A hex colour.
inkstring'#f6f3ec'Colour of the print. A hex colour.
lightstring'#fff0dc'Colour of the key light. A hex colour.
backgroundstring'#2b2e35'Colour of the studio wall behind the cloth (and of the stage). A hex colour.
windnumber1How hard the wind blows, from hanging still to snapping. Range 0 to 2.
turbulencenumber0.5From long clean folds to many cross folds and fine crinkles. Range 0 to 1.
foldnumber1How deep the folds are. Range 0 to 2.
pointerWindbooleantrueThe pointer blows on the cloth: folds swell and ripple outward from it. A click or ref.gust() sends a gust along the cloth.
lightAnglenumber135Direction of the key light: 0 right, 90 above, 180 left. Range 0 to 360 deg.
sheennumber1.15Strength of the fabric's sheen: satin gloss, velvet rim, cotton fuzz. Range 0 to 2.
weavenumber1How visible the woven threads are. Range 0 to 2.
grainnumber0.3Film grain. A fine dither is always on, so gradients never band. Range 0 to 1.
backdrop'studio' | 'none''studio'studio paints a lit wall behind the cloth; none leaves the canvas transparent, with only the cloth and its soft shadow.
classNamestring—Extra class on the root element. The effect fills its parent: give the parent a height.
styleCSSProperties—Inline style on the root element.

Behaviour

  • The cloth is simulated in one fragment shader: travelling folds along the wind, cross folds that make diamonds, a fine ripple and a broad billow, all pinned at the hanging edge (a pole, a rod or two corners) and growing toward the free end. Cloth cannot stretch, so every fold also pulls the free end in, which is why a flag's tip breathes.
  • Each pixel inverts that fold map to find the cloth point it shows, so the print is bent by the real folds, not painted on top. The type is drawn into a canvas at device resolution and filtered across a three-level mip chain with four taps per pixel, so letters stay crisp in the flat parts of a fold and do not shimmer where it compresses them.
  • The fabric is lit with a per-fabric model: satin has an anisotropic highlight along its warp, tinted by the dye; cotton has a visible plain weave, slubs and a soft fuzz; velvet is dark head-on, bright at grazing angles, flips tone with the pile direction and carries its print as gold foil; mesh is an open knit with real holes that let the wall and the shadow through. Folds cast shadows on each other, and valleys are occluded.
  • A hem with stitching runs along the free edges and grommets sit on the pinned edge; both live in cloth space, so they ride the folds. The cloth casts a soft shadow on the studio wall (backdrop='studio'); backdrop='none' leaves the canvas transparent with only the cloth and its shadow.
  • The pointer is wind: folds swell around it and ripples run outward from it. A click, a tap or ref.gust() sends a gust along the cloth from the pinned edge to the free one. Wind itself varies slowly, so the cloth never repeats exactly.
  • The headline and small print are the accessible label (role='img') and a visually hidden copy of the text. It pauses off screen and in a background tab, lowers its resolution automatically when frames run slow, and draws one gently folded still frame under prefers-reduced-motion. Without WebGL, and before the first frame, a flat poster shows the banner, its type and a hint of folds. The first server render is the poster, so nothing differs between server and client.

See all effects