Beautiful bubbly backgrounds in less than 1kB (750 bytes gzipped)
JavaScript
1,617
87 commits
updated Oct 29, 2025
bubbly()Add bubbly to your webpage and call bubbly():
<body>
...
<script src="https://cdn.jsdelivr.net/npm/bubbly-bg@1.0.0/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/bubbly-bg@1.0.0/dist/bubbly-bg.js"></script>
npm install bubbly-bg
bubbly({
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
Overall
Maintained
Code review
npm
Latest release
Releases this year
1,272 followers · starred Oct 2017
544 followers · starred Apr 2018
513 followers · starred Oct 2017
155 followers · starred Jan 2018
Beautiful bubbly backgrounds in less than 1kB (750 bytes gzipped)
JavaScript
1,617
87 commits
updated Oct 29, 2025
bubbly()Add bubbly to your webpage and call bubbly():
<body>
...
<script src="https://cdn.jsdelivr.net/npm/bubbly-bg@1.0.0/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/bubbly-bg@1.0.0/dist/bubbly-bg.js"></script>
npm install bubbly-bg
bubbly({
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
Overall
Maintained
Code review
npm
Latest release
Releases this year
1,272 followers · starred Oct 2017
544 followers · starred Apr 2018
513 followers · starred Oct 2017
155 followers · starred Jan 2018