Workspace / component / shaders

Chroma Shader

Mounts the Pax glitch engine over live HTML: RGB channels split and slices tear on an interval you control. The content stays real and selectable.

Workspacecomponentshaders

paxfx add blocks/component-shaders-chromalocal only

Tier: high. Reduced motion: Engine idles on its first frame with no tearing.

"use client";

import type { ReactNode } from "react";
import { cn, EffectSurface } from "@pax-sh/blocks";

export interface ChromaShaderProps {
  className?: string;
  /** Content the glitch engine tears apart. Defaults to a demo panel. */
  children?: ReactNode;
}

function DemoContent() {
  return (
    <div className="flex min-h-[320px] flex-col justify-center gap-5 p-8 md:p-12">
      <p className="m-0 text-xs font-medium uppercase tracking-[0.22em] text-[var(--pax-acid,#c8ff00)]">
        Signal 07 / RGB split
      </p>
      <h3 className="m-0 max-w-xl text-3xl font-semibold leading-tight tracking-tight [text-wrap:balance] md:text-4xl">
        Out of register, on purpose.
      </h3>
      <p className="m-0 max-w-md text-sm leading-relaxed text-[var(--pax-paper,#f6f2ea)] opacity-70">
        The glitch engine splits this markup into color channels and tears horizontal slices on an
        interval. Select the text: it stays real HTML underneath the effect.
      </p>
      <div className="mt-2 flex flex-wrap gap-2">
        {["Live DOM", "Selectable", "GPU composited"].map((label) => (
          <span
            key={label}
            className="rounded-full border px-3 py-1 text-[11px] font-medium uppercase tracking-[0.14em] text-[var(--pax-paper,#f6f2ea)]"
            style={{ borderColor: "color-mix(in srgb, var(--pax-paper,#f6f2ea) 22%, transparent)" }}
          >
            {label}
          </span>
        ))}
      </div>
    </div>
  );
}

/**
 * Mounts the Pax glitch engine over live HTML. RGB channels split and slices
 * tear on an interval while the content underneath remains selectable DOM.
 * Under reduced motion the engine idles on its first frame with no tearing.
 */
export function ChromaShader({ className, children }: ChromaShaderProps) {
  return (
    <div
      className={cn(
        "relative isolate overflow-hidden rounded-2xl border border-[var(--pax-border,rgba(18,17,15,0.12))]",
        "bg-[var(--pax-night,#0b0d10)] text-[var(--pax-paper,#f6f2ea)]",
        className,
      )}
      data-pax-asset="component-shaders-chroma"
    >
      <EffectSurface effect="glitch" tier="high" className="h-full w-full">
        {children ?? <DemoContent />}
      </EffectSurface>
    </div>
  );
}