taste canvases read the theme's colours instead of hard-coded dark ones
shots / shots (push) Successful in 2m22s
shots / shots (push) Successful in 2m22s
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01K6897PWcUEwHiqZMcVnNF6
This commit is contained in:
1 parent
2beac64165
commit
83bf464b49
1 file changed
+11
-10
@@ -165,12 +165,13 @@ const guessText = (spec) => spec && spec.guess != null ? ` · ${Math.round(spec.
|
||||
})();
|
||||
|
||||
/* ---------- TASTE: the brain and the map ---------- */
|
||||
const cssv = (n) => getComputedStyle(document.documentElement).getPropertyValue(n).trim();
|
||||
function drawBrain(canvas, net, spec, pulse = 0) {
|
||||
const ctx = canvas.getContext("2d"), W = canvas.width, H = canvas.height;
|
||||
ctx.clearRect(0, 0, W, H); ctx.fillStyle = "#121216"; ctx.fillRect(0, 0, W, H);
|
||||
ctx.clearRect(0, 0, W, H); ctx.fillStyle = cssv("--card"); ctx.fillRect(0, 0, W, H);
|
||||
const cols = [W * 0.16, W * 0.5, W * 0.86], ins = ["tempo", "energy", "key·x", "key·y", "minor", "words"];
|
||||
const yI = (i) => H * (0.12 + 0.76 * i / 5), yH = (i) => H * (0.07 + 0.86 * i / (NH - 1)), yO = H / 2;
|
||||
if (!net) { ctx.fillStyle = "#8a8a96"; ctx.font = `${W * 0.035}px -apple-system, system-ui, sans-serif`; ctx.textAlign = "center"; ctx.fillText("react to three tracks and the brain wakes up", W / 2, H / 2); return; }
|
||||
if (!net) { ctx.fillStyle = cssv("--dim"); ctx.font = `${W * 0.035}px -apple-system, system-ui, sans-serif`; ctx.textAlign = "center"; ctx.fillText("react to three tracks and the brain wakes up", W / 2, H / 2); return; }
|
||||
const x = spec ? feats(spec) : new Array(NIN).fill(0), { h, y } = net.forward(x);
|
||||
// the words block is shown as one input: its activation is how much of the song's wording the net recognises
|
||||
let wordsAct = 0; for (let j = NUM; j < NIN; j++) wordsAct += Math.abs(x[j]); wordsAct = Math.min(1, wordsAct / 3);
|
||||
@@ -185,20 +186,20 @@ function drawBrain(canvas, net, spec, pulse = 0) {
|
||||
const glow = Math.abs(a) * (1 + pulse);
|
||||
ctx.beginPath(); ctx.arc(cx, cy, r + 10 * glow, 0, Math.PI * 2); ctx.fillStyle = `hsl(${a >= 0 ? 44 : 220} 80% 65% / ${0.18 * glow})`; ctx.fill();
|
||||
ctx.beginPath(); ctx.arc(cx, cy, r, 0, Math.PI * 2); ctx.fillStyle = `hsl(${a >= 0 ? 44 : 220} ${40 + 50 * Math.abs(a)}% ${35 + 35 * Math.abs(a)}%)`; ctx.fill();
|
||||
if (label) { ctx.fillStyle = "#8a8a96"; ctx.font = `600 ${W * 0.026}px ui-monospace, Menlo, monospace`; ctx.textAlign = "right"; ctx.fillText(label, cx - r - 8, cy + 4); }
|
||||
if (label) { ctx.fillStyle = cssv("--dim"); ctx.font = `600 ${W * 0.026}px ui-monospace, Menlo, monospace`; ctx.textAlign = "right"; ctx.fillText(label, cx - r - 8, cy + 4); }
|
||||
};
|
||||
shown.forEach((v, j) => node(cols[0], yI(j), W * 0.018, v, ins[j]));
|
||||
h.forEach((v, k) => node(cols[1], yH(k), W * 0.017, v));
|
||||
node(cols[2], yO, W * 0.034, y * 2 - 1);
|
||||
ctx.fillStyle = "#ededf0"; ctx.font = `600 ${W * 0.03}px ui-monospace, Menlo, monospace`; ctx.textAlign = "left"; ctx.fillText(`${Math.round(y * 100)}%`, cols[2] + W * 0.05, yO + 5);
|
||||
ctx.fillStyle = "#8a8a96"; ctx.font = `${W * 0.024}px ui-monospace, Menlo, monospace`; ctx.fillText(spec ? "would like this" : "", cols[2] + W * 0.05, yO + 5 + W * 0.03);
|
||||
ctx.fillStyle = cssv("--ink"); ctx.font = `600 ${W * 0.03}px ui-monospace, Menlo, monospace`; ctx.textAlign = "left"; ctx.fillText(`${Math.round(y * 100)}%`, cols[2] + W * 0.05, yO + 5);
|
||||
ctx.fillStyle = cssv("--dim"); ctx.font = `${W * 0.024}px ui-monospace, Menlo, monospace`; ctx.fillText(spec ? "would like this" : "", cols[2] + W * 0.05, yO + 5 + W * 0.03);
|
||||
}
|
||||
function drawTaste(rows, title, net) {
|
||||
const c = $("#tasteMap"), ctx = c.getContext("2d"), W = c.width, H = c.height, pad = 70;
|
||||
const X = (bpm) => pad + (Math.min(180, Math.max(60, bpm)) - 60) / 120 * (W - 2 * pad);
|
||||
const Y = (en) => H - pad - Math.min(1, Math.max(0, en)) * (H - 2 * pad);
|
||||
const pts = rows.map((t) => ({ x: X(+t.spec.bpm || 100), y: Y(+t.spec.energy || 0.5), w: reactionWeight(t.spec, t), hue: keyHue(t.spec.key), minor: /m(in|inor)?\b/i.test(t.spec.key || "") && !/maj/i.test(t.spec.key || ""), t }));
|
||||
ctx.fillStyle = "#121216"; ctx.fillRect(0, 0, W, H);
|
||||
ctx.fillStyle = cssv("--card"); ctx.fillRect(0, 0, W, H);
|
||||
// the field: the net's prediction, in the station's usual key; lit gold where it says yes, blue where no
|
||||
const keys = {}; for (const t of rows) keys[t.spec.key] = (keys[t.spec.key] || 0) + 1;
|
||||
const key = Object.entries(keys).sort((a, b) => b[1] - a[1])[0]?.[0] || "A minor";
|
||||
@@ -212,8 +213,8 @@ function drawTaste(rows, title, net) {
|
||||
ctx.fillStyle = v > 0 ? `hsl(44 60% 60% / ${0.5 * Math.abs(v)})` : `hsl(220 30% 45% / ${0.45 * Math.abs(v)})`;
|
||||
ctx.fillRect(gx, gy, cell, cell);
|
||||
}
|
||||
ctx.strokeStyle = "#232329"; ctx.lineWidth = 2; ctx.strokeRect(pad, pad, W - 2 * pad, H - 2 * pad);
|
||||
ctx.fillStyle = "#8a8a96"; ctx.font = `600 ${W * 0.018}px ui-monospace, Menlo, monospace`; ctx.textAlign = "center";
|
||||
ctx.strokeStyle = cssv("--line"); ctx.lineWidth = 2; ctx.strokeRect(pad, pad, W - 2 * pad, H - 2 * pad);
|
||||
ctx.fillStyle = cssv("--dim"); ctx.font = `600 ${W * 0.018}px ui-monospace, Menlo, monospace`; ctx.textAlign = "center";
|
||||
for (const b of [60, 90, 120, 150, 180]) ctx.fillText(b + "", X(b), H - pad + 34);
|
||||
ctx.textAlign = "right"; for (const e of [0, 0.5, 1]) ctx.fillText(e === 0 ? "calm" : e === 1 ? "wild" : "·", pad - 14, Y(e) + 6);
|
||||
// the points, with the listener's emoji over them
|
||||
@@ -227,12 +228,12 @@ function drawTaste(rows, title, net) {
|
||||
const em = reactionEmoji(p.t.spec.reaction);
|
||||
const tg = tagSignals(p.t.spec), tagMark = tg.length ? ` ${tg.filter((s) => s.like).length}▲${tg.filter((s) => !s.like).length}▼` : "";
|
||||
const tag = [...em].slice(0, 4).join("") + ((p.t.plays || 0) > 1 ? `×${p.t.plays}` : "") + tagMark;
|
||||
if (tag) { ctx.font = `${W * 0.024}px -apple-system, system-ui, sans-serif`; ctx.fillStyle = "#ededf0"; ctx.fillText(tag, p.x, p.y - r - 8); }
|
||||
if (tag) { ctx.font = `${W * 0.024}px -apple-system, system-ui, sans-serif`; ctx.fillStyle = cssv("--ink"); ctx.fillText(tag, p.x, p.y - r - 8); }
|
||||
}
|
||||
// the track in the oven, as a hollow mark
|
||||
const nx = state.nextJob && state.nextJob.spec;
|
||||
if (nx && rows.some((t) => t.spec.stationId === nx.stationId || title === "ALL")) {
|
||||
ctx.beginPath(); ctx.arc(X(+nx.bpm || 100), Y(+nx.energy || 0.5), W * 0.014, 0, Math.PI * 2); ctx.setLineDash([4, 4]); ctx.lineWidth = 2; ctx.strokeStyle = "#ededf0"; ctx.stroke(); ctx.setLineDash([]);
|
||||
ctx.beginPath(); ctx.arc(X(+nx.bpm || 100), Y(+nx.energy || 0.5), W * 0.014, 0, Math.PI * 2); ctx.setLineDash([4, 4]); ctx.lineWidth = 2; ctx.strokeStyle = cssv("--ink"); ctx.stroke(); ctx.setLineDash([]);
|
||||
}
|
||||
const warm = pts.filter((p) => p.w >= 0.25).length, cold = pts.filter((p) => p.w <= -0.25).length;
|
||||
$("#tasteNote").textContent = !pts.length ? "Nothing heard here yet." :
|
||||
|
||||
Reference in new issue
Block a user