Leuchtende Kugel als Animation
Eine weiche, atmende Lichtkugel, wie eine Kugel schattiert, mit Wirbel im Inneren und weitem Schein, mit WebGL gezeichnet. Neigt sich zum Zeiger.
Ein ruhiges Licht, das zu atmen scheint
Eine Lichtkugel ist eine weiche Kugel aus Licht, die langsam atmet, schattiert wie eine echte Kugel und umgeben von weitem Schein, mit WebGL gezeichnet. Sie gibt einer Seite eine ruhige, lebendige Mitte und passt gut zu Assistenten, Sprachfunktionen und leisen Marken.
„Hero mit Kugel daneben“ setzt den Text links, rechts atmet die Kugel, am Telefon liegt sie unter dem Text. Die „Aufgehende Kugel“ steigt halb über die Unterkante wie eine Sonne, der Text steht darüber. Die „Hervorgehobene Karte“ zeigt eine kleine Kugel, die leuchtet wie eine Stimme, die zuhört. „Hinter einem Call to Action“ lässt eine große Kugel weich hinter der abschließenden Überschrift leuchten.
Lass die Kugel allein stehen, sie braucht Raum, um zu leuchten. Die Karte eignet sich als leises Zeichen, dass etwas zuhört oder nachdenkt, etwa neben einer Assistenzfunktion.
Variants
Details
Was Lichtkugel mitbringt, aus Registry und Quellcode gelesen.
- Kategorie
- 3D-Hintergründe
- Bereich
- Visuals
- Variants
- 4
- Version
- 1.0.0 · seit 1.2.0
- Datei
- components/ui/glow-orb.tsx
- Bringt mit
- utilskitwebgl
- npm-Pakete
- Keine
- Sprachen
- Texte kommen über Props
- Studio
- Im Code anpassen
- In Sammlungen
- 3D und Bewegung
- Mit KI bauen
- Per MCP in Claude, Cursor, Copilot und Codex
Props
Die Schnittstelle GlowOrbProps aus components/ui/glow-orb.tsx. Beschreibungen stammen aus den Kommentaren im Code und sind auf Englisch. Nimmt außerdem alle Props von ShaderLayerProps an.
placementoptionalGlowOrbPlacementcenterrightbottomcorner
center behind the copy, right next to it (from 900 px box width, below the copy on narrower boxes), bottom half sunk below the edge, or corner at the top right (for cards)
sizeoptionalnumberSize, 1 is the designed size
wobbleoptionalnumberHow much the outline moves, 0 is a calm circle, default 1
glowoptionalnumberWidth of the glow around the orb, default 1
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, 115 Zeilen
'use client';
import { cn } from '@/lib/kit';
import { GLSL_NOISE, ACCENT_PALETTE, ShaderBackdrop, ShaderCanvas, type ShaderLayerProps } from '@/components/ui/webgl';
/*
* A soft orb of light that breathes. Its outline is a circle bent by slow
* noise, its body is shaded like a sphere lit from the upper left, with a
* swirl of the neighbour colors inside, a bright rim and a wide glow around
* it. It leans toward the pointer and swells a little while the page scrolls
* past. Soft by nature, rendered at reduced resolution.
*/
export type GlowOrbPlacement = 'center' | 'right' | 'bottom' | 'corner';
export interface GlowOrbProps extends ShaderLayerProps {
/** center behind the copy, right next to it (from 900 px box width, below the copy on narrower boxes), bottom half sunk below the edge, or corner at the top right (for cards) */
placement?: GlowOrbPlacement;
/** Size, 1 is the designed size */
size?: number;
/** How much the outline moves, 0 is a calm circle, default 1 */
wobble?: number;
/** Width of the glow around the orb, default 1 */
glow?: number;
}
const PLACE: Record<GlowOrbPlacement, number> = { center: 0, right: 1, bottom: 2, corner: 3 };
const FRAG = `${GLSL_NOISE}
uniform float u_place;uniform float u_size;uniform float u_wobble;uniform float u_glow;
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 c=vec2(0.);float R=.27;
if(u_place>.5&&u_place<1.5){if(u_res.x/u_dpr>=900.){c=vec2(hw*.5,0.);R=.3;}else{R=min(.3,130.*u_dpr/m);c=vec2(0.,-hh+R*1.45+.04);}}
if(u_place>1.5&&u_place<2.5){R=min(.55,hw*.6);c=vec2(0.,-hh-R*.15);}
if(u_place>2.5){R=min(min(.3,hh*.42),80.*u_dpr/m);c=vec2(hw-R*1.05,hh-R*1.05);}
float t=u_time;
R*=u_size*(1.+.045*sin(t*.85)+(u_scroll-.5)*.08);
c+=(u_mouse-.5)*vec2(.12,.08)*u_hover;
vec2 d=p-c;float len=length(d);
vec2 dir=d/max(len,1e-4);
float w=(noise(dir*1.3+vec2(t*.22,-t*.17))-.5)*.22+(noise(dir*2.7-vec2(t*.31,t*.13))-.5)*.1;
float rr=R*(1.+w*u_wobble);
float sdf=len-rr;
vec2 q=d/rr;
float z=sqrt(max(0.,1.-dot(q,q)));
vec3 n=vec3(q,z);
float lit=clamp(dot(n,normalize(vec3(-.45,.55,.7))),0.,1.);
float sw=fbm(q*1.8+vec2(t*.09,-t*.07)+n.xy*.6);
vec3 hi=mix(vec3(1.),u_c3,u_dark);
vec3 body=mix(u_c0,hi,smoothstep(.25,1.,lit)*.62);
body=mix(body,u_c1,smoothstep(.45,.85,sw)*.32);
body=mix(body,u_c2,smoothstep(.55,.9,1.-sw)*.28*(1.-lit));
float rim=pow(1.-z,2.5);
body+=u_c0*rim*.3*u_dark;
float inside=smoothstep(.035,-.035,sdf);
float glow=exp(-max(sdf,0.)*mix(5.5,3.5,u_dark)/max(u_glow,.1))*mix(.32,.55,u_dark);
float ab=inside*mix(.74,.92,u_dark)*(.78+.22*z);
vec3 col=body*ab+u_c0*glow*(1.-inside);
float a=ab+glow*(1.-inside);
float k=u_intensity;
a=clamp(a*k,0.,1.);
gl_FragColor=vec4(min(col*k,vec3(1.)),a);
}`;
const SPOT: Record<GlowOrbPlacement, string> = {
center: 'left-1/2 top-1/2 aspect-square w-[min(54%,54vh)] -translate-x-1/2 -translate-y-1/2',
right: 'max-lg:left-1/2 max-lg:top-[64%] max-lg:aspect-square max-lg:w-[min(60%,40vh)] max-lg:-translate-x-1/2 lg:right-[10%] lg:top-1/2 lg:aspect-square lg:w-[min(32%,60vh)] lg:-translate-y-1/2',
bottom: 'left-1/2 top-[78%] aspect-square w-[min(66%,40rem)] -translate-x-1/2',
corner: 'right-[6%] top-[6%] aspect-square h-[44%]',
};
/**
* A breathing orb of light behind or beside any content. With children it
* renders a box, without children only the layer for a `relative` parent.
*/
export function GlowOrb({ intensity = 1, speed = 1, colors, interactive = true, placement = 'center', size = 1, wobble = 1, glow = 1, fallback, scrim = 'none', scrimStrength, scrimColor, children, className, contentClassName, layerClassName }: GlowOrbProps) {
return (
<ShaderBackdrop
scrim={scrim}
scrimStrength={scrimStrength}
scrimColor={scrimColor}
className={className}
contentClassName={contentClassName}
layer={
<ShaderCanvas
fragment={FRAG}
colors={colors ?? ACCENT_PALETTE}
uniforms={{ u_place: PLACE[placement], u_size: size, u_wobble: wobble, u_glow: glow }}
speed={speed}
intensity={intensity}
scale={0.6}
pointer={interactive}
fallback={
fallback ?? (
<div
className={cn('absolute rounded-full', SPOT[placement])}
style={{
background: 'radial-gradient(circle at 38% 34%, color-mix(in oklab, var(--primary) 40%, var(--foreground) 25%), var(--primary) 45%, oklch(from var(--primary) calc(l * 0.8) c calc(h - 52)) 100%)',
boxShadow: '0 0 120px 30px color-mix(in oklab, var(--primary) 35%, transparent)',
opacity: 0.9,
}}
/>
)
}
className={layerClassName}
/>
}
>
{children}
</ShaderBackdrop>
);
}Häufige Fragen
Wie installiere ich Lichtkugel?
Mit aiw add @ai-website/glow-orb. Der Befehl legt die Datei components/ui/glow-orb.tsx in dein Projekt, der Code gehört danach dir. Mit dabei sind webgl. Weitere npm-Pakete braucht sie nicht.
Welche Varianten hat Lichtkugel?
4 Varianten, Hero mit Kugel daneben, Aufgehende Kugel, Hervorgehobene Karte und Hinter einem Call to Action.
Kann ein KI-Assistent Lichtkugel einbauen?
Ja. Über den MCP-Server der aiw CLI finden Claude, Cursor, GitHub Copilot, Windsurf, Codex und Gemini Lichtkugel mit aiw_components und installieren sie mit aiw_add @ai-website/glow-orb.