Hundreds of fine colored rays bursting from a dark center, slowly turning.
Tip: pick a preset, use the custom picker, or paste your brand hex to preview this element in your colors. Some elements use a fixed multi-color palette.
three @react-three/fiber @react-three/drei<HypnoRays /> inside your own <Canvas>.import { useMemo, useRef } from 'react';
import { useFrame } from '@react-three/fiber';
import * as THREE from 'three';
import type { LineSegments } from 'three';
const RAYS = 220;
export default function HypnoRays({ scale = 1 }: { color?: string; scale?: number }) {
const ref = useRef<LineSegments>(null);
const { positions, colors } = useMemo(() => {
const pos = new Float32Array(RAYS * 2 * 3);
const col = new Float32Array(RAYS * 2 * 3);
const pal = [
new THREE.Color('#22e0ff'),
new THREE.Color('#8a5cff'),
new THREE.Color('#ff2fd0'),
new THREE.Color('#ff8a3d'),
];
for (let i = 0; i < RAYS; i++) {
const a = (i / RAYS) * Math.PI * 2;
const inner = 0.3;
const outer = 5;
pos.set([Math.cos(a) * inner, Math.sin(a) * inner, 0, Math.cos(a) * outer, Math.sin(a) * outer, 0], i * 6);
const c = pal[i % pal.length];
// dark at the center, bright at the rim
col.set([c.r * 0.05, c.g * 0.05, c.b * 0.05, c.r, c.g, c.b], i * 6);
}
return { positions: pos, colors: col };
}, []);
useFrame((_, dt) => {
if (ref.current) ref.current.rotation.z += dt * 0.05;
});
return (
<lineSegments ref={ref} scale={scale}>
<bufferGeometry>
<bufferAttribute attach="attributes-position" args={[positions, 3]} />
<bufferAttribute attach="attributes-color" args={[colors, 3]} />
</bufferGeometry>
<lineBasicMaterial
vertexColors
toneMapped={false}
transparent
opacity={0.9}
blending={THREE.AdditiveBlending}
depthWrite={false}
/>
</lineSegments>
);
}