# Amalgam — Animated Text Effect for React

> A wordmark cast in living liquid chrome: a glyph alpha mask shaded by an original OGL metal shader — domain-warped churn, thin specular bands over dark troughs, a fresnel-lit rim, a whisper of chromatic fringing, and one crisp highlight that sweeps the full mark every few seconds, after a one-shot pour-in on first view. Polished cool steel by default; tint reaches warm bronze/gold.

- Page: https://crucibleui.com/components/text/amalgam
- Category: [text](https://crucibleui.com/components/text)
- Tier: pro (one-time purchase, see https://crucibleui.com/pricing)
- Engine: ogl
- npm dependencies: ogl

## Install

```bash
npx shadcn@latest add @crucible/amalgam
```

Pro install requires adding the token-bearing `@crucible` registry to components.json (issued at https://crucibleui.com/account after purchase).

Import from `@/components/crucible/amalgam`.

## Props (`AmalgamProps`)

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `text?` | `string` | `"AMALGAM"` | The wordmark rendered as liquid metal. |
| `fontSize?` | `number` | `120` | Cap height of the wordmark, in CSS pixels. |
| `fontWeight?` | `number \| string` | `800` | Font weight of the mask glyphs. |
| `fontFamily?` | `string` | `a heavy cross-platform sans stack` | Font family used to render the mask. Must be a concrete family (canvas cannot inherit CSS fonts). |
| `letterSpacing?` | `number` | `2` | Extra letter spacing in CSS pixels. |
| `colors?` | `AmalgamColors` | `polished cool steel` | Metal ramp: `{ dark, light, tint }`. |
| `speed?` | `number` | `1` | Flow speed multiplier. 1 = default, 0 = frozen churn. |
| `intensity?` | `number` | `1` | Overall surface brightness. 1 = default. |
| `amplitude?` | `number` | `1` | Liquid wave amplitude — how far the metal churns. 1 = default. |
| `scale?` | `number` | `1` | Pattern scale of the flow field. Higher = finer marbling. |
| `sharpness?` | `number` | `1` | Specular band sharpness. Higher = thinner, crisper highlights. |
| `fresnel?` | `number` | `1` | Fresnel rim strength along the silhouette. |
| `chroma?` | `number` | `0.14` | Chromatic-aberration amount — a faint per-channel split at the bands. Defaults to a whisper; push up for a rainbow oil-slick edge. |
| `sweepInterval?` | `number` | `6` | Seconds between the single crisp highlight sweeps that travel the full mark. 0 disables the sweep, leaving only ambient churn. |
| `mouseAnimation?` | `boolean` | `false` | Swap the auto flow loop for pointer-driven flow. |
| `paused?` | `boolean` | `false` | Freeze the animation at its current frame. |
| `intro?` | `boolean` | `true` | Designed intro: the first time the mark scrolls into view, liquid metal pours across it behind a bright leading edge (~1.2s, once). Off renders the full mark immediately. Never under reduced motion. |
| `idle?` | `boolean` | `true` | Idle autoplay for `mouseAnimation`: after 1.5s with no pointer over the mark, a ghost point drifts a slow Lissajous path so the pointer-driven flow keeps leaning and churning; a real pointer takes over instantly. No effect without `mouseAnimation`. |
| `ref?` | `React.Ref<AmalgamHandle>` | — | React 19 ref prop — imperative `replay()` of the intro. |

Also accepts: `React.ComponentPropsWithoutRef<"div">`.

## Usage example

```tsx
import { Amalgam } from "@/components/crucible/amalgam";

export default function AmalgamDemo() {
  return (
    <div className="relative isolate flex h-full min-h-[360px] w-full flex-col items-center justify-center gap-10 overflow-hidden rounded-xl bg-neutral-950">
      <div
        aria-hidden
        className="pointer-events-none absolute inset-0 bg-[radial-gradient(ellipse_at_center,rgba(255,255,255,0.045),transparent_70%)]"
      />
      <div className="relative z-10 flex w-full flex-col items-center gap-3 px-6 text-center">
        <Amalgam text="AMALGAM" fontSize={132} />
        <p className="text-sm text-neutral-500">
          A wordmark cast in flowing liquid steel — watch for the slow highlight sweep.
        </p>
      </div>

      <div className="relative z-10 flex w-full flex-col items-center gap-2 px-6 text-center">
        <Amalgam
          text="BRONZE"
          fontSize={92}
          colors={{ dark: "#241505", light: "#f7e4b6", tint: "#d7a44a" }}
          chroma={0.22}
        />
        <span className="text-[10px] font-medium uppercase tracking-[0.2em] text-neutral-600">
          Custom colors — warm chrome
        </span>
      </div>
    </div>
  );
}
```

## Accessibility & performance

Honors `prefers-reduced-motion` with a designed static frame or fade (never a blank box) and passes `className` through. Pauses offscreen and on hidden tabs, clamps device pixel ratio, and tears down its GL/canvas context on unmount.
