Technique
Mesh gradients
Make a mesh gradient in CSS (stacked radial-gradients over a base colour), export it as SVG or PNG, and get the contrast report. Seeded Poisson-disc layout, so the same colours and seed give the same mesh forever. Free, no sign-up.
Export
CSS with the interpolation space, Tailwind v4, SVG with correct geometry, a DTCG token, and the PNG.
Apply this to a brand → sign in
.gradient {
background-color: #9795ee;
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='g' x='0' y='0' width='100%25' height='100%25' color-interpolation-filters='sRGB'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.858' numOctaves='2' seed='2' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3CfeComponentTransfer%3E%3CfeFuncR type='linear' slope='3' intercept='-1'/%3E%3CfeFuncG type='linear' slope='3' intercept='-1'/%3E%3CfeFuncB type='linear' slope='3' intercept='-1'/%3E%3C/feComponentTransfer%3E%3CfeColorMatrix type='matrix' values='1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 19 -12'/%3E%3CfeComponentTransfer%3E%3CfeFuncA type='linear' slope='0.012'/%3E%3C/feComponentTransfer%3E%3C/filter%3E%3Crect width='160' height='160' filter='url(%23g)'/%3E%3C/svg%3E"), radial-gradient(circle farthest-corner at 6.16% 12.62%, rgba(99, 91, 255, 0.72) 0%, rgba(99, 91, 255, 0) 50.06%), radial-gradient(circle farthest-corner at 95.51% 53.69%, rgba(144, 137, 252, 0.875) 0%, rgba(144, 137, 252, 0) 55.68%), radial-gradient(circle farthest-corner at 45.23% 15.03%, rgba(255, 128, 181, 0.728) 0%, rgba(255, 128, 181, 0) 49.83%), radial-gradient(circle farthest-corner at 37.97% 64.32%, rgba(0, 212, 255, 0.809) 0%, rgba(0, 212, 255, 0) 46.1%);
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='g' x='0' y='0' width='100%25' height='100%25' color-interpolation-filters='sRGB'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.858' numOctaves='2' seed='2' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3CfeComponentTransfer%3E%3CfeFuncR type='linear' slope='3' intercept='-1'/%3E%3CfeFuncG type='linear' slope='3' intercept='-1'/%3E%3CfeFuncB type='linear' slope='3' intercept='-1'/%3E%3C/feComponentTransfer%3E%3CfeColorMatrix type='matrix' values='1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 19 -12'/%3E%3CfeComponentTransfer%3E%3CfeFuncA type='linear' slope='0.012'/%3E%3C/feComponentTransfer%3E%3C/filter%3E%3Crect width='160' height='160' filter='url(%23g)'/%3E%3C/svg%3E"), radial-gradient(circle farthest-corner at 6.16% 12.62%, oklch(from #635bff l c h / 0.72) 0%, rgb(from #635bff r g b / 0) 50.06%), radial-gradient(circle farthest-corner at 95.51% 53.69%, oklch(from #9089fc l c h / 0.8751) 0%, rgb(from #9089fc r g b / 0) 55.68%), radial-gradient(circle farthest-corner at 45.23% 15.03%, oklch(from #ff80b5 l c h / 0.7283) 0%, rgb(from #ff80b5 r g b / 0) 49.83%), radial-gradient(circle farthest-corner at 37.97% 64.32%, oklch(from #00d4ff l c h / 0.8087) 0%, rgb(from #00d4ff r g b / 0) 46.1%);
background-size: 160px 160px, auto, auto, auto, auto;
background-blend-mode: soft-light, normal, normal, normal, normal;
}
/* or keep the gradient untouched and overlay the grain: */
.gradient {
position: relative;
isolation: isolate;
}
.gradient::after {
content: "";
position: absolute;
inset: 0;
pointer-events: none;
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='g' x='0' y='0' width='100%25' height='100%25' color-interpolation-filters='sRGB'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.858' numOctaves='2' seed='2' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3CfeComponentTransfer%3E%3CfeFuncR type='linear' slope='3' intercept='-1'/%3E%3CfeFuncG type='linear' slope='3' intercept='-1'/%3E%3CfeFuncB type='linear' slope='3' intercept='-1'/%3E%3C/feComponentTransfer%3E%3CfeColorMatrix type='matrix' values='1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 19 -12'/%3E%3C/filter%3E%3Crect width='160' height='160' filter='url(%23g)'/%3E%3C/svg%3E");
background-size: 160px 160px;
image-rendering: pixelated;
mix-blend-mode: soft-light;
opacity: 0.0124;
}How it works
There is no mesh gradient in CSS or in SVG 2 — the paint-servers chapter defines only linearGradient and radialGradient. Meshes survive as Coons patches in Illustrator and Inkscape and as a vendor feature in Figma, but nothing you can hand a browser. So "mesh" on the web is one of three techniques, and the generator above makes the first two.
1. Stacked radials — pure CSS, static, zero JS
Layer N radial-gradient()s with a transparent falloff over a base colour. Radial layers beat linear ones because the falloff is isotropic. The layout is the whole craft: we place the points with a seeded Poisson-disc sampler (minimum separation 0.35 of the box), give the highest-chroma colours to the points nearest the corners (corners carry the eye), and set each radius to about half the diagonal at 70–90% alpha. The seed is part of the spec, so the same colours and seed produce the same mesh forever — which is what makes it citable in a brand guide.
.mesh {
background-color: #9795ee;
background-image:
radial-gradient(circle farthest-corner at 6.16% 12.62%, oklch(from #635bff l c h / 0.72) 0%, rgb(from #635bff r g b / 0) 50.06%),
radial-gradient(circle farthest-corner at 95.51% 53.69%, oklch(from #9089fc l c h / 0.8751) 0%, rgb(from #9089fc r g b / 0) 55.68%),
radial-gradient(circle farthest-corner at 45.23% 15.03%, oklch(from #ff80b5 l c h / 0.7283) 0%, rgb(from #ff80b5 r g b / 0) 49.83%),
radial-gradient(circle farthest-corner at 37.97% 64.32%, oklch(from #00d4ff l c h / 0.8087) 0%, rgb(from #00d4ff r g b / 0) 46.1%);
}2. SVG — the export that matters for a brand kit
The same layout baked as nested <radialGradient> + <rect> elements: portable, printable, resolution-independent, and it imports into Figma. The PNG is rendered from this SVG, so all three agree.
3. WebGL — animated
Stripe-style motion is a fullscreen quad with per-fragment simplex-noise weights over the palette colours. The one change that separates a shader that looks like Stripe from one that looks like a lava lamp is blending in OKLab inside the shader. We plan to ship this on @paper-design/shaders-react (Apache-2.0) once the dependency lands — it is deferred, not forgotten.
The gotcha: layers composite in sRGB
Each layer can say in oklch, but the layers blend in sRGB because ordinary compositing is not colour-space-aware. So a CSS mesh is inherently a little less clean than a shader. Two mitigations, both built in: keep adjacent blobs close in hue, and add a few percent of grain (the slider above; see grainy gradients).
Starting point, as code
.gradient {
background-color: #9795ee;
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='g' x='0' y='0' width='100%25' height='100%25' color-interpolation-filters='sRGB'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.858' numOctaves='2' seed='2' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3CfeComponentTransfer%3E%3CfeFuncR type='linear' slope='3' intercept='-1'/%3E%3CfeFuncG type='linear' slope='3' intercept='-1'/%3E%3CfeFuncB type='linear' slope='3' intercept='-1'/%3E%3C/feComponentTransfer%3E%3CfeColorMatrix type='matrix' values='1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 19 -12'/%3E%3CfeComponentTransfer%3E%3CfeFuncA type='linear' slope='0.012'/%3E%3C/feComponentTransfer%3E%3C/filter%3E%3Crect width='160' height='160' filter='url(%23g)'/%3E%3C/svg%3E"), radial-gradient(circle farthest-corner at 6.16% 12.62%, rgba(99, 91, 255, 0.72) 0%, rgba(99, 91, 255, 0) 50.06%), radial-gradient(circle farthest-corner at 95.51% 53.69%, rgba(144, 137, 252, 0.875) 0%, rgba(144, 137, 252, 0) 55.68%), radial-gradient(circle farthest-corner at 45.23% 15.03%, rgba(255, 128, 181, 0.728) 0%, rgba(255, 128, 181, 0) 49.83%), radial-gradient(circle farthest-corner at 37.97% 64.32%, rgba(0, 212, 255, 0.809) 0%, rgba(0, 212, 255, 0) 46.1%);
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='g' x='0' y='0' width='100%25' height='100%25' color-interpolation-filters='sRGB'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.858' numOctaves='2' seed='2' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3CfeComponentTransfer%3E%3CfeFuncR type='linear' slope='3' intercept='-1'/%3E%3CfeFuncG type='linear' slope='3' intercept='-1'/%3E%3CfeFuncB type='linear' slope='3' intercept='-1'/%3E%3C/feComponentTransfer%3E%3CfeColorMatrix type='matrix' values='1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 19 -12'/%3E%3CfeComponentTransfer%3E%3CfeFuncA type='linear' slope='0.012'/%3E%3C/feComponentTransfer%3E%3C/filter%3E%3Crect width='160' height='160' filter='url(%23g)'/%3E%3C/svg%3E"), radial-gradient(circle farthest-corner at 6.16% 12.62%, oklch(from #635bff l c h / 0.72) 0%, rgb(from #635bff r g b / 0) 50.06%), radial-gradient(circle farthest-corner at 95.51% 53.69%, oklch(from #9089fc l c h / 0.8751) 0%, rgb(from #9089fc r g b / 0) 55.68%), radial-gradient(circle farthest-corner at 45.23% 15.03%, oklch(from #ff80b5 l c h / 0.7283) 0%, rgb(from #ff80b5 r g b / 0) 49.83%), radial-gradient(circle farthest-corner at 37.97% 64.32%, oklch(from #00d4ff l c h / 0.8087) 0%, rgb(from #00d4ff r g b / 0) 46.1%);
background-size: 160px 160px, auto, auto, auto, auto;
background-blend-mode: soft-light, normal, normal, normal, normal;
}bg-[radial-gradient(circle_farthest-corner_at_6.16%_12.62%,oklch(from_#635bff_l_c_h_/_0.72)_0%,rgb(from_#635bff_r_g_b_/_0)_50.06%),radial-gradient(circle_farthest-corner_at_95.51%_53.69%,oklch(from_#9089fc_l_c_h_/_0.8751)_0%,rgb(from_#9089fc_r_g_b_/_0)_55.68%),radial-gradient(circle_farthest-corner_at_45.23%_15.03%,oklch(from_#ff80b5_l_c_h_/_0.7283)_0%,rgb(from_#ff80b5_r_g_b_/_0)_49.83%),radial-gradient(circle_farthest-corner_at_37.97%_64.32%,oklch(from_#00d4ff_l_c_h_/_0.8087)_0%,rgb(from_#00d4ff_r_g_b_/_0)_46.1%)]
Questions
- Can I export a mesh gradient as SVG?
- Yes. The layout is baked as nested radialGradient + rect elements in SVG 2; the PNG is rendered from that same SVG, so CSS, SVG and PNG agree.
- Can I use a mesh gradient on my website?
- Yes — as stacked CSS radial-gradients over a base colour (no JavaScript), or as the SVG/PNG. The layers composite in sRGB, so keep adjacent blobs close in hue and add a few percent of grain.
- Why does the same mesh come back every time?
- The layout is a seeded Poisson-disc sample: the seed is part of the spec, so the same colours and seed give the same mesh forever. Press Re-lay for a new seed.
More
Point any MCP client at the shared gradients endpoint and your agent gets the same engine as this page — make_gradient returns CSS with the interpolation space, Tailwind v4, SVG, a PNG URL, a DTCG token and the contrast report in one call; brand_gradients derives the whole contact sheet from a brand or a palette. Read-only, no key. Every gradient is a /gradients/new/… link: open it, refine, paste it back.
https://mcp.brandsweets.com/gradients/mcpclaude mcp add --transport http brandsweets-gradients https://mcp.brandsweets.com/gradients/mcp
›make a mesh gradient from #635bff, #00d4ff and #ff80b5 with seed 7, export the SVG, and tell me if white text passes AA
Want the agent to remember your picks and write them into a living brand? Create a free BrandSweets workspace.