<!--
LUME ✨👉 https://github.com/lume/lume
-->
<script src="https://unpkg.com/[email protected]/dist/global.js"></script>
<!--
And Tween.js: https://github.com/tweenjs/tween.js
-->
<script src="https://unpkg.com/[email protected]"></script>
html,
body {
width: 100%;
height: 100%;
padding: 0;
margin: 0;
background: radial-gradient(
circle,
rgb(23, 132, 252) 0%,
rgb(0, 0, 198) 43.67%,
rgb(13, 9, 98) 100%
);
}
{
LUME.defineElements();
const log = console.log.bind(console);
const { Motor, Scene, Node } = LUME;
const { Tween, Easing } = TWEEN;
const sleep = (duration) => new Promise((r) => setTimeout(r, duration));
async function rippleFlip() {
const scene = new Scene();
document.body.append(scene);
const gridSizeX = 16;
const gridSizeY = 16;
const gridCellSize = 100;
const grid = new Node().set({
size: [gridSizeX * gridCellSize, gridSizeY * gridCellSize],
alignPoint: [0.5, 0.5],
mountPoint: [0.5, 0.5],
rotation: [30],
position: { z: -600 }
});
scene.append(grid);
await sleep(500);
const rippleOptions = {
// ripple center
cx: grid.calculatedSize.x / 2,
cy: grid.calculatedSize.y / 2,
amountToRotate: 180,
rotationDuration: 1600,
rotationCurve: Easing.Bounce.Out,
amountToDisplace: 200,
displaceDuration: 1600,
displaceCurve: Easing.Exponential.Out,
amountToOpacify: 1,
opacifyDuration: 2400,
opacifyCurve: Easing.Exponential.Out,
rippleDistance: grid.calculatedSize.x / 2,
rippleDuration: 1000,
rippleCurve: Easing.Linear.None,
rotation: true,
displacement: true,
opacification: true
};
// make a grid of rectangles
for (let i = 0; i < gridSizeX; i++) {
for (let j = 0; j < gridSizeY; j++) {
const node = new Node().set({
size: [gridCellSize, gridCellSize],
position: [i * gridCellSize, j * gridCellSize],
opacity: 0
});
node.opacity = 0;
const img = document.createElement("img");
img.src = "https://assets.codepen.io/191583/blue-gradient-square.svg";
img.style.display = "block";
img.style.width = "100%";
img.style.height = "100%";
node.append(img);
grid.append(node);
}
}
await sleep(500);
while (true) {
await ripple(grid, rippleOptions);
await sleep(1000);
}
}
function ripple(
grid,
{
cx,
cy,
amountToRotate,
rotationDuration,
rotationCurve,
amountToDisplace,
displaceDuration,
displaceCurve,
amountToOpacify,
opacifyDuration,
opacifyCurve,
rippleDistance,
rippleDuration,
rippleCurve,
rotation,
displacement,
opacification
}
) {
log("start ripple!");
let resolve = null;
const promise = new Promise((r) => (resolve = r));
let radiusTweenComplete = false;
const radius = { value: 0 };
const radiusTween = new Tween(radius)
.to({ value: rippleDistance }, rippleDuration)
.easing(rippleCurve)
.onComplete(() => (radiusTweenComplete = true))
.start();
Motor.addRenderTask((time) => {
console.log("ripple task");
radiusTween.update(time);
for (let i = 0, l = grid.children.length; i < l; i += 1) {
const node = grid.children[i];
if (node.animating) continue;
if (!node.distanceFromCircle) {
const dx = cx - (node.position.x + 50);
const dy = cy - (node.position.y + 50);
const distanceToCircleCenter = Math.sqrt(dx ** 2 + dy ** 2);
node.initialDistanceFromCircle =
distanceToCircleCenter - radius.value;
node.distanceFromCircle = node.initialDistanceFromCircle;
} else {
node.distanceFromCircle =
node.initialDistanceFromCircle - radius.value;
}
if (node.distanceFromCircle <= 0) {
node.animating = true;
if (rotation)
rotateNode(node, amountToRotate, rotationDuration, rotationCurve);
if (displacement)
displaceNode(
node,
amountToDisplace,
displaceDuration,
displaceCurve
);
if (opacification)
opacifyNode(node, amountToOpacify, opacifyDuration, opacifyCurve);
}
}
if (radiusTweenComplete) {
const children = grid.children;
for (let i = 0, l = children.length; i < l; i += 1) {
children[i].animating = false;
}
resolve();
return false;
}
});
return promise;
}
function rotateNode(node, finalValue, duration, curve) {
let resolve = null;
const promise = new Promise((r) => (resolve = r));
let tweenDone = false;
const rotationTween = new Tween(node.rotation)
.to({ y: "+180" }, duration)
.easing(curve)
.onComplete(() => (tweenDone = true))
.start();
Motor.addRenderTask((time) => {
rotationTween.update(time);
if (tweenDone) {
resolve();
return false;
}
});
return promise;
}
function displaceNode(node, amount, duration, curve) {
let resolve = null;
const promise = new Promise((r) => (resolve = r));
const displace = { value: 0 };
let tweenDone = false;
const displacementTween = new Tween(displace)
.to({ value: Math.PI }, duration)
.easing(curve)
.onComplete(() => (tweenDone = true))
.start();
Motor.addRenderTask((time) => {
displacementTween.update(time);
node.position.z = amount * Math.sin(displace.value);
if (tweenDone) {
resolve();
return false;
}
});
return promise;
}
function opacifyNode(node, amount, duration, curve) {
let resolve = null;
const promise = new Promise((r) => (resolve = r));
const opacify = { value: 0 };
let tweenDone = false;
const opacifyTween = new Tween(opacify)
.to({ value: Math.PI }, duration)
.easing(curve)
.onComplete(() => (tweenDone = true))
.start();
Motor.addRenderTask((time) => {
opacifyTween.update(time);
node.opacity = amount * Math.sin(opacify.value);
if (tweenDone) {
resolve();
return false;
}
});
return promise;
}
rippleFlip();
}
View Compiled
This Pen doesn't use any external CSS resources.
This Pen doesn't use any external JavaScript resources.