@anarkisti/igyb
v0.5.0
Published
Tree-shakeable repeating & generative backgrounds — geometric tiles and WebGL generative art, framework-agnostic with a Svelte wrapper.
Maintainers
Readme
@anarkisti/igyb
Tree-shakeable repeating & generative backgrounds — geometric tiles and WebGL generative art. A framework-agnostic core (Canvas2D + WebGL) with a thin Svelte wrapper.
▶ Live playground →
yarn add @anarkisti/igybVanilla
import { flowField } from '@anarkisti/igyb/core';
const bg = flowField(document.querySelector('#hero')!, { theme: 'neon', interactive: true });
bg.start();
// bg.update({ theme: 'terminal' }); // live re-theme
// bg.destroy();Svelte
<script>
import Background from '@anarkisti/igyb/svelte';
import { plasma } from '@anarkisti/igyb/core';
</script>
<div style="height: 100vh">
<Background pattern={plasma} options={{ theme: 'ink', interactive: true }} />
</div>Web component (any framework)
<igyb-background> resolves a pattern by name from the registry — drop it into plain HTML,
React, Vue, anything:
import { register } from '@anarkisti/igyb/element';
register(); // defines <igyb-background> once<igyb-background
pattern="gradientMesh"
theme="sunset"
interactive
style="display:block; inline-size:100%; block-size:100vh"
></igyb-background>React
Use <igyb-background> above, or this ~20-line wrapper that takes a tree-shakeable factory:
import { useEffect, useRef } from 'react';
import type { AnyBackgroundFactory, BaseOptions } from '@anarkisti/igyb/core';
export function Background({
pattern,
options,
paused
}: {
pattern: AnyBackgroundFactory;
options?: BaseOptions & Record<string, unknown>;
paused?: boolean;
}) {
const host = useRef<HTMLDivElement>(null);
const bg = useRef<ReturnType<AnyBackgroundFactory>>();
useEffect(() => {
bg.current = pattern(host.current!, options);
if (!paused) bg.current.start();
return () => bg.current?.destroy();
}, [pattern]); // eslint-disable-line react-hooks/exhaustive-deps
useEffect(() => bg.current?.update(options ?? {}), [options]);
useEffect(() => (paused ? bg.current?.stop() : bg.current?.start()), [paused]);
return <div ref={host} style={{ position: 'relative', width: '100%', height: '100%' }} />;
}Patterns
| Pattern | Import (@anarkisti/igyb/core) | Renderer | Category |
| ------------- | ------------------------------- | -------- | ---------- |
| Flow field | flowField | WebGL | Generative |
| Plasma | plasma | WebGL | Generative |
| Gradient mesh | gradientMesh | WebGL | Generative |
| Aurora | aurora | WebGL | Generative |
| Metaballs | metaballs | WebGL | Generative |
| Voronoi | voronoi | WebGL | Generative |
| Particles | particles | Canvas2D | Generative |
| Ripple | ripple | Canvas2D | Generative |
| Matrix rain | matrixRain | Canvas2D | Generative |
| Starfield | starfield | Canvas2D | Generative |
| Truchet | truchet | Canvas2D | Geometric |
| Hex | hex | Canvas2D | Geometric |
| Isometric | iso | Canvas2D | Geometric |
| Dot grid | dotGrid | Canvas2D | Geometric |
| Wave lines | waveLines | Canvas2D | Geometric |
| Low poly | lowPoly | Canvas2D | Geometric |
| Glyph tile | glyphTile | Canvas2D | Geometric |
Overlays for layering: grain, vignette, scanlines, spotlight.
Deep imports (@anarkisti/igyb/patterns/flow-field) keep bundles minimal even without
tree-shaking. Every pattern also takes theme, animate, speed, interactive
(true | 'fine'), pointerSource, pointerSmoothing, themeTransition, reducedMotion,
autoPause and dpr. Interactive patterns track multitouch (pointer.points); the loop
auto-pauses while the tab is hidden or the host scrolls offscreen. Set themeTransition
(seconds) to crossfade palettes on a theme change, and pattern authors can read env.scroll
(window scroll progress) for scroll-linked effects. Themes: ink (default), neon, pastel,
terminal, mono, paper, halo, sunset, ocean, cyberpunk, forest, or a custom
Palette.
Composing layers
Stack patterns into one background with per-layer opacity and blend — WebGL and Canvas2D mix freely, since each layer keeps its own canvas:
import { layers, aurora, particles, grain, vignette } from '@anarkisti/igyb/core';
const bg = layers(
[
{ pattern: aurora },
{ pattern: particles, blend: 'screen', opacity: 0.6 },
{ pattern: grain, blend: 'overlay', opacity: 0.5 },
{ pattern: vignette, options: { animate: false } }
],
{ theme: 'sunset' } // shared across every layer
)(document.querySelector('#hero')!);
bg.start();
const poster = bg.capture(); // data URL — a static first-frame for SSR/LCPbg.capture() works on any background (single or layered). For a gallery or a randomize
button, @anarkisti/igyb/registry lists every pattern with metadata; @anarkisti/igyb/element
ships an <igyb-background> custom element.
Theming from CSS variables
For token-driven apps, read the palette straight from CSS custom properties and pass theme
as a thunk. On a light/dark flip, call bg.refresh() — it re-invokes the thunk and
repaints in place, no teardown:
import { glyphTile, paletteFromCSS } from '@anarkisti/igyb/core';
const map = { bg: '--surface', fg: '--ink', accents: ['--accent'] };
const bg = glyphTile(el, { theme: () => paletteFromCSS(map) });
bg.start();
// when your theme toggles (after the new tokens land on the element):
bg.refresh();Drawing your own glyph/marks? The glyphTile callback receives the resolved palette, and
@anarkisti/igyb/core exports small color helpers so you don't re-roll them:
import { lighten, mix, toRgb } from '@anarkisti/igyb/core';
glyphTile(el, {
glyph(ctx, size, i, { palette, highlight }) {
ctx.strokeStyle = mix(palette.fg, lighten(palette.fg, 0.8), highlight); // reacts to the pointer
ctx.strokeRect(-size / 4, -size / 4, size / 2, size / 2);
}
});toRgb / toRgbString, mix, lighten, darken accept hex or rgb() strings.
Authoring
import { defineCanvas2D } from '@anarkisti/igyb/core';
export const stripes = defineCanvas2D<{ width?: number }>({
defaults: { width: 20 },
frame({ ctx, surface, palette, time, options }) {
/* draw one frame */
}
});defineWebGL is the same shape with a WebGL2 gl context. Cache resources in env.state.
