Import the existing local project snapshot. This commit organizes existing files; it does not represent newly developed functionality.
170 lines
8.7 KiB
JavaScript
170 lines
8.7 KiB
JavaScript
"use strict";
|
|
|
|
function svgURI(svg) {
|
|
return "data:image/svg+xml," + encodeURIComponent(svg);
|
|
}
|
|
|
|
function gid(seed, name) {
|
|
return "g" + name + seed;
|
|
}
|
|
|
|
function artSVG(palette, seed, pattern) {
|
|
const rnd = seeded(seed);
|
|
const c1 = palette[0], c2 = palette[1], c3 = palette[2];
|
|
const id = gid(seed, pattern);
|
|
let inner = "";
|
|
|
|
if (pattern === "mesh") {
|
|
inner = `
|
|
<rect width="512" height="512" fill="#0a0a0c"/>
|
|
<defs>
|
|
<radialGradient id="${id}a" cx="0.25" cy="0.15" r="0.9">
|
|
<stop offset="0" stop-color="${c1}" stop-opacity="0.95"/><stop offset="1" stop-color="${c1}" stop-opacity="0"/>
|
|
</radialGradient>
|
|
<radialGradient id="${id}b" cx="0.85" cy="0.9" r="1">
|
|
<stop offset="0" stop-color="${c2}" stop-opacity="0.9"/><stop offset="1" stop-color="${c2}" stop-opacity="0"/>
|
|
</radialGradient>
|
|
<radialGradient id="${id}c" cx="0.6" cy="0.45" r="0.55">
|
|
<stop offset="0" stop-color="${c3}" stop-opacity="0.55"/><stop offset="1" stop-color="${c3}" stop-opacity="0"/>
|
|
</radialGradient>
|
|
</defs>
|
|
<rect width="512" height="512" fill="url(#${id}a)"/>
|
|
<rect width="512" height="512" fill="url(#${id}b)"/>
|
|
<rect width="512" height="512" fill="url(#${id}c)"/>
|
|
<circle cx="256" cy="256" r="${180 + rnd() * 60}" fill="none" stroke="#ffffff" stroke-opacity="0.12" stroke-width="2"/>`;
|
|
}
|
|
|
|
if (pattern === "waves") {
|
|
let bands = "";
|
|
for (let i = 0; i < 6; i++) {
|
|
const y = 60 + i * 78 + rnd() * 24;
|
|
const amp = 26 + rnd() * 30;
|
|
const col = [c1, c2, c3, "#ffffff"][i % 4];
|
|
const op = 0.75 - i * 0.09;
|
|
bands += `<path d="M-20 ${y} Q 128 ${y - amp * 2} 256 ${y - amp * 0.6} T 532 ${y} L 532 ${y + 300} L -20 ${y + 300} Z" fill="${col}" opacity="${op}"/>`;
|
|
}
|
|
inner = `<rect width="512" height="512" fill="#0c0c10"/>${bands}`;
|
|
}
|
|
|
|
if (pattern === "arcs") {
|
|
let arcs = "";
|
|
const cx = 120 + rnd() * 200, cy = 120 + rnd() * 200;
|
|
for (let i = 0; i < 9; i++) {
|
|
const r = 40 + i * 42 + rnd() * 20;
|
|
const col = [c1, c2, c3, "#ffffff"][i % 4];
|
|
arcs += `<circle cx="${cx}" cy="${cy}" r="${r}" fill="none" stroke="${col}" stroke-opacity="${0.9 - i * 0.09}" stroke-width="${12 - i}"/>`;
|
|
}
|
|
inner = `<rect width="512" height="512" fill="#0b0b0e"/>
|
|
<defs><radialGradient id="${id}" cx="0.3" cy="0.3" r="1"><stop offset="0" stop-color="${c3}" stop-opacity="0.5"/><stop offset="1" stop-color="#0b0b0e" stop-opacity="0"/></radialGradient></defs>
|
|
<rect width="512" height="512" fill="url(#${id})"/>
|
|
${arcs}`;
|
|
}
|
|
|
|
if (pattern === "rings") {
|
|
let rings = "";
|
|
for (let i = 0; i < 7; i++) {
|
|
const r = 60 + i * 55;
|
|
const col = [c1, c2, c3, "#ffffff"][i % 4];
|
|
rings += `<circle cx="256" cy="256" r="${r}" fill="none" stroke="${col}" stroke-opacity="${0.85 - i * 0.1}" stroke-width="${5 + i * 1.4}" stroke-dasharray="${90 + rnd() * 200} ${30 + rnd() * 60}"/>`;
|
|
}
|
|
inner = `<rect width="512" height="512" fill="#0a0a0d"/>
|
|
<defs><radialGradient id="${id}" cx="0.5" cy="0.5" r="0.7"><stop offset="0" stop-color="${c1}" stop-opacity="0.35"/><stop offset="1" stop-color="#0a0a0d" stop-opacity="0"/></radialGradient></defs>
|
|
<rect width="512" height="512" fill="url(#${id})"/>
|
|
${rings}`;
|
|
}
|
|
|
|
if (pattern === "stripes") {
|
|
inner = `<rect width="512" height="512" fill="#0a0a0c"/>
|
|
<defs><linearGradient id="${id}" x1="0" y1="0" x2="1" y2="1"><stop offset="0" stop-color="${c1}"/><stop offset="1" stop-color="${c2}"/></linearGradient></defs>
|
|
<rect width="512" height="512" fill="url(#${id})" opacity="0.92"/>
|
|
<g transform="rotate(-28 256 256)">
|
|
${[0, 1, 2, 3, 4, 5, 6].map((i) => `<rect x="${i * 92 - 60}" y="-80" width="${22 + rnd() * 30}" height="672" fill="#0a0a0c" opacity="${0.25 + rnd() * 0.35}"/>`).join("")}
|
|
${[0, 1, 2, 3].map((i) => `<rect x="${i * 150 + 30}" y="-80" width="6" height="672" fill="#ffffff" opacity="0.18"/>`).join("")}
|
|
</g>`;
|
|
}
|
|
|
|
if (pattern === "sparkle") {
|
|
let dots = "";
|
|
for (let x = 20; x < 512; x += 26) {
|
|
for (let y = 20; y < 512; y += 26) {
|
|
const r = rnd();
|
|
if (r < 0.28) continue;
|
|
const size = 1 + rnd() * 5;
|
|
const col = [c1, c2, c3, "#ffffff"][Math.floor(rnd() * 4)];
|
|
dots += `<circle cx="${x + rnd() * 8}" cy="${y + rnd() * 8}" r="${size}" fill="${col}" opacity="${0.2 + rnd() * 0.6}"/>`;
|
|
}
|
|
}
|
|
inner = `<rect width="512" height="512" fill="#0c0a14"/>
|
|
<defs><radialGradient id="${id}" cx="0.5" cy="0.5" r="0.75"><stop offset="0" stop-color="${c1}" stop-opacity="0.55"/><stop offset="1" stop-color="#0c0a14" stop-opacity="0"/></radialGradient></defs>
|
|
<rect width="512" height="512" fill="url(#${id})"/>
|
|
${dots}`;
|
|
}
|
|
|
|
if (pattern === "orbital") {
|
|
let stars = "";
|
|
for (let i = 0; i < 70; i++) {
|
|
stars += `<circle cx="${rnd() * 512}" cy="${rnd() * 512}" r="${0.6 + rnd() * 1.8}" fill="#ffffff" opacity="${0.15 + rnd() * 0.5}"/>`;
|
|
}
|
|
inner = `<rect width="512" height="512" fill="#08080b"/>
|
|
${stars}
|
|
<defs>
|
|
<radialGradient id="${id}a" cx="0.5" cy="0.5" r="0.5"><stop offset="0" stop-color="${c1}"/><stop offset="1" stop-color="${c2}"/></radialGradient>
|
|
<linearGradient id="${id}b" x1="0" y1="0" x2="1" y2="1"><stop offset="0" stop-color="${c3}"/><stop offset="1" stop-color="${c1}"/></linearGradient>
|
|
</defs>
|
|
<circle cx="256" cy="256" r="150" fill="none" stroke="url(#${id}b)" stroke-opacity="0.5" stroke-width="2" transform="rotate(${rnd() * 45} 256 256)"/>
|
|
<ellipse cx="256" cy="256" rx="225" ry="80" fill="none" stroke="url(#${id}b)" stroke-opacity="0.35" stroke-width="1.5" transform="rotate(${-30 + rnd() * 20} 256 256)"/>
|
|
<ellipse cx="256" cy="256" rx="225" ry="80" fill="none" stroke="#ffffff" stroke-opacity="0.12" stroke-width="1.5" transform="rotate(${60 + rnd() * 20} 256 256)"/>
|
|
<circle cx="256" cy="256" r="62" fill="url(#${id}a)"/>
|
|
<circle cx="352" cy="196" r="10" fill="${c2}"/><circle cx="352" cy="196" r="16" fill="${c2}" opacity="0.25"/>`;
|
|
}
|
|
|
|
if (pattern === "grain") {
|
|
let grains = "";
|
|
for (let i = 0; i < 260; i++) {
|
|
grains += `<rect x="${rnd() * 512}" y="${rnd() * 512}" width="${1.5 + rnd() * 4}" height="${1.5 + rnd() * 4}" fill="${[c1, c2, c3, "#ffffff"][i % 4]}" opacity="${0.08 + rnd() * 0.3}"/>`;
|
|
}
|
|
inner = `<rect width="512" height="512" fill="${c1}"/>
|
|
<defs><linearGradient id="${id}" x1="0" y1="0" x2="1" y2="1"><stop offset="0" stop-color="${c2}" stop-opacity="0.85"/><stop offset="1" stop-color="${c3}" stop-opacity="0.85"/></linearGradient></defs>
|
|
<rect width="512" height="512" fill="url(#${id})" opacity="0.5"/>
|
|
${grains}
|
|
<rect width="512" height="512" fill="#000000" opacity="0.22"/>`;
|
|
}
|
|
|
|
return `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">${inner}</svg>`;
|
|
}
|
|
|
|
const Art = {
|
|
album(album) {
|
|
const pattern = ["mesh", "waves", "arcs", "rings", "stripes", "sparkle", "orbital", "grain"][album.seed % 8];
|
|
return svgURI(artSVG(album.palette, album.seed, pattern));
|
|
},
|
|
song(song) {
|
|
return Art.album(D.album(song.albumId));
|
|
},
|
|
mix(mix) {
|
|
return svgURI(artSVG(mix.palette, hashStr(mix.id) % 997, ["mesh", "orbital", "sparkle", "rings"][hashStr(mix.id) % 4]));
|
|
},
|
|
station(station) {
|
|
return svgURI(artSVG(station.palette, station.seed * 7 + 1, ["arcs", "sparkle", "waves", "stripes"][station.seed % 4]));
|
|
},
|
|
artist(artist) {
|
|
const initials = artist.name.split(" ").map((w) => w[0]).slice(0, 2).join("").toUpperCase();
|
|
const rnd = seeded(hashStr(artist.id));
|
|
const r1 = 30 + rnd() * 200, r2 = 30 + rnd() * 200;
|
|
const svg = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
|
|
<defs>
|
|
<radialGradient id="aa" cx="0.3" cy="0.25" r="0.95"><stop offset="0" stop-color="${artist.palette[0]}"/><stop offset="1" stop-color="${artist.palette[2] || "#0a0a0c"}"/></radialGradient>
|
|
<radialGradient id="ab" cx="0.8" cy="0.85" r="0.8"><stop offset="0" stop-color="${artist.palette[1]}"/><stop offset="1" stop-color="${artist.palette[0]}" stop-opacity="0"/></radialGradient>
|
|
</defs>
|
|
<rect width="512" height="512" fill="url(#aa)"/>
|
|
<circle cx="${280 + r1}" cy="${r2}" r="260" fill="url(#ab)" opacity="0.8"/>
|
|
<circle cx="256" cy="256" r="170" fill="#000000" opacity="0.28"/>
|
|
<text x="256" y="296" font-family="Arial Black, Helvetica, sans-serif" font-size="120" font-weight="900" fill="#ffffff" text-anchor="middle">${initials}</text>
|
|
</svg>`;
|
|
return svgURI(svg);
|
|
},
|
|
placeholder() {
|
|
return svgURI(`<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><rect width="512" height="512" fill="#1c1c1e"/><path fill="#48484a" d="M230 160v98.55A64 64 0 1 0 262 256V208h96v-48h-96z"/></svg>`);
|
|
}
|
|
};
|