Workspace / component / animations

Laser Flow

Beams of light sweep diagonally across the surface, refracting where they cross content edges. Beam count, angle, and speed are props.

Workspacecomponentanimations

paxfx add blocks/component-animations-laser-flowlocal only

Tier: medium. Reduced motion: Beams hold fixed diagonal positions.

"use client";

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

export interface LaserFlowProps {
  /** Number of beams (1 to 8). */
  count?: number;
  /** Beam tilt in degrees. */
  angle?: number;
  /** Seconds for one full sweep. */
  speed?: number;
  className?: string;
  children?: ReactNode;
}

/**
 * Diagonal beams of light sweep across the surface on transform-only CSS
 * keyframes. Each beam is a skewed gradient sliver whose duration and
 * negative delay derive deterministically from its index, so the pattern
 * never syncs and needs no JavaScript per frame. Reduced motion holds the
 * beams at fixed diagonal positions.
 */
export function LaserFlow({
  count = 4,
  angle = 18,
  speed = 7,
  className,
  children,
}: LaserFlowProps) {
  const reduced = useReducedMotion();
  const [ref, inView] = useInView<HTMLDivElement>({ threshold: 0.2 });

  const beams = Math.min(8, Math.max(1, Math.round(count)));
  const animate = inView && !reduced;

  const beamStyle = (i: number): CSSProperties => {
    const duration = speed * (1 + ((i * 29) % 35) / 100);
    const delay = -duration * (((i * 47) % 100) / 100);
    const staticShift = -150 + ((i * 83) % 100) * 3;
    return {
      left: `${8 + (i * 90) / beams}%`,
      width: `${9 + ((i * 13) % 3) * 3}%`,
      transform: animate ? undefined : `translateX(${staticShift}%) skewX(${-angle}deg)`,
      animation: animate
        ? `pax-laser-sweep ${duration.toFixed(2)}s linear ${delay.toFixed(2)}s infinite`
        : undefined,
      opacity: 0.5 + ((i * 17) % 40) / 100,
    };
  };

  return (
    <div
      ref={ref}
      className={cn(
        "relative isolate min-h-[240px] 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-animations-laser-flow"
      style={{ "--pax-laser-skew": `${-angle}deg` } as CSSProperties}
    >
      <style>{`
        @keyframes pax-laser-sweep {
          0% { transform: translateX(-400%) skewX(var(--pax-laser-skew, -18deg)); }
          100% { transform: translateX(400%) skewX(var(--pax-laser-skew, -18deg)); }
        }
      `}</style>
      <div aria-hidden="true" className="pointer-events-none absolute inset-[-20%] z-[1]">
        {Array.from({ length: beams }, (_, i) => (
          <span
            key={i}
            className="absolute bottom-0 top-0 will-change-transform"
            style={{
              ...beamStyle(i),
              background:
                "linear-gradient(90deg, transparent 0%, rgba(200,255,0,0.16) 30%, rgba(246,242,234,0.34) 50%, rgba(200,255,0,0.16) 70%, transparent 100%)",
            }}
          />
        ))}
      </div>
      <div className="relative z-[2]">
        {children ?? (
          <div className="flex min-h-[240px] flex-col justify-end p-8">
            <p className="m-0 text-xs font-medium uppercase tracking-[0.22em] text-[var(--pax-mute,#6b645c)]">
              Laser flow
            </p>
            <h3 className="mt-3 max-w-md text-2xl font-semibold leading-snug tracking-tight [text-wrap:balance]">
              Beams sweep the surface on nothing but compositor transforms.
            </h3>
            <p className="mt-3 max-w-sm text-sm leading-relaxed text-[var(--pax-mute,#6b645c)]">
              Count, angle, and speed are props. Zero JavaScript per frame.
            </p>
          </div>
        )}
      </div>
    </div>
  );
}