hypr angle logo dynamic wave
by phloe
HTML
<svg viewBox="-50 -50 691 395">
<g>
<g>
<path d="M0 0H79V79L214.861 215H103.139L79 190.866V215H0V0Z"/>
<path d="M295 79V294H216V214.866L80.1385 79H191.861L216 103.143V79L295 79Z"/>
</g>
<g>
<path d="M510.861 79L375 214.866V294H296V182.143L320.138 158H296V79L510.861 79Z"/>
<path d="M512.143 79L376.139 215H487.861L547.861 156H591V79H512.143Z"/>
</g>
<path d="M512 192.627L548.2 157H591V215H512V192.627ZM512 0H591V78H512V0Z" fill-opacity="0.5"/>
</g>
</svg>
CSS
path {
transform: translate(var(--x, 0px), var(--y, 0px));
}
JavaScript
class Waves {
constructor(coords, callback) {
this.coords = coords;
this.waves = [];
this.checking = false;
this.callback = callback;
}
add(wave) {
this.waves.push(wave);
if (!this.checking) {
this.checking = true;
this.check();
}
}
check() {
const retire = [];
const heights = this.coords.map(() => 0);
const now = +Date.now();
this.waves.forEach((wave, index) => {
if (wave.start + wave.falloff > now) {
this.coords.forEach((x, i) => {
heights[i] += wave.getY(x, now);
});
}
else {
retire.unshift(index);
}
});
retire.forEach((index) => {
this.waves[index] = null;
this.waves.splice(index, 1);
});
this.callback(heights);
if (this.waves.length) {
requestAnimationFrame(() => this.check());
}
else {
this.checking = false;
}
}
}
class Wave {
constructor(center, amp, freq, size) {
this.center = center;
this.amp = amp;
this.freq = freq;
this.size = size;
this.start = +Date.now();
this.falloff = 5000;
}
getY(x, now) {
const elapsed = now - this.start;
if (elapsed > this.falloff) {
return 0;
}
const sinDelta = elapsed;
const dist = Math.abs(x - this.center);
const sinPos = (dist % this.freq) / this.freq;
return Math.sin(sinPos + ((sinDelta / 1000 - 1) * Math.PI / 2)) * this.amp * (1 - (elapsed / this.falloff));
}
}
const svg = document.querySelector("svg");
const paths = [...document.querySelectorAll("path")];
let path, startX, startY, scale;
const box = svg.getAttribute("viewBox")
.split(" ")
.map((string) => parseFloat(string, 10));
const boxWidth = box[2] - box[0];
const pathCoords = paths.map((path) => {
const { left, width } = path.getBoundingClientRect();
return left + (width / 2);
});
const waves = new Waves(pathCoords, (heights) => {
heights.forEach((height, index) => {
let y = height;
if (index === 0) {
...