Zum Inhalt springen
UI Kit
Accent

Lichtstrahlen als Hintergrund

Lichtschächte von oben mit Dunst und schwebendem Staub, mit WebGL gezeichnet. Sie schimmern, ohne sich zu wiederholen, die Quelle folgt leicht dem Zeiger.

4 VariantsEine von 6 Components in 3D-Hintergründe

Eine Bühne, von oben beleuchtet

Lichtstrahlen fallen von oben, mit Dunst und schwebendem Staub in den Strahlen, mit WebGL gezeichnet. Sie stellen eine Überschrift auf eine Bühne und lenken den Blick direkt dorthin, ein Schleier hält den Text dabei lesbar.

„Hero von oben“ lässt Licht gerade auf eine mittige Überschrift fallen, wie durch ein Oberlicht. Das „Morgenband“ lässt das Licht schräg von rechts oben über ein Band mit Kennzahlen fallen. Die „Karte im Rampenlicht“ beleuchtet mit einem schmalen Strahl die eine Karte, auf die es ankommt. „Hinter einem Call to Action“ öffnet einen weiten, langsamen Lichtfächer über der Abschlussfläche.

Strahlen wirken am besten mit einer kurzen, mittigen Überschrift genau dort, wo das Licht landet. Nimm die Karte im Rampenlicht für den Tarif oder das Feature, das du empfiehlst, der Strahl zeigt von selbst darauf.

Variants

Hero von obenNeu in 1.2

Licht fällt gerade auf eine mittige Überschrift, wie durch ein Oberlicht.

MorgenbandNeu in 1.2

Licht fällt schräg von rechts oben über ein Band mit Kennzahlen.

Karte im RampenlichtNeu in 1.2

Ein schmaler Strahl beleuchtet die eine Karte, auf die es ankommt.

Hinter einem Call to ActionNeu in 1.2

Ein weiter, langsamer Lichtfächer öffnet sich über der Abschlussfläche.

Details

Was Lichtstrahlen mitbringt, aus Registry und Quellcode gelesen.

Bereich
Visuals
Variants
4
Version
1.0.0 · seit 1.2.0
Datei
components/ui/light-rays.tsx
Bringt mit
utilskitwebgl
npm-Pakete
Keine
Sprachen
Texte kommen über Props
Studio
Im Code anpassen

Props

Die Schnittstelle LightRaysProps aus components/ui/light-rays.tsx. Beschreibungen stammen aus den Kommentaren im Code und sind auf Englisch. Nimmt außerdem alle Props von ShaderLayerProps an.

  • originoptional
    LightRaysOrigin

    toptop-lefttop-right

    Where the light comes from

  • reachoptional
    number

    How far the rays reach down, 0.3 to 1.5, default 1

  • spreadoptional
    number

    Opening of the cone, 1 is the designed width

  • dustoptional
    boolean

    Floating dust in the light, default true

Barrierefreiheit

Aus dem Quellcode der Component abgeleitet.

  • Kommt ohne Client-State aus. Der Server schreibt sie vollständig, sie ist auch ohne JavaScript lesbar.

Bewegung

  • Ohne Animationen, sie steht sofort ruhig da.

Quellcode

Die Datei, die aiw add in dein Projekt legt. Sie gehört danach dir.

Datei anzeigen, 111 Zeilen
components/ui/light-rays.tsx
'use client';

import { GLSL_NOISE, ShaderBackdrop, ShaderCanvas, type ShaderLayerProps } from '@/components/ui/webgl';

/*
 * Shafts of light falling from above, like sun through a high window. The
 * rays are noise along the angle around a source above the box, layered in
 * three widths that drift at different paces, so they shimmer without ever
 * repeating. A thin haze and slow floating dust give the light its volume.
 * Soft by nature, rendered at reduced resolution.
 */

export type LightRaysOrigin = 'top' | 'top-left' | 'top-right';

export interface LightRaysProps extends ShaderLayerProps {
  /** Where the light comes from */
  origin?: LightRaysOrigin;
  /** How far the rays reach down, 0.3 to 1.5, default 1 */
  reach?: number;
  /** Opening of the cone, 1 is the designed width */
  spread?: number;
  /** Floating dust in the light, default true */
  dust?: boolean;
}

const ORIGIN: Record<LightRaysOrigin, number> = { 'top-left': -1, top: 0, 'top-right': 1 };

