Workspace / component / backgrounds

Acid Mesh Background

Layered radial mesh gradients in acid, lime, and ink that drift slowly against each other. Saturated without tipping into noise.

Workspacecomponentbackgrounds

paxfx add blocks/component-backgrounds-acid-meshlocal only

Tier: low. Reduced motion: Mesh holds a fixed composition.

"use client";

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

export interface AcidMeshBackgroundProps {
  /** 0 to 1; overall visibility of the mesh layers. */
  intensity?: number;
  /** Multiplier on drift speed. 1 is the tuned default. */
  speed?: number;
  className?: string;
  children?: ReactNode;
}

/**
 * Layered radial mesh gradients in acid, lime, and ink that drift slowly
 * against each other on independent durations. Each layer animates transform
 * only, so the whole surface composites on the GPU. Under reduced motion the
 * mesh holds a fixed composition.
 */
export function AcidMeshBackground({
  intensity = 0.8,
  speed = 1,
  className,
  children,
}: AcidMeshBackgroundProps) {
  const reduced = useReducedMotion();
  const clamped = Math.min(1, Math.max(0, intensity));
  const dur = (seconds: number) => `${seconds / Math.max(0.1, speed)}s`;

  const layer = (background: string, animation: string, opacity: number) => (
    <div
      aria-hidden="true"
      className="pointer-events-none absolute -inset-[22%] will-change-transform"
      style={{
        background,
        opacity: opacity * clamped,
        animation: reduced ? "none" : animation,
      }}
    />
  );

  return (
    <div
      className={cn(
        "relative isolate overflow-hidden rounded-2xl border border-[var(--pax-border,rgba(18,17,15,0.12))]",
        "bg-[var(--pax-paper,#f6f2ea)] text-[var(--pax-ink,#12110f)]",
        className,
      )}
      data-pax-asset="component-backgrounds-acid-mesh"
    >
      <style>{`
        @keyframes pax-acid-mesh-a {
          from { transform: translate3d(-3%, -2%, 0) rotate(0deg); }
          to { transform: translate3d(4%, 3%, 0) rotate(5deg); }
        }
        @keyframes pax-acid-mesh-b {
          from { transform: translate3d(3%, 2%, 0) rotate(0deg); }
          to { transform: translate3d(-4%, -3%, 0) rotate(-6deg); }
        }
        @keyframes pax-acid-mesh-c {
          from { transform: translate3d(-2%, 3%, 0) scale(1); }
          to { transform: translate3d(2%, -3%, 0) scale(1.08); }
        }
      `}</style>
      {layer(
        "radial-gradient(46% 42% at 26% 30%, color-mix(in srgb, var(--pax-acid,#c8ff00) 88%, transparent) 0%, transparent 100%)",
        `pax-acid-mesh-a ${dur(26)} ease-in-out infinite alternate`,
        0.9,
      )}
      {layer(
        "radial-gradient(50% 46% at 74% 64%, color-mix(in srgb, var(--pax-acid,#c8ff00) 60%, white) 0%, transparent 100%)",
        `pax-acid-mesh-b ${dur(34)} ease-in-out infinite alternate`,
        0.8,
      )}
      {layer(
        "radial-gradient(44% 52% at 58% 12%, color-mix(in srgb, var(--pax-ink,#12110f) 32%, transparent) 0%, transparent 100%)",
        `pax-acid-mesh-c ${dur(42)} ease-in-out infinite alternate`,
        0.55,
      )}
      <div
        aria-hidden="true"
        className="pointer-events-none absolute inset-0"
        style={{
          background: "linear-gradient(180deg, rgba(255,255,255,0.28) 0%, rgba(255,255,255,0) 42%)",
        }}
      />
      <div className="relative z-[1]">{children}</div>
    </div>
  );
}