JS Metaballs
For Chrome. Mix of webkit-filter and canvas for a metaballs effect.
<script src="//cdn.jsdelivr.net/physicsjs/0.6.0/physicsjs.full.min.js"></script>
<script src="//cdn.jsdelivr.net/physicsjs/0.6.0/physicsjs.full.min.js"></script>
<div class="container">
<canvas id="viewport"></canvas>
</div>
html, body {
html, body {
margin: 0;
background-color: #1d1f20;
}
.container {
position: absolute;
left: 0;
top: 0;
right: 0;
bottom: 0;
margin: auto;
filter: blur(20px) drop-shadow(0 0 80px #000) contrast(10);
}
Physics(function(world) {
Physics(function(world) {
var viewWidth = window.innerWidth,
viewHeight = window.innerHeight,
// center of the window
center = Physics.vector(viewWidth, viewHeight).mult(0.5),
// bounds of the window
viewportBounds = Physics.aabb(0, 0, viewWidth, viewHeight),
edgeBounce, renderer;
// create a renderer
renderer = Physics.renderer('canvas', {
el: 'viewport',
width: viewWidth,
height: viewHeight
});
// add the renderer
world.add(renderer);
// render on each step
world.on('step', function() {
world.render();
});
renderer.el.addEventListener('mousedown', function(e) {
world.clicked = true;
world.add(spawnBlob({
x: e.pageX,
y: e.pageY
}));
});
renderer.el.addEventListener('mousemove', function(e) {
if (world.clicked) {
world.add(spawnBlob({
x: e.pageX,
y: e.pageY
}));
}
});
renderer.el.addEventListener('mouseup', function(e) {
world.clicked = false;
});
function spawnBlob(options) {
options = options || {};
return Physics.body('circle', {
radius: 20,
mass: 20,
x: options.x || 0,
y: options.y || 0,
vx: options.vx || 0,
vy: options.vy || 0,
styles: {
fillStyle: '#00ff00'
}
});
}
function spawnBlobs() {
// create some bodies
var l = 10;
var bodies = [];
var v = Physics.vector(0, 300);
var b, r;
while (l--) {
r = 20;
b = spawnBlob({
x: v.x + center.x,
y: v.y + center.y,
vx: v.perp().mult(0.0001).x,
vy: v.y
});
bodies.push(b);
}
world.add(bodies);
}
// constrain objects to these bounds
edgeBounce = Physics.behavior('edge-collision-detection', {
aabb: viewportBounds,
restitution: 0.1,
cof: 0.1
});
// add things to the world
spawnBlobs();
world.add([
Physics.behavior('constant-acceleration', {
acc: {
x: 0,
y: 0.001
}
}),
Physics.behavior('body-impulse-response'),
Physics.behavior('body-collision-detection', {
restitution: 1,
cof: 1
}),
Physics.behavior('sweep-prune'),
edgeBounce
]);
// subscribe to ticker to advance the simulation
Physics.util.ticker.on(function(time) {
world.step(time);
});
// start the ticker
Physics.util.ticker.start();
// resize events
window.addEventListener('resize', function() {
viewWidth = window.innerWidth;
viewHeight = window.innerHeight;
renderer.el.width = viewWidth;
renderer.el.height = viewHeight;
viewportBounds = Physics.aabb(0, 0, viewWidth, viewHeight);
// update the boundaries
edgeBounce.setAABB(viewportBounds);
}, true);
});