IrisBackgroundsFiber Burst
Fiber Burst
A fan of thin blue-white strands bursting rightward from a single warm-lit chip at the left edge, each carrying its own travelling pulse of light — a direct build of the reference photo.
Fiber Burst
A small chip sits lit at the left edge, warm against everything around it, a few bare leads reaching back into the dark behind it. From its face two dozen thin, near-straight strands fan out to the right, each at its own slight angle, thinning and dimming the further out it travels — the way a bundle of fibre-optic cable looks lit from one end and photographed in the dark.
The animation is the point: every strand carries its own narrow band of light travelling continuously outward along it, away from the chip, at its own speed and phase, so the bundle never pulses in sync and the light visibly originates at the source rather than just sitting lit. A soft glow independently gathers wherever the cursor rests — the one thing a field built this plainly can answer back with.
Install
No installation needed — self-contained, paste-in code.
Usage
Drop it straight into a page.
import { FiberBurstField } from "./FiberBurstField";
export default function Example() {
return (
// Fills its nearest positioned ancestor (it renders itself `absolute
// inset-0`) — give it a sized, relatively positioned box.
<div className="relative isolate h-[32rem] w-full overflow-hidden rounded-2xl">
<FiberBurstField />
</div>
);
}Component
The real source, exactly as it ships — multiple files, kept together.
"use client";
import { useEffect, useRef } from "react";
import { mountShaderSurface } from "@/lib/shader-surface";
/**
* A live WebGL burst of light from a single lit source at the left edge —
* a small warm-glowing chip with a few bare leads reaching back into the
* dark, and from its face a fan of two dozen thin, near-straight blue-white
* strands running out to the right, each at its own slight angle. A direct
* build of the reference photo (a chip firing a bundle of fibre-optic
* light into the dark), not a variation on the rest of the catalogue's
* mood: warm at the source, cooling to blue-white the moment the light
* leaves it.
*
* The animation IS the point: every strand carries a narrow band of light
* travelling continuously outward along it, away from the source, so the
* light visibly originates there and keeps flowing rather than just
* sitting lit — each strand at its own speed and phase, so the bundle
* never pulses in sync. The whole fan also thins and dims the further out
* it travels, the way real fibre attenuates.
*
* Interactive: a soft glow independently gathers wherever the cursor
* rests, the one thing a field like this can answer back with.
*
* One of the reusable background fields (`ShaftField`, `SignalGridField`,
* …). Drop it into any `position: relative`/`isolate` parent — it fills
* the box. Built on `lib/shader-surface.ts`, so every degradation path is
* already handled: no WebGL, a blocked or lost context, a hidden tab, or
* `prefers-reduced-motion` all leave the CSS `.iris-fiberburstfield__floor`
* underneath visible.
*
* Reading guard: when `guardSelector` resolves to an element, the field
* measures that block every frame and clamps its own luminance under a
* ceiling inside that region (hue and saturation untouched). `null` (the
* default) turns the guard off — for decorative use where nothing sits on
* top.
*/
/* Palette, sRGB 0–1. Uniforms, not tokens — the warm source against a cool
beam lives nowhere in the accent ramp. */
const PALETTE: Record<string, [number, number, number]> = {
u_ground: [0.008, 0.009, 0.013], // near-black ground the beams travel through
u_halo: [0.09, 0.15, 0.24], // the strands' soft outer bleed
u_body: [0.42, 0.62, 0.86], // the body of each strand
u_core: [0.88, 0.95, 1.0], // the hot near-white centreline and pulses
u_chip: [1.0, 0.87, 0.62], // the source itself — warm, not blue
};
const FRAG = `
uniform vec2 u_res;
uniform float u_time;
uniform float u_scale;
uniform vec3 u_pointer; /* x, y (0 bottom .. 1 top), presence 0..1 */
uniform vec3 u_ground;
uniform vec3 u_halo;
uniform vec3 u_body;
uniform vec3 u_core;
uniform vec3 u_chip;
uniform vec4 u_readA;
uniform float u_guard;
const int N_RAYS = 22;
const float MAX_ANGLE = 0.56;
const float MAX_LEN = 1.7;
const float REPEATS = 6.0;
const float TAU = 6.2831853;
void main() {
vec2 res = u_res / u_scale;
vec2 uv = gl_FragCoord.xy / u_scale / res; /* 0..1, y up */
vec2 sc = vec2(res.x / max(res.y, 1.0), 1.0);
vec2 q = uv * sc;
vec2 srcUV = vec2(0.115, 0.52);
vec2 src = srcUV * sc;
vec3 col = u_ground;
/* a soft ambient wash around the source, under the individual strands */
col += u_halo * exp(-length(q - src) / 0.62) * 0.10;
for (int i = 0; i < N_RAYS; i++) {
float fi = (float(i) + 0.5) / float(N_RAYS); /* 0..1 */
float s = fi * 2.0 - 1.0; /* -1..1 */
float h1 = fract(sin(fi * 91.7 + 1.0) * 43758.5453);
float h2 = fract(sin(fi * 131.3 + 4.7) * 12543.233);
float h3 = fract(sin(fi * 57.9 + 9.1) * 39217.113);
float spread = sign(s) * pow(abs(s), 0.82);
float angle = spread * MAX_ANGLE + (h1 - 0.5) * 0.05;
vec2 dir = vec2(cos(angle), sin(angle));
vec2 rel = q - src;
float t = max(dot(rel, dir), 0.0);
float perp = length(rel - dir * t);
float along = clamp(t / MAX_LEN, 0.0, 1.0);
float speed = 0.22 + h2 * 0.28;
float phase = h3 * TAU;
float pulse = pow(max(0.0, cos(along * REPEATS * TAU - u_time * speed * TAU + phase)), 16.0);
float atten = exp(-along * 1.15);
float bright = (0.35 + 0.65 * h2) * atten;
float coreW = mix(0.0045, 0.0011, along);
float bodyW = mix(0.016, 0.0038, along);
float haloR = mix(0.06, 0.016, along);
float coreG = exp(-perp * perp / (coreW * coreW));
float bodyG = exp(-perp * perp / (bodyW * bodyW));
float haloG = exp(-perp / haloR);
col += u_halo * haloG * bright * 0.30;
col += u_body * bodyG * bright * (0.45 + 0.55 * pulse);
col += u_core * coreG * bright * (0.30 + 0.85 * pulse);
}
/* the chip itself: a small warm-lit source block with a soft bleed and a
few bare leads reaching left into the dark behind it */
vec2 chipHalf = vec2(0.02, 0.065);
vec2 cd = abs(q - src) - chipHalf;
float chipDist = length(max(cd, 0.0)) + min(max(cd.x, cd.y), 0.0);
float chipFace = smoothstep(0.006, -0.006, chipDist);
float chipGlow = exp(-max(chipDist, 0.0) / 0.10);
col = mix(col, u_chip, chipFace);
col += u_chip * chipGlow * 0.55;
float leftEdge = src.x - chipHalf.x;
float tickStart = leftEdge - 0.055;
for (int i = 0; i < 5; i++) {
float ty = src.y + (float(i) - 2.0) * 0.024;
float tickDist = abs(q.y - ty);
float xMask = smoothstep(tickStart - 0.004, tickStart + 0.004, q.x)
* smoothstep(leftEdge + 0.004, leftEdge - 0.004, q.x);
col += u_chip * exp(-tickDist * tickDist / 0.0009) * xMask * 0.22;
}
/* the pointer's own small glow — the one thing this field answers back */
vec2 toP = q - u_pointer.xy * sc;
float spot = u_pointer.z * exp(-dot(toP, toP) / (0.045 * 0.045));
col += u_core * spot * 0.35;
col = max(col, 0.0);
/* ---- the reading guard (see TileField for the full rationale) ---- */
vec2 rd = abs(uv - u_readA.xy) / max(u_readA.zw, vec2(0.02));
float m = mix(max(rd.x, rd.y), length(rd), 0.4);
float band = 1.0 - smoothstep(0.72, 2.1, m);
col = mix(col, holdUnder(col, 0.09), band * u_guard);
col += (bayer8(gl_FragCoord.xy) - 0.5) * (2.2 / 255.0);
gl_FragColor = vec4(col, 1.0);
}
`;
export interface FiberBurstFieldProps {
className?: string;
/**
* CSS selector for the block the reading guard should keep readable,
* resolved against `document`. `null` (the default) turns the guard off.
*/
guardSelector?: string | null;
}
export function FiberBurstField({
className,
guardSelector = null,
}: FiberBurstFieldProps) {
const canvasRef = useRef<HTMLCanvasElement>(null);
useEffect(() => {
const canvas = canvasRef.current;
if (!canvas) return;
const guardOn = guardSelector != null;
let guardEl: Element | null | undefined;
const readGuardEl = () => {
if (guardEl === undefined) {
guardEl = guardOn ? document.querySelector(guardSelector as string) : null;
}
return guardEl;
};
return mountShaderSurface(canvas, {
fragment: FRAG,
uniforms: [...Object.keys(PALETTE), "u_readA", "u_guard"],
onInit: (gl, u) => {
for (const name of Object.keys(PALETTE)) {
if (u[name]) gl.uniform3fv(u[name], PALETTE[name]);
}
if (u.u_readA) gl.uniform4f(u.u_readA, 0.5, 0.5, 0.44, 0.32);
if (u.u_guard) gl.uniform1f(u.u_guard, guardOn ? 1 : 0);
},
onFrame: (gl, u, s) => {
if (!guardOn || !u.u_readA) return;
let cx = 0.5, cy = 0.5, hw = 0.44, hh = 0.32;
const el = readGuardEl();
const { rect } = s;
if (el && rect.width > 0 && rect.height > 0) {
const r = el.getBoundingClientRect();
const padX = rect.width * 0.09;
const padY = rect.height * 0.11;
cx = (r.left + r.width / 2 - rect.left) / rect.width;
cy = 1 - (r.top + r.height / 2 - rect.top) / rect.height;
hw = (r.width / 2 + padX) / rect.width;
hh = (r.height / 2 + padY) / rect.height;
}
gl.uniform4f(u.u_readA, cx, cy, hw, hh);
},
onPainted: () => canvas.setAttribute("data-shader", "on"),
/* No onIdle — same contract as ShaftField / SignalGridField: once
painted, the last frame stays on screen while the surface is
parked off-view, so scrolling away and back does not crossfade to
the static floor. A lost context still clears it below. */
onLost: () => canvas.removeAttribute("data-shader"),
maxPixels: 2_000_000,
dprCap: 1.5,
});
}, [guardSelector]);
return (
<div
className={`absolute inset-0 overflow-hidden${className ? ` ${className}` : ""}`}
aria-hidden="true"
>
<div className="absolute inset-0 [background:radial-gradient(_9%_16%_at_11%_52%,oklch(0.9_0.06_80)_0%,oklch(0.7_0.1_60_/_0.6)_45%,transparent_78%_),conic-gradient(_from_250deg_at_11%_52%,oklch(0.55_0.07_230_/_0.5)_0deg,transparent_55deg,transparent_305deg,oklch(0.55_0.07_230_/_0.5)_360deg_),radial-gradient(_160%_130%_at_11%_52%,oklch(0.14_0.03_230_/_0.4)_0%,transparent_55%_),oklch(0.04_0.005_240)]" />
<canvas ref={canvasRef} className="absolute inset-0 w-full h-full opacity-0 transition-opacity duration-[--duration-slow] ease-[--ease-standard] data-[shader=on]:opacity-100" />
</div>
);
}Custom work
Need one that isn't in the catalogue?
Describe what you're after and I'll reply by email — no promise on turnaround yet, this is a new channel, not a service with a set price or queue.
Fardin Omor Afnan
Reads and answers every request himself