Skip to content
Plinth

Backgrounds

Prism Beams

Spectral beams fanning from an off-frame apex, dispersed by one conic gradient and softened into light with a blur.

#background#prism#conic-gradient#light#animation

Install

npx shadcn@latest add https://plinthui.com/r/prism-beams.json
Open in v0
// No hooks or handlers, so this stays a server component — it is pure CSS.
const css = `
.prism {
  position: relative;
  min-height: 300px;
  height: 100%;
  overflow: hidden;
  background: radial-gradient(120% 100% at 20% 0%, #140a2e 0%, #08040f 60%, #050208 100%);
  isolation: isolate;
}

/* The fan is ONE conic-gradient, not a set of beam elements. A conic sweep
   already varies hue with angle, which is exactly what a prism does; drawing
   individual wedges means positioning and rotating each one by hand and
   keeping their hues in step. */
.prism__fan {
  position: absolute;
  /* Oversized and anchored off-frame so the apex sits outside the viewport —
     you see beams spreading, never the point they come from, which is what
     sells it as light entering rather than a pinwheel. */
  left: -60%;
  top: -120%;
  width: 220%;
  height: 220%;
  background: conic-gradient(
    from 190deg at 50% 50%,
    transparent 0deg,
    rgba(255, 62, 129, 0.85) 6deg,
    rgba(255, 170, 64, 0.75) 12deg,
    transparent 17deg,
    transparent 24deg,
    rgba(64, 226, 255, 0.8) 30deg,
    rgba(120, 110, 255, 0.85) 36deg,
    transparent 42deg,
    transparent 52deg,
    rgba(255, 92, 220, 0.7) 58deg,
    transparent 66deg,
    transparent 360deg
  );
  /* Softening the wedges is what turns hard pie slices into light. */
  filter: blur(9px);
  mix-blend-mode: screen;
  transform-origin: 50% 50%;
  animation: prism-sweep 24s ease-in-out infinite alternate;
}

/* A second fan, counter-rotating and slower, so beams cross and brighten where
   they overlap instead of the whole fan turning as one rigid object. */
.prism__fan--b {
  background: conic-gradient(
    from 205deg at 50% 50%,
    transparent 0deg,
    rgba(120, 220, 255, 0.5) 8deg,
    transparent 15deg,
    transparent 33deg,
    rgba(255, 120, 190, 0.45) 40deg,
    transparent 48deg,
    transparent 360deg
  );
  filter: blur(15px);
  animation: prism-sweep-b 31s ease-in-out infinite alternate;
  opacity: 0.9;
}

@keyframes prism-sweep {
  from { transform: rotate(-5deg); }
  to   { transform: rotate(6deg); }
}
@keyframes prism-sweep-b {
  from { transform: rotate(4deg); }
  to   { transform: rotate(-7deg); }
}

/* The edge the light breaks on. A bright hairline with a bloom under it gives
   the beams somewhere to originate, without ever showing the conic apex. */
.prism__edge {
  position: absolute;
  left: 8%;
  top: -14%;
  width: 2px;
  height: 62%;
  transform: rotate(24deg);
  transform-origin: 50% 0;
  background: linear-gradient(180deg, transparent, rgba(255, 255, 255, 0.95) 45%, transparent);
  box-shadow: 0 0 26px 6px rgba(180, 220, 255, 0.45);
  mix-blend-mode: screen;
}

.prism__vignette {
  position: absolute;
  inset: 0;
  background: radial-gradient(120% 90% at 30% 20%, transparent 52%, rgba(2, 1, 6, 0.72) 100%);
  pointer-events: none;
}

@media (prefers-reduced-motion: reduce) {
  .prism__fan { animation: none; }
}
`;

export function PrismBeams() {
  return (
    <>
      <style>{css}</style>
      <div className="prism">
        <div className="prism__fan" />
        <div className="prism__fan prism__fan--b" />
        <div className="prism__edge" />
        <div className="prism__vignette" />
      </div>
    </>
  );
}

More in Backgrounds

Similar tags