const FRAG = `${GLSL_NOISE}
uniform float u_origin;uniform float u_reach;uniform float u_spread;uniform float u_dust;
void main(){
float m=min(u_res.x,u_res.y);
vec2 p=(gl_FragCoord.xy-.5*u_res)/m;
float hw=.5*u_res.x/m,hh=.5*u_res.y/m;
vec2 src=vec2(u_origin*hw*.8+(u_mouse.x-.5)*.25*u_hover,hh+.35);
vec2 d=p-src;
float dist=length(d);
float ang=atan(d.x,-d.y);
float axis=-u_origin*.42;
float ca=(ang-axis)/(.62*u_spread);float cone=exp(-ca*ca);
float t=u_time;
float r=noise(vec2(ang*9./u_spread,t*.12))*.5+noise(vec2(ang*23./u_spread+3.,-t*.2))*.32+noise(vec2(ang*51./u_spread+7.,t*.35))*.18;
r=pow(smoothstep(.25,.95,r),1.6);
float len=hh*2.*u_reach+.3;
float fall=smoothstep(len,0.,dist-.35)*smoothstep(0.,.5,dist);
float haze=fbm(p*1.6+vec2(0.,t*.05))*.35;
float v=cone*fall*(r*.85+haze*.4+.06);
float dust=0.;
if(u_dust>.5){
vec2 q=p*14.+vec2(t*.15,-t*.25);
vec2 id=floor(q);vec2 h=hash2(id);
float dd=length(fract(q)-.5-(h-.5)*.6);
dust=smoothstep(.06,.0,dd)*step(.86,h.x)*(.5+.5*sin(t*2.+h.y*30.))*cone*fall*1.4;
}
vec3 col=mix(u_c0,u_c3,clamp(r*.7+(1.-dist/len)*.4,0.,1.)*u_dark);
float a=(v+dust)*mix(.5,1.,u_dark)*u_intensity;
a=clamp(a,0.,1.);
gl_FragColor=vec4(col*a,a);
}`;

const FALLBACK_AT: Record<LightRaysOrigin, string> = { top: '50% -12%', 'top-left': '12% -12%', 'top-right': '88% -12%' };
const FALLBACK_TURN: Record<LightRaysOrigin, number> = { top: 180, 'top-left': 156, 'top-right': 204 };

/** Still picture: a cone of striped light from the same corner */
function fallbackFor(origin: LightRaysOrigin) {
  const at = FALLBACK_AT[origin];
  const turn = FALLBACK_TURN[origin];
  const ray = 'color-mix(in oklab, var(--primary) 40%, var(--foreground) 12%)';
  return [
    `repeating-conic-gradient(from ${turn - 40}deg at ${at}, transparent 0deg, color-mix(in oklab, ${ray} 30%, transparent) 2deg, transparent 5deg, transparent 9deg)`,
    `radial-gradient(ellipse 60% 90% at ${at}, color-mix(in oklab, var(--primary) 26%, transparent), transparent 70%)`,
  ].join(', ');
}

/**
 * Light rays from above behind any content. With children it renders a box,
 * without children only the layer for a `relative` parent.
 */
export function LightRays({ intensity = 1, speed = 1, colors, interactive = true, origin = 'top', reach = 1, spread = 1, dust = true, fallback, scrim = 'none', scrimStrength, scrimColor, children, className, contentClassName, layerClassName }: LightRaysProps) {
  const at = FALLBACK_AT[origin];
  return (
    <ShaderBackdrop
      scrim={scrim}
      scrimStrength={scrimStrength}
      scrimColor={scrimColor}
      className={className}
      contentClassName={contentClassName}
      layer={
        <ShaderCanvas
          fragment={FRAG}
          colors={colors ?? ['var(--primary)', 'var(--primary)', 'var(--primary)', 'color-mix(in oklab, var(--primary) 35%, var(--foreground))']}
          uniforms={{ u_origin: ORIGIN[origin], u_reach: reach, u_spread: spread, u_dust: dust ? 1 : 0 }}
          speed={speed}
          intensity={intensity}
          scale={0.6}
          pointer={interactive}
          fallback={
            fallback ?? (
              <div
                className="absolute inset-0"
                style={{ background: fallbackFor(origin), maskImage: `radial-gradient(ellipse 90% 110% at ${at}, #000 20%, transparent 75%)`, WebkitMaskImage: `radial-gradient(ellipse 90% 110% at ${at}, #000 20%, transparent 75%)` }}
              />
            )
          }
          className={layerClassName}
        />
      }
    >
      {children}
    </ShaderBackdrop>
  );
}

Häufige Fragen

Wie installiere ich Lichtstrahlen?

Mit aiw add @ai-website/light-rays. Der Befehl legt die Datei components/ui/light-rays.tsx in dein Projekt, der Code gehört danach dir. Mit dabei sind webgl. Weitere npm-Pakete braucht sie nicht.

Welche Varianten hat Lichtstrahlen?

4 Varianten, Hero von oben, Morgenband, Karte im Rampenlicht und Hinter einem Call to Action.

Kann ein KI-Assistent Lichtstrahlen einbauen?

Ja. Über den MCP-Server der aiw CLI finden Claude, Cursor, GitHub Copilot, Windsurf, Codex und Gemini Lichtstrahlen mit aiw_components und installieren sie mit aiw_add @ai-website/light-rays.

Oft gesucht

Direkt zu

In die Zwischenablage kopiert