A zero-dependency procedural geometry engine for generating detailed mandala SVG art. Composable rings, exact polar/bezier math, and a seeded composer that turns a single string into a complex, perfectly symmetric mandala — deterministically.
▶ Live studio · MIT · no dependencies · works in the browser and Node
Hand-drawing mandalas as SVG is tedious and error-prone — it's a lot of trigonometry,
radial repetition, and bezier control points. mandala-forge does that math for you.
You describe rings (petals, dots, scallops, polygons, stars, spokes…) at radii, and the
engine handles the symmetry, the polar→cartesian conversion, and clean SVG output. Or you
hand it a seed and it composes a whole mandala for you — the same seed always renders the
same art.
npm install mandala-forgeOr just drop src/mandala-forge.js into a page — it's a single ES module with no deps.
import { randomMandala } from 'mandala-forge';
// one seed → one detailed, reproducible mandala
const svg = randomMandala('avasis', { stroke: '#9B3A2E', size: 600 }).toSVG();
document.body.innerHTML = svg;import { Mandala, rings } from 'mandala-forge';
const svg = new Mandala({ size: 600, stroke: '#9B3A2E', strokeWidth: 1.2 })
.add(rings.circle({ r: 286 }))
.add(rings.dotRing({ r: 272, count: 48, dotR: 2 }))
.add(rings.petalRing({ r: 150, count: 24, length: 110, width: 26, kind: 'lance' }))
.add(rings.scallop({ r: 150, count: 24, depth: 12 }))
.add(rings.petalRing({ r: 60, count: 12, length: 90, width: 40, kind: 'lotus', vein: true }))
.add(rings.star({ points: 12, outer: 60, inner: 30 }))
.add(rings.dotRing({ r: 0, count: 1, dotR: 8, fill: '@stroke' })) // center
.toSVG();import { presets } from 'mandala-forge';
presets.lotus({ stroke: '#9B3A2E' }).toSVG();
presets.star({ stroke: '#1B1A17' }).toSVG();| option | default | description |
|---|---|---|
size |
600 |
square canvas size in px |
stroke |
#1B1A17 |
default stroke color for all layers |
strokeWidth |
1 |
default stroke width |
fill |
none |
default fill for shape layers |
background |
transparent |
background rect fill |
cx / cy |
center | origin of the radial space |
.add(layer | layer[])— append one or more ring layers (chainable)..toSVG()— render to an SVG string.
Every generator returns a layer and accepts per-layer style overrides
(stroke, strokeWidth, fill, opacity, dash). fill: '@stroke' fills with the
mandala's stroke color (handy for dots and the center).
| generator | key params |
|---|---|
circle |
r |
concentric |
radii: number[] |
dotRing |
r, count, dotR, phase |
petalRing |
r, count, length, width, kind('lotus'|'leaf'|'lance'|'teardrop'), vein |
polygonRing |
r, count, sides, scale, spin, phase |
spokes |
count, r1, r2, phase |
scallop |
r, count, depth, dir(1|-1), phase |
star |
points, outer, inner, phase |
phyllotaxis |
count, spread, dotR, max (golden-angle dot field) |
arcs |
r, count, sweepDeg, phase |
Composes a tasteful, dense mandala from a seed (string or number). Deterministic.
Accepts all Mandala options plus symmetry (force the fold count; omit to derive from
the seed).
polar(r, deg), repeatRadial(count, draw, phase), petalPath(kind, rb, rt, w),
polygonPath(sides, R, spin), mulberry32(seed), hashSeed(s).
The live studio lets you pick a style or seed, tune symmetry / stroke / colors, and export SVG or PNG — plus copy the exact code to reproduce any mandala. Run it locally:
npm run demo # serves on http://localhost:8731The output is plain SVG — inline it, set it as a CSS background-image (data URI), or save
it to a file. It scales crisply and is tiny. Great for hero backgrounds, section dividers,
favicons, generative avatars, or print.
npm run example # writes a set of SVGs to examples/out/PRs welcome — new ring generators, presets, and palette ideas especially. The engine is a
single readable file (src/mandala-forge.js); keep it dependency-free.
MIT © 2026 Abhay (celesticlabs)
