30 WebGL elements for interfaces that don't look vibe-coded.
Raymarched orbs, liquid metal, holographic foil, caustics, real glass refraction, volumetric fog. One shared GL context, zero dependencies, 14 kB gzipped, MIT.
Live demo and playground: https://aura.bles-software.com
<script src="https://aura.bles-software.com/aura.min.js"></script>
<aura-fx effect="plasma-orb" size="120"></aura-fx>That is the whole integration. The tag registers itself and works in plain HTML, Vue, Svelte, Astro and React 19. React 18 has a wrapper, see below.
CDN — one file, no build step:
<script src="https://aura.bles-software.com/aura.min.js"></script>Bundler:
npm install github:stas4000/aura-fximport 'aura-fx'; // registers <aura-fx> and <aura-text>
import { AuraFX } from 'aura-fx/react'; // optional React 18 wrapper<!-- an agent thinking state -->
<aura-fx effect="plasma-orb" size="64"></aura-fx>
<!-- a hero background -->
<aura-fx effect="aurora" style="position:absolute;inset:0"></aura-fx>
<!-- a gauge, driven from your code -->
<aura-fx effect="progress-orb" size="120" progress="0.62"></aura-fx>
<!-- live, selectable text -->
<aura-text effect="scramble">Deploying</aura-text>Update at runtime with an attribute, or imperatively:
el.setAttribute('progress', '0.8');
el.update({ progress: 0.8, speed: 1.5 }); // skips attribute parsing
document.querySelector('aura-text').replay(); // re-run a one-shot text effect| Attribute | Applies to | Default | What it does |
|---|---|---|---|
effect |
both | plasma-orb / shimmer |
Which of the 30 to render |
size |
aura-fx |
— | Shorthand for equal width and height |
speed |
both | per effect | Time multiplier. 0 freezes it |
intensity |
aura-fx |
1 |
Effect-specific amplitude |
progress |
aura-fx |
0 |
0..1, for the gauges and meters |
seed |
aura-fx |
0 |
Varies the random layout |
color color2 color3 |
aura-fx |
white / blue / pink | Hex palette, highlight then two accents |
paused |
aura-fx |
— | Freeze on the current frame |
React 19 renders custom elements directly, so no wrapper is needed:
<aura-fx effect="liquid-orb" size="140" />React 18 and older do not forward non-string props or call element methods:
import { AuraFX, AuraText } from 'aura-fx/react';
<AuraFX effect="voice-orb" size={140} progress={level} />
<AuraText effect="glitch">SYSTEM</AuraText>Orbs — plasma-orb neural-orb liquid-orb voice-orb
Backgrounds — aurora starfield grid-tunnel volumetric-fog silk dot-wave
Surfaces — liquid-metal glass-refract holo-foil beam-border caustics
Interaction — magnet-glow ripple shimmer gooey spotlight
Feedback — pulse-ring progress-orb wave-bars spark-line raymarch-cube particle-burst
Text — shimmer scramble glitch wave (on <aura-text>)
One GL context for the whole page. Browsers cap live WebGL contexts at around 16 and silently kill the oldest one past that. A component library is exactly the thing that trips it: put 30 effects on a page and half of them go black. aura renders every instance through a single shared context and blits the result into each element's own 2D canvas. The demo page runs all 30 at once.
Off-screen means off. Each element watches itself with an
IntersectionObserver and stops rendering when it scrolls away. Device pixel
ratio is capped at 2.
It respects the system. prefers-reduced-motion freezes every effect on a
composed still frame rather than removing it. Text effects stay real text:
selectable, searchable and readable by a screen reader, because they are DOM, not
a canvas. Without WebGL2, elements fall back to a CSS gradient instead of an
empty box.
No dependencies. No three.js, no GSAP, no framework. 14 kB gzipped, all in.
Every effect is a fragment shader that ends in vec4 fx(vec2 uv, vec2 p). The
runtime supplies the version header, the uniforms and a library of noise, SDF and
palette helpers. Register your own before first paint:
import { effects } from 'aura-fx';
effects['my-thing'] = {
title: 'My thing', group: 'Custom', blurb: '', defaults: { speed: 1 },
glsl: `vec4 fx(vec2 uv, vec2 p){
return vec4(u_c2 * smoothstep(0.5, 0.0, length(p) + 0.2*sin(u_t)), 1.0);
}`,
};Uniforms available in every shader: u_res u_t u_mouse u_hover u_prog
u_amp u_seed u_c1 u_c2 u_c3. Helpers: rot hash11/21/22/31 noise
fbm fbm2 fbm3 pal sdSphere sdBox sdTorus sdRoundBox sdRoundRect
smin tone. PRELUDE and EPILOGUE are exported if you want to read them.
npx playwright install chromium # once
npm run build # dist/aura.min.js (IIFE, window.Aura) + dist/aura.esm.min.js
npm test # compiles all 30 in headless Chromium and reads the pixels back
node verify.mjs # renders the site and reports what a visitor actually gets
node og.mjs # re-renders site/og.png from the live components
node capture.mjs # frame-stepped launch video, never a screen recordingSet CHROME_PATH=/path/to/chrome if you want to point the tests at a Chromium
you already have instead of Playwright's own download.
npm test is not a unit test. It drives a real browser, compiles every shader on
a real GL pipeline, asserts each one paints a non-trivial image, and asserts the
frame loop is actually advancing. A GLSL typo is invisible to anything less.
MIT. Use it in anything, including commercial work.
Built by Bles Software.
0 comments
log in to comment.