Dependency-free WebGL studio for generating backgrounds, wallpapers, Open Graph images, and live embeddable canvases.
One HTML file. No build step. No backend state. No runtime dependencies.
- WebGL1 fragment-shader renderer with 24 field engines, including a quasicrystal, paper marbling, string-art caustics, whirling pursuit polygons, Chladni plate figures, Cassini ovals, topographic contours, and a von Karman vortex street.
- Kaleidoscope symmetry modifier: fold any field into an N-fold radial mandala.
- Layers: stack up to three engines, each blending onto everything under it with multiply / screen / add / difference / overlay.
- Math lenses: bend the plane through 12 conformal maps — z², 1/z, Möbius, Droste, hyperbolic, Julia, z³, e^z, sin z, Joukowski, Newton basins, and the SL(2,ℤ) modular fold — plus Ground, which is a camera rather than a map: it tips the plane away so any engine recedes to a horizon.
- Material finishes: glass, metal, sand, liquid, and molten relighting, plus paint — impasto oil, dabs laid along the field's contours with bristle ridges, lit as thick paint on a toned canvas.
- Square, hex, ASCII, halftone, ordered-dither, and glitch surface modes.
- Preset palettes plus shareable custom four-stop gradients, with a draggable colour editor: saturation/brightness pad, hue strip, HSB and RGB sliders, hex, and harmony schemes that rebuild the whole ramp from one hue.
- Optional image melt: uploaded image luminance drives the field.
- Text in living colour: fill a word or brand name with the field, with a 9-font picker and a background-colour choice; persists locally and travels in share links.
- Exact-size export as PNG, JPG, or WebP.
- Self-contained HTML export: copy the piece as a complete, dependency-free file with the shaders inlined — no iframe, no server.
- Clip recording through
MediaRecorder. - Undo across the session, with a Recent shelf of every state you passed through as thumbnails.
- Explore: a fresh shelf of generated pieces on every open, rendered on the spot — plus a seed of the day, one piece per UTC day, the same for everyone.
- URL hash format that round-trips every piece without server storage.
- Cloudflare Worker API and Streamable HTTP MCP endpoint.
Each thumbnail opens the live piece in the studio.
git clone https://github.com/enonforetsam/fluid
cd fluid
open index.htmlFor the Worker routes, security headers, JSON API, and MCP endpoint:
npm run dev # http://localhost:8787Use the script rather than a bare npx wrangler dev. The assets directory is the repo root,
so wrangler's own .wrangler/state writes land inside the tree it is watching — it sees them,
reloads, writes again, and reloads about once every four seconds forever, which makes requests
hang mid-reload. The script keeps that state outside the repo with --persist-to.
Two npm packages ship from this repo. fluid-bg
is the drop-in background — it renders natively on a canvas in your page (~15 KB gz, no iframe):
<script src="https://cdn.jsdelivr.net/npm/fluid-bg@0.3"></script>
<fluid-bg fixed hash="#p=0.5,1.5,5.5,0.03,1,10,0,0,18,0,0,1.7778"></fluid-bg>React: npm i fluid-bg, then import FluidBg from 'fluid-bg/react'. Keep the page
background transparent when using fixed — see fluid-bg/README.md.
fluid-core is the raw engine library
underneath (createFluid(el, {…}), zero dependencies, TypeScript types) — see
fluid-core/README.md.
No npm at all? A plain iframe still works:
<iframe
src="https://fluid.krackeddevs.com/#p=0.5,1.5,5.5,0.03,1,10,0,0,18,0,0,1.7778,0,1,1"
title="Fluid background"
loading="lazy"
style="border:0;width:100%;height:100%">
</iframe>The embed flag makes the canvas fill the iframe without the studio UI.
Everything in this repo is MIT. What is not in the repo is befluid.xyz's data: the published pieces, their authors, the media and the admin secrets. Clone it and you have the whole studio; run the Worker with your own bindings and you have your own instance.
The share-hash contract (the #p= fields, append-only) is the project's real API and is
specified in docs/ARCHITECTURE.md.
curl "https://fluid.krackeddevs.com/api/piece?look=borealis"
curl "https://fluid.krackeddevs.com/api/piece?field=flow&palette=sunset&warp=4"
curl "https://fluid.krackeddevs.com/api/piece?field=cellular&colors=0a0a1a,3a1f7a,c84fe0,ffe1f5"
curl "https://fluid.krackeddevs.com/api/looks"
curl "https://fluid.krackeddevs.com/api/today" # the day's piece
curl "https://fluid.krackeddevs.com/api/today?date=2026-01-01" # replay any day/today is a permalink that opens the day's piece in the studio.
MCP clients that support Streamable HTTP can connect to:
https://fluid.krackeddevs.com/mcpClaude Code:
claude mcp add --transport http fluid https://fluid.krackeddevs.com/mcpOn claude.ai (web, desktop, or mobile): Settings → Connectors → Add custom
connector → paste the /mcp URL. No auth. Tools: create_piece,
get_embed_code, list_looks, get_seed_of_the_day, decode_link.
AI agents without MCP can read the whole integration surface from
/llms.txt.
| File | Purpose |
|---|---|
index.html |
Complete studio app: UI, WebGL shader, state, export, recording, sharing |
worker.js |
Cloudflare Worker: static assets, security headers, API, MCP, OG image rotation |
gallery.html |
Curated examples and downloadable preview images |
manual.html |
User reference |
dev.html |
Embed, API, and MCP reference |
fluid-core/ |
Zero-dependency native canvas library on npm — shader + engine/palette/look tables generated from index.html by fluid-core/build.mjs, plus a small mount runtime; see fluid-core/README.md |
fluid-bg/ |
npm package: <fluid-bg> web component + React wrapper built on fluid-core; see fluid-bg/README.md |
fluid-vibe/ |
Prototype: client-side semantic "describe a vibe" matcher (transformers.js); not yet wired into the studio |
assets/ |
Favicon, gallery previews, Open Graph images, and README media |
Important invariants:
- Keep the app dependency-free: no bundler, framework, or install step.
- Keep the shader source as joined string arrays.
- Preserve the append-only
#p=share-hash field order. - Keep mirrored constants in
index.htmlandworker.jsin sync. - After changing engines, palettes, or looks, run
node fluid-core/build.mjs— the test suite fails on drift. - Scale screen-space shader sizes by the render scale
kused for export.
See docs/ARCHITECTURE.md for the share-hash contract and Worker mirror notes.
The hosted instance auto-deploys from master via GitHub Actions. To deploy
your own:
npx wrangler deployStaging:
npx wrangler deploy --env stagingDeployment requires Cloudflare credentials with Worker deploy access.
See CONTRIBUTING.md. The most useful contributions are field engines, palette presets, gallery pieces, manual fixes, and bug reports with a share link.
MIT. See LICENSE.





