Files
musictest/js/artwork.js
T
arsam 6020fd05be Import source: js/artwork
Import the existing local project snapshot. This commit organizes existing files; it does not represent newly developed functionality.
2026-09-18 23:20:56 +03:30

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>`);
}
};