# Data Corruption Text Resolving

A shadcn/ui block from the [@weinc](https://we.inc/components?utm_source=shadcn.exchange) registry, listed on [shadcn.exchange](https://shadcn.exchange/r/weinc/data-corruption-text-resolving-into-headline).

- Page, with a live preview: https://shadcn.exchange/r/weinc/data-corruption-text-resolving-into-headline
- Screenshot: https://shadcn.exchange/shot/weinc/data-corruption-text-resolving-into-headline/light.png
- Registry item: https://we.inc/r/data-corruption-text-resolving-into-headline.json
- Listed: 2026-10-28, source last changed 2026-10-28

## Install

```bash
npx shadcn@latest add https://shadcn.exchange/r/weinc/data-corruption-text-resolving-into-headline.json
```

Run it in a project that has shadcn/ui set up. It adds the files below and installs what they depend on.

## Dependencies

- npm packages: `framer-motion`

## Files

### `components/we-inc/data-corruption-text-resolving-into-headline.tsx`

```tsx
import { useEffect, useRef, useState } from "react";
import { useReducedMotion } from "framer-motion";

const headline = "Your files, restored intact.";
const NOISE = "#%&*+=/<>?!01$@{}[]";
const RESOLVE_MS = 1500; // time for the line to settle, left to right
const HOLD_MS = 4200; // how long the clean line stays before it breaks again
const BREAK_MS = 700; // how long the corruption takes to spread

export default function DataCorruptionTextResolvingIntoHeadline() {
  const root = useRef<HTMLElement>(null);
  const chars = useRef<(HTMLSpanElement | null)[]>([]);
  const reduce = useReducedMotion();
  const [visible, setVisible] = useState(true);

  useEffect(() => {
    const el = root.current;
    if (!el) return;
    const io = new IntersectionObserver(([entry]) => setVisible(entry.isIntersecting));
    io.observe(el);
    return () => io.disconnect();
  }, []);

  useEffect(() => {
    const spans = chars.current;
    const letters = headline.split("");
    const show = (i: number, clean: boolean) => {
      const s = spans[i];
      if (!s || letters[i] === " ") return;
      s.textContent = clean ? letters[i] : NOISE[Math.floor(Math.random() * NOISE.length)];
      s.dataset.state = clean ? "clean" : "noise";
    };
    if (reduce || !visible) {
      letters.forEach((_, i) => show(i, true));
      return;
    }
    const n = letters.length;
    const order = letters.map((_, i) => i / n);
    const breakAt = letters.map(() => Math.random());
    const cycle = RESOLVE_MS + HOLD_MS + BREAK_MS;
    const start = performance.now();
    let last = 0;
    let frame = 0;
    const tick = (now: number) => {
      frame = requestAnimationFrame(tick);
      if (now - last < 55) return;
      last = now;
      const t = (now - start) % cycle;
      for (let i = 0; i < n; i += 1) {
        let clean: boolean;
        if (t < RESOLVE_MS) clean = t > 150 + order[i] * (RESOLVE_MS - 350);
        else if (t < RESOLVE_MS + HOLD_MS) clean = true;
        else clean = (t - RESOLVE_MS - HOLD_MS) / BREAK_MS < breakAt[i];
        show(i, clean);
      }
    };
    frame = requestAnimationFrame(tick);
    return () => cancelAnimationFrame(frame);
  }, [reduce, visible]);

  return (
    <section ref={root} className="w10dcr relative overflow-hidden bg-[#0b1322] px-5 py-20 sm:px-10 sm:py-28">
      <style>{`
        .w10dcr-grid { background-image: linear-gradient(rgba(148,233,200,0.05) 1px, transparent 1px), linear-gradient(90deg, rgba(148,233,200,0.05) 1px, transparent 1px); background-size: 32px 32px; mask-image: radial-gradient(70% 70% at 50% 45%, #000, transparent); -webkit-mask-image: radial-gradient(70% 70% at 50% 45%, #000, transparent); }
        .w10dcr-c[data-state="noise"] { color: #3f8f78; }
        .w10dcr-c[data-state="clean"] { color: #b9f5dc; text-shadow: 0 0 18px rgba(120, 240, 190, 0.25); }
        @media (prefers-reduced-motion: reduce) { .w10dcr-c { transition: none; } }
      `}</style>
      <div aria-hidden="true" className="w10dcr-grid pointer-events-none absolute inset-0" />
      <div className="relative mx-auto max-w-4xl">
        <p className="font-mono text-xs uppercase tracking-[0.3em] text-[#7fb8a6]">Coldvault · offsite backup</p>
        <h1 className="mt-6 font-mono text-[clamp(32px,6.2vw,72px)] font-bold leading-[1.1] tracking-tight text-[#b9f5dc]">
          <span className="sr-only">{headline}</span>
          <span aria-hidden="true">
            {headline.split("").map((ch, i) => (
              <span key={i} ref={(el) => { chars.current[i] = el; }} className="w10dcr-c" data-state="clean">{ch}</span>
            ))}
          </span>
        </h1>
        <p className="mt-7 max-w-xl text-base leading-relaxed text-[#a9c4bb] sm:text-lg">
          Encrypted nightly copies of every laptop in the office, checked byte for byte each week so a restore is never a gamble.
        </p>
        <div className="mt-10 flex flex-wrap items-center gap-5">
          <a
            href="#"
            className="inline-flex h-12 items-center rounded-md bg-[#b9f5dc] px-6 font-mono text-sm font-semibold text-[#0b1322] transition hover:bg-white focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[#b9f5dc] focus-visible:ring-offset-2 focus-visible:ring-offset-[#0b1322]"
          >
            Run a test restore
          </a>
          <span className="font-mono text-xs uppercase tracking-widest text-[#7fb8a6]">Last check passed 06:00</span>
        </div>
      </div>
    </section>
  );
}
```
