Chrome Blob
A metallic sphere that distorts as it turns, with studio reflections.
- Price
- USD 10, all access
- Built with
- React Three Fiber
A slow gradient background in three colours.
One GLSL shader on a full-width plane, in colours you choose. It runs at a fraction of the cost of a video background.
The whole file is below. Install the packages it imports, add the file to your project and import it.
"use client";
/**
* Aurora — a slow, folded gradient background in three colours.
*
* Self-contained: three, @react-three/fiber. One fragment shader on a
* full-screen plane; no textures, no assets.
*
* <Aurora colorA="#c35a2c" colorB="#1b1512" colorC="#f5cb73" speed={0.5} />
*/
import { Canvas, useFrame } from "@react-three/fiber";
import { useMemo, useRef } from "react";
import { Color, type ShaderMaterial } from "three";
export type AuroraProps = {
colorA?: string;
colorB?: string;
colorC?: string;
speed?: number;
className?: string;
};
const vertex = /* glsl */ `
varying vec2 vUv;
void main() {
vUv = uv;
gl_Position = vec4(position, 1.0);
}
`;
// Simplex-style value noise, folded twice, so the gradient looks like
// bands of light rather than a blurred blob.
const fragment = /* glsl */ `
precision highp float;
varying vec2 vUv;
uniform float uTime;
uniform vec3 uA;
uniform vec3 uB;
uniform vec3 uC;
vec2 hash(vec2 p) {
p = vec2(dot(p, vec2(127.1, 311.7)), dot(p, vec2(269.5, 183.3)));
return -1.0 + 2.0 * fract(sin(p) * 43758.5453123);
}
float noise(vec2 p) {
vec2 i = floor(p);
vec2 f = fract(p);
vec2 u = f * f * (3.0 - 2.0 * f);
return mix(
mix(dot(hash(i + vec2(0.0, 0.0)), f - vec2(0.0, 0.0)), dot(hash(i + vec2(1.0, 0.0)), f - vec2(1.0, 0.0)), u.x),
mix(dot(hash(i + vec2(0.0, 1.0)), f - vec2(0.0, 1.0)), dot(hash(i + vec2(1.0, 1.0)), f - vec2(1.0, 1.0)), u.x),
u.y
);
}
void main() {
vec2 p = vUv * vec2(2.2, 1.4);
float t = uTime * 0.12;
float n1 = noise(p * 1.6 + vec2(t, -t * 0.7));
float n2 = noise(p * 3.1 - vec2(t * 0.5, t));
float band = sin((vUv.y + n1 * 0.35 + n2 * 0.12) * 6.0 + t * 2.0);
float band2 = sin((vUv.y * 1.7 - n2 * 0.5 + n1 * 0.2) * 9.0 - t * 3.0);
float m = smoothstep(-0.7, 0.7, band) * 0.75 + smoothstep(-0.4, 0.9, band2) * 0.25;
vec3 col = mix(uB, uA, m);
float glow = smoothstep(0.2, 1.0, n1 * 0.5 + 0.5) * smoothstep(0.0, 0.6, 1.0 - vUv.y);
col = mix(col, uC, glow * 0.85);
col += uC * pow(max(0.0, band2), 6.0) * 0.18;
// Vignette so it sits under text.
float v = smoothstep(1.3, 0.3, distance(vUv, vec2(0.5)));
col *= 0.65 + 0.35 * v;
gl_FragColor = vec4(col, 1.0);
}
`;
function Plane({ colorA, colorB, colorC, speed }: Required<Omit<AuroraProps, "className">>) {
const material = useRef<ShaderMaterial>(null);
const uniforms = useMemo(
() => ({
uTime: { value: 0 },
uA: { value: new Color(colorA) },
uB: { value: new Color(colorB) },
uC: { value: new Color(colorC) },
}),
// Uniform objects are created once; colours are written below.
// eslint-disable-next-line react-hooks/exhaustive-deps
[],
);
useFrame((_, delta) => {
if (!material.current) return;
material.current.uniforms.uTime.value += delta * speed;
material.current.uniforms.uA.value.set(colorA);
material.current.uniforms.uB.value.set(colorB);
material.current.uniforms.uC.value.set(colorC);
});
return (
<mesh>
<planeGeometry args={[2, 2]} />
<shaderMaterial ref={material} vertexShader={vertex} fragmentShader={fragment} uniforms={uniforms} />
</mesh>
);
}
export function Aurora({
colorA = "#c35a2c",
colorB = "#1b1512",
colorC = "#f5cb73",
speed = 0.5,
className = "",
}: AuroraProps) {
return (
<div className={className} style={{ width: "100%", height: "100%", minHeight: 240 }}>
<Canvas dpr={[1, 1.5]} gl={{ antialias: false, preserveDrawingBuffer: true }} orthographic camera={{ position: [0, 0, 1] }}>
<Plane colorA={colorA} colorB={colorB} colorC={colorC} speed={speed} />
</Canvas>
</div>
);
}
export default Aurora;
Inside
Install
npm install three @react-three/fiber
One file.
A metallic sphere that distorts as it turns, with studio reflections.
12,000 points that move away from the cursor.
Five metal rings on tilted orbits, each turning at its own speed.
What you get, what it runs on, what it costs to run and what the licence allows.
One React component file per element, plus any shader or asset files it needs. Members of a series also get the small engine file they share. Free elements are copied from the page. Pro elements are a download after one payment of USD 10, which unlocks all of them. Each element imports only public packages, which are listed on its page.
React 19. The 3D and shader elements use three.js through React Three Fiber. The 2D ones use Framer Motion or plain CSS and canvas. They work in Next.js, Vite, Remix and any other React setup. Framer and Webflow users can embed an element as a code component.
Yes. Every element exposes its look as props, the same controls shown on its page. Anything beyond the props is yours to edit in the file.
Yes. Every element page has a Save frame button that downloads the current frame as a PNG at the size shown. Make the browser window large for a print-size still. For motion, record the page or ask us for a rendered clip. The licence covers web, print, decks and video, for your own work and your clients' work.
The 3D elements mount when they scroll into view and unmount when they leave, so an element off screen costs nothing. The shader backgrounds cost a fraction of a video background. The 2D elements are a few kilobytes.
Free elements are MIT. Use them anywhere, including client work. Pro elements are licensed to you for unlimited projects of your own and your clients'. You may not resell or redistribute the source itself.
Yes. A custom element, such as your product in 3D or a branded shader, is a small project quoted up front. All-access members are asked first about what we build next.