Lava Lamp in CSS Canvas + Javascript

HTML
<canvas id='canvas'></canvas>
CSS
html { height: 100%; } body { min-height: 100%; border: 0; margin: 0; overflow: hidden; display: flex; justify-content: center; align-items: center; background: #333745; } canvas { height: 500px; width: 500px; background: #E63462; }
ES6
let canvas = document.getElementById("canvas"); let ctx = canvas.getContext('2d'); let context = ctx; let width = 500; let height = 500; let bubblesNum = 200; let magnetH = 5; let centerX = width / 2; let centerY = height / 2; let bubbles = []; let state; canvas.width = width; canvas.height = height; function animate() { window.requestAnimationFrame(animate); render(); } function init() { for (let id = 0; id < bubblesNum; id++) { let r = random(5, 25); let x = id * 3 + random(-20, 50); let y = height - random(0, 20); let c = '#333745'; bubbles.push({ x, y, r, c, id }); } state = { moved: {}, movedSize: 0, movingIds: {}, moving: [], falledSize: 0, falledIds: {}, fallingIds: {}, falling: [] }; } function render() { ctx.clearRect(0, 0, width, height); // draw scene drawMagnet(); drawStaticBublbes(); moveBubblesUp(); moveBubblesDown(); if (state.falledSize === bubblesNum) { state.fallingIds = {}; state.moved = {}; state.movedSize = 0; state.movingIds = {}; state.moving = []; state.falledSize = 0; state.falledIds = {}; state.fallingIds = {}; state.falling = []; } } function drawMagnet() { ctx.beginPath(); ctx.rect(0, 0, width, magnetH); ctx.fillStyle = '#FE5F55'; ctx.fill(); } function drawStaticBublbes() { for (let i = 0, l = bubbles.length; i < l; i++) { let b = bubbles[i]; if (state.moved[b.id] && !state.fallingIds[b.id]) { state.fallingIds[b.id] = true; b.c = '#FE5F55'; state.falling.push(b); } circle(b); } } function moveBubblesUp() { function getB() { let i = random(0, bubbles.length - 1); return bubbles[i]; } function move(b) { if (!state.moved[b.id]) { if (!(b.x <= 0 || b.x >= width)) { b.x += random(-1, 1); } if (b.y <= b.r + magnetH) { state.moved[b.id] = true; state.movedSize += 1; } else { b.y -= 2; } } } for (let i = 0; i < state.moving.length; i++) { move(state.moving[i]); } if (Date.now() % 2 === 0) { let newB = getB(); if (!state.movingIds[newB.id]) { state.moving.push(newB); state.movingIds[newB.id] = true; } } } function moveBubblesDown() { for (let i = 0; i < state.falling.length; i++) { let b = state.falling[i]; if (!state.falledIds[b.id]) { if (b.y >= height) { b.c = '#333745'; state.falledSize += 1; state.falledIds[b.id] = true; } else { b.y += 1; } } } } init(); animate(); function circle(b) { ctx.beginPath(); ctx.arc(b.x, b.y, b.r, 0, 2 * Math.PI, false); ctx.fillStyle = b.c; ctx.fill(); } function random(min, max) { min = Math.ceil(min); max = Math.floor(max); return Math.floor(Math.random() * (max - min + 1)) + min; }
Expand for more options Login