Skip to content

Instantly share code, notes, and snippets.

@gp0119
Created August 20, 2021 04:31
Show Gist options
  • Select an option

  • Save gp0119/f030b560482157f8a1fcf4c5756570f5 to your computer and use it in GitHub Desktop.

Select an option

Save gp0119/f030b560482157f8a1fcf4c5756570f5 to your computer and use it in GitHub Desktop.
Generative macOS Big Sur Waves 🌊 [SVG]

Generative macOS Big Sur Waves 🌊 [SVG]

This is a generative program that creates macOS Big Sur style wave backgrounds. Each image is random within constraints

The waves generated here may not always look perfect, but they are unique! If you find an output you like, you can copy the SVG to your clipboard using the download button πŸš€

Interested in a tutorial on how I made this? Let me know!

A Pen by gp on CodePen.

License.

<div class="canvas-wrapper">
<svg class="canvas" viewBox="0 0 1920 1080" preserveAspectRatio="xMaxYMid slice"></svg>
</div>
<div class="controls">
<p>* Export is disabled for mobile devices</p>
<button class="download">Copy SVG</button>
<button class="regenerate">Regenerate</button>
</div>
console.clear();
import { SVG } from "https://cdn.skypack.dev/@svgdotjs/svg.js";
import {
random,
map,
spline,
pointsInPath
} from "https://cdn.skypack.dev/@georgedoescode/generative-utils@1.0.0";
import tinycolor from "https://cdn.skypack.dev/tinycolor2@1.4.2";
import "https://cdn.skypack.dev/@svgdotjs/svg.filter.js";
import copy from "https://cdn.skypack.dev/copy-to-clipboard@3.3.1";
import { gsap } from "https://cdn.skypack.dev/gsap@3.6.0";
const svg = SVG(".canvas");
const { width, height } = svg.viewbox();
const regenerateBtn = document.querySelector(".regenerate");
const downloadBtn = document.querySelector(".download");
function wave(start, end, gradient) {
const numSteps = random(4, 8, true);
const step = 1 / numSteps;
const randomRange = random(32, 64);
const points = [];
let pointPosition = 0;
for (let i = 0; i <= numSteps; i++) {
const step = map(i, 0, numSteps, 0, 1);
let x = lerp(start.x, end.x, step);
let y = lerp(start.y, end.y, step);
if (i !== 0 && i !== numSteps) {
x += random(-randomRange, randomRange);
y += random(-randomRange, randomRange);
}
points.push({ x, y });
}
const pathData =
spline(points, 1, false) + `L ${end.x} ${height} L ${start.x} ${height} Z`;
const path = svg.path(pathData).attr("fill", gradient);
}
function lerp(v0, v1, t) {
return v0 * (1 - t) + v1 * t;
}
function generate() {
const numWaves = 7;
const base = tinycolor(`hsl(${random(0, 360)}, 65%, 55%)`);
const colors = base.analogous(6);
svg.rect(width, height).fill(random(colors).clone().darken(40).toString());
for (let i = 0; i < numWaves; i++) {
const randomOffset = random(-50, 50);
const originY = map(i, 0, numWaves, -height / 2, height / 3) + randomOffset;
const endY = map(i, 0, numWaves, 0, 1000) + randomOffset;
const color = random(colors).clone();
if (i < 3) {
color.darken(50).desaturate(10);
}
const gradientOffset = map(i, 0, numWaves, 0.1, 1);
let gradient = svg.gradient("linear", function (add) {
add.stop(0, color.clone().lighten(30).toHexString());
add.stop(gradientOffset, color.clone().spin(60).toHexString());
});
gradient.from(0.5, 0).to(0, 1);
wave({ x: 0, y: originY }, { x: width, y: endY }, gradient);
}
}
generate();
regenerateBtn.addEventListener("click", () => {
svg.clear();
generate();
});
downloadBtn.addEventListener("click", () => {
copy(svg.node.outerHTML);
downloadBtn.innerHTML = "Copied to Clipboard!";
setTimeout(() => {
downloadBtn.innerHTML = "Copy SVG";
}, 1500);
});
gsap.fromTo(
".controls",
{
opacity: 0,
y: 24
},
{
opacity: 1,
y: 0,
ease: "back.out(1.7)",
delay: 0.175
}
);
gsap.fromTo(
"button",
{
opacity: 0,
y: 12
},
{
opacity: 1,
y: 0,
stagger: 0.125,
delay: 0.175,
ease: "back.out(1.7)"
}
);
gsap.fromTo(
"p",
{
opacity: 0,
y: 12
},
{
opacity: 1,
y: 0,
ease: "back.out(1.7)",
delay: 0.175
}
);
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
html {
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
body {
min-height: 100vh;
display: grid;
place-items: center;
padding: 1rem;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica,
Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
color: hsl(0, 0%, 10%);
background: hsl(0, 0%, 100%);
}
.canvas-wrapper {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
overflow: hidden;
}
.canvas {
width: 100vw;
height: 100vh;
}
.controls {
position: relative;
display: grid;
grid-gap: 1rem;
grid-template-columns: 1fr;
width: 100%;
max-width: 24rem;
padding: 1rem;
background: hsla(0, 0%, 100%, 0.25);
z-index: 1;
-webkit-backdrop-filter: blur(12px);
backdrop-filter: blur(12px);
border-radius: 0.5rem;
border: 1px solid hsla(0, 0%, 100%, 0.25);
opacity: 0;
}
.controls p {
grid-column: -1 / 1;
font-style: italic;
text-align: center;
font-size: 0.75rem;
}
button {
width: 100%;
height: 2.25rem;
border: 0;
font-weight: 500;
font-family: inherit;
border-radius: 0.5rem;
font-size: 0.875rem;
line-height: 2.25rem;
background: hsla(0, 0%, 100%, 0.25);
cursor: pointer;
}
button:nth-of-type(1) {
-webkit-backdrop-filter: blur(12px);
backdrop-filter: blur(12px);
display: none;
}
button:nth-of-type(2) {
background: linear-gradient(to bottom, #287cfe, #0466ff);
color: #fff;
}
@media only screen and (min-width: 640px) {
.controls {
grid-template-columns: 1fr 1fr;
}
.controls p {
display: none;
}
.controls button:nth-of-type(1) {
display: block;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment