# Gravity Letters

> A React physics text effect: a gravity field where letters, numbers, emoji or any components you pass fall and pile up like real objects.

- Type: React component (Text & Effects)
- Access: Free (the source is open to everyone)
- Version: 1.0.1
- Install: `npx wingo-ui@latest add gravity-letters`
- Docs: https://wingo-ui.com/components/gravity-letters

## Interaction

The field opens by pouring its initial text, letter by letter, onto the floor. Click or tap anywhere to drop a glyph, or press and hold to pour a steady stream that follows your pointer. Glyphs tumble as they fall, bounce softly when they land, and pile up into rounded hills. On phones, tilt the device to spill the pile toward the low side. With reduced motion on, glyphs appear straight on the pile.

## Installation

```bash
npx wingo-ui@latest add gravity-letters
```

The CLI adds the files, their dependencies and a version record for updates.

With shadcn: `npx shadcn@latest add https://wingo-ui.com/r/gravity-letters.json`

Files:

- `components/ui/gravity-letters.tsx`

Wingo UI dependencies (installed automatically):

- [UIProvider](https://wingo-ui.com/components/ui-config) ([Markdown](https://wingo-ui.com/components/ui-config.md))

## Usage

```tsx
import GravityLetters from "@/components/ui/gravity-letters"

export function Demo() {
  return (
    <GravityLetters type="letters" className="h-96 w-full rounded-3xl border">
      {/* anything you render inside sits under the falling glyphs */}
      <p className="absolute inset-0 grid place-items-center text-sm text-muted-foreground">
        Click anywhere
      </p>
    </GravityLetters>
  )
}

// A blank field, or your own opening word:
// <GravityLetters initialText="" />
// <GravityLetters initialText="404" type="numbers" />

// Digits instead:
// <GravityLetters type="numbers" />

// Or drop your own content: emoji, icons, any component:
// <GravityLetters items={["🍎", "🍊", "🍇", <Sparkles key="s" className="size-7" />]} />
```

## Props

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `type?` | `"letters" \| "numbers" \| "both"` | `"letters"` | Which pool to draw from: letters, digits, or both. Ignored when items is set. |
| `initialText?` | `string` | `"HELLO"` | Letters poured across the middle of the field on mount, one after another, so it never starts empty. Spaces leave gaps; pass an empty string for a blank field. |
| `items?` | `React.ReactNode[]` |  | Your own drop pool: emoji, icons, or any components. Each drop picks a random entry. Overrides type. |
| `gravity?` | `number` | `800` | Downward acceleration in px/s². Lower is floatier, higher is heavier. Changes apply mid-fall. |
| `size?` | `number` | `28` | Base glyph size in pixels. Each drop varies by up to 20% around it. Applies to new drops. |
| `color?` | `string` | `"currentColor"` | Glyph color, any CSS color. Defaults to currentColor so it follows your theme. |
| `weight?` | `"normal" \| "medium" \| "semibold" \| "bold"` | `"semibold"` | Font weight of the falling glyphs. |
| `sizeVariance?` | `number` | `0.2` | How much a dropped glyph's size varies around size: 0.2 means 80% to 120%. initialText letters always use size exactly. |
| `bounce?` | `number` | `0.22` | How much of its speed a glyph keeps on its first touch down, 0 (a thud) to 0.95. |
| `holdDelay?` | `number` | `300` | How long a press has to last, in milliseconds, before glyphs start pouring. |
| `pourInterval?` | `number` | `120` | Time between glyphs while pouring, in milliseconds. |
| `maxGlyphs?` | `number` | `0` | Max glyphs kept in the field; past the cap the oldest fade out and the pile settles into the gap. 0 keeps every glyph, which is the default. |
| `deviceTilt?` | `boolean` | `true` | Tilting a phone spills the pile toward the low side. iOS asks for motion permission on the first tap. |
| `children?` | `React.ReactNode` |  | Rendered under the glyph layer, e.g. a hint or an empty state. Clicks on it still drop glyphs unless a handler calls preventDefault. |
| `className?` | `string` |  | Extra classes for the root element. Use it to size the field; glyphs pile on its bottom edge and are clipped to it. Pointer handlers you pass run before the drop. |

## Examples

- **Celebrating empty state**: items swaps the letters for emoji; the message sits behind the pile and maxGlyphs keeps it light.
- **Numbers in a brand color**: type numbers pours 2026 on load in bold orange; every click adds a random digit.
- **Your own components**: Any element can fall, here tag pills with no size variance and a bouncier landing.

## See also

- [Background Pattern](https://wingo-ui.com/components/background-pattern) ([Markdown](https://wingo-ui.com/components/background-pattern.md))
- [Grid Reveal](https://wingo-ui.com/components/grid-reveal) ([Markdown](https://wingo-ui.com/components/grid-reveal.md))
- [Empty State](https://wingo-ui.com/components/empty-state) ([Markdown](https://wingo-ui.com/components/empty-state.md))
- [Animated Counter](https://wingo-ui.com/components/animated-counter) ([Markdown](https://wingo-ui.com/components/animated-counter.md))

---

Canonical: https://wingo-ui.com/components/gravity-letters
More components: https://wingo-ui.com/components · Index for agents: https://wingo-ui.com/llms.txt
