- 🪶 Lightweight - Only 1.6kB minified, 841 bytes gzipped
- 🎨 Customizable - Full control over colors, gradients, and animations
- 🚀 Zero dependencies - Pure vanilla JavaScript
- 📦 Easy to use - Just include and call
bubbly() - 🎯 TypeScript support - Full type definitions included
- 🔧 Flexible - Works with your own canvas or creates one automatically
Add bubbly to your webpage and call bubbly():
<body>
...
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/bubbly-bg.js"></script>
<script>bubbly();</script>
</body>That's it! Bubbly creates a canvas element with position: fixed and z-index: -1, filling the viewport. It's plug-and-play for most projects.
You can also use your own canvas element:
bubbly({ canvas: document.querySelector("#my-canvas") });<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/bubbly-bg.js"></script>npm install bubbly-bgbubbly({
canvas: document.querySelector("#background"), // default is created and attached automatically
compose: "lighter", // default is "lighter"
animate: false, // default is true
background: (ctx) => "#2AE", // default background, can be a color string or function returning gradient
bubbles: {
count: 100, // default is Math.floor((canvas.width + canvas.height) * 0.02)
radius: () => 4 + Math.random() * 25, // default is () => 4 + Math.random() * window.innerWidth / 25
fill: () => `hsla(${Math.random() * 360}, 100%, 50%, ${Math.random() * 0.25})`, // default is () => `hsla(0, 0%, 100%, ${Math.random() * 0.1})`
angle: () => Math.random() * Math.PI * 2, // default is this
velocity: () => 0.1 + Math.random() * 0.5, // default is this
shadow: () => ({blur: 4, color: "#fff"}), // default is () => null
stroke: () => ({width: 2, color: "#fff"}), // default is () => null
objectCreator: () => ({...}) // advanced: custom bubble object creator
}
});| Option | Type | Default | Description |
|---|---|---|---|
canvas |
HTMLCanvasElement |
auto-created | Canvas element to use |
compose |
string |
"lighter" |
Global composite operation |
animate |
boolean |
true |
Whether to animate bubbles |
background |
string | function |
"#2AE" |
Background color or gradient function |
bubbles.count |
number |
auto-calculated | Number of bubbles |
bubbles.radius |
function |
auto-calculated | Function returning bubble radius |
bubbles.fill |
function |
white with opacity | Function returning bubble fill color |
bubbles.angle |
function |
random | Function returning movement angle |
bubbles.velocity |
function |
random | Function returning velocity |
bubbles.shadow |
function |
null |
Function returning shadow config |
bubbles.stroke |
function |
null |
Function returning stroke config |
bubbles.objectCreator |
function |
default creator | Advanced: custom bubble creator |
bubbly();bubbly({
background: (ctx) => {
const gradient = ctx.createLinearGradient(0, 0, ctx.canvas.width, ctx.canvas.height);
gradient.addColorStop(0, "#111");
gradient.addColorStop(1, "#422");
return gradient;
},
bubbles: {
fill: () => `hsla(0, 100%, 50%, ${Math.random() * 0.25})`,
shadow: () => ({blur: 4, color: "#fff"})
}
});bubbly({
background: (ctx) => {
const gradient = ctx.createLinearGradient(0, 0, ctx.canvas.width, ctx.canvas.height);
gradient.addColorStop(0, "#4c004c");
gradient.addColorStop(1, "#1a001a");
return gradient;
},
bubbles: {
fill: () => `hsla(${Math.random() * 360}, 100%, 50%, ${Math.random() * 0.25})`,
shadow: () => ({blur: 4, color: "#fff"})
}
});bubbly({
background: (ctx) => {
const gradient = ctx.createLinearGradient(0, 0, ctx.canvas.width, ctx.canvas.height);
gradient.addColorStop(0, "#fff4e6");
gradient.addColorStop(1, "#ffe9e4");
return gradient;
},
compose: "source-over",
bubbles: {
fill: () => `hsla(${Math.random() * 50}, 100%, 50%, .3)`,
shadow: () => ({blur: 1, color: "#fff"})
}
});For complete control over bubble creation and rendering:
bubbly({
bubbles: {
objectCreator: function() {
return {
x: Math.random() * canvas.width,
y: Math.random() * canvas.height,
r: 10,
a: Math.random() * Math.PI * 2,
v: 1,
draw: (ctx, bubble) => {
// Custom drawing logic
ctx.fillStyle = "red";
ctx.fillRect(bubble.x, bubble.y, bubble.r, bubble.r);
}
};
}
}
});Full TypeScript definitions are included:
import { bubbly, BubblyConfig } from 'bubbly-bg';
const config: BubblyConfig = {
animate: true,
bubbles: {
count: 50
}
};
bubbly(config);Apache-2.0 © David Åse
Contributions, issues and feature requests are welcome!
Give a ⭐️ if this project helped you!
Made with ❤️ by David Åse
