Dozens of fine light strands flowing together in a silky iridescent wave.
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<SilkFlow /> inside your own <Canvas>.import { useMemo, useRef } from 'react';
import { useFrame } from '@react-three/fiber';
import * as THREE from 'three';
import type { Group } from 'three';
const COUNT = 64;
class StrandCurve extends THREE.Curve<THREE.Vector3> {
amp: number;
phase: number;
yoff: number;
zoff: number;
constructor(amp: number, phase: number, yoff: number, zoff: number) {
super();
this.amp = amp;
this.phase = phase;
this.yoff = yoff;
this.zoff = zoff;
}
getPoint(t: number, target = new THREE.Vector3()) {
const x = (t - 0.5) * 7;
const env = Math.cos((t - 0.5) * Math.PI); // taper the ends
const y = Math.sin(x * 0.85 + this.phase) * this.amp * env + this.yoff;
const z = this.zoff + Math.cos(x * 0.6 + this.phase) * 0.2;
return target.set(x, y, z);
}
}
export default function SilkFlow({ scale = 1 }: { color?: string; scale?: number }) {
const g = useRef<Group>(null);
const strands = useMemo(() => {
const c1 = new THREE.Color('#22e0ff');
const c2 = new THREE.Color('#8a5cff');
const c3 = new THREE.Color('#ff2fd0');
const tmp = new THREE.Color();
return Array.from({ length: COUNT }, (_, i) => {
const t = i / (COUNT - 1);
if (t < 0.5) tmp.copy(c1).lerp(c2, t * 2);
else tmp.copy(c2).lerp(c3, (t - 0.5) * 2);
const amp = 0.7 + Math.sin(i * 1.3) * 0.5;
const phase = i * 0.11;
const yoff = (t - 0.5) * 0.5;
const zoff = (t - 0.5) * 0.9;
const geo = new THREE.TubeGeometry(new StrandCurve(amp, phase, yoff, zoff), 140, 0.006, 6, false);
return { geo, color: tmp.getStyle() };
});
}, []);
useFrame((state) => {
if (!g.current) return;
g.current.rotation.z = Math.sin(state.clock.elapsedTime * 0.15) * 0.06;
g.current.rotation.y = Math.sin(state.clock.elapsedTime * 0.1) * 0.12;
});
return (
<group ref={g} scale={scale}>
{strands.map((s, i) => (
<mesh key={i} geometry={s.geo}>
<meshBasicMaterial
color={s.color}
toneMapped={false}
transparent
opacity={0.85}
blending={THREE.AdditiveBlending}
depthWrite={false}
/>
</mesh>
))}
</group>
);
}