brain: track length is an input to the taste net
shots / shots (push) Canceled after 0s

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01K6897PWcUEwHiqZMcVnNF6
This commit is contained in:
teahubxyzandClaude Fable 5.1 committed 2026-10-21 01:29:58 +00:00
1 parent d9dbedd956
commit c82a340d15
1 file changed
+4 -3
+4 -3
View File
@@ -23,7 +23,7 @@ function reactionWeight(spec, row) {
// inputs: 5 numbers (tempo, energy, key on the circle, minor) + WORDS hashed slots for the song's words: the DJ's tags
// (full weight), the title (half) and the lyrics (a third). Signed hashing, so "wobble bass" and "harmonica" land in
// slots of their own and the net can learn them; the words block is unit-normalised so a wordy song isn't louder.
const NUM = 5, WORDS = 48, NIN = NUM + WORDS, NH = 12;
const NUM = 6, WORDS = 48, NIN = NUM + WORDS, NH = 12;
const tokens = (s) => String(s || "").toLowerCase().replace(/\[[^\]]*\]/g, " ").split(/[^a-z0-9#+']+/).filter((w) => w.length > 1 && !STOP.has(w));
const STOP = new Set(["the","and","a","an","of","to","in","on","with","for","is","it","my","me","i","you","we","your","our","this","that","at","by","or","as","be","are","was","so","no","not","do","oh","yeah","la","na","from","into","up","down","out","all","just","like","im","its","dont","can","will"]);
function feats(spec) {
@@ -31,6 +31,7 @@ function feats(spec) {
const h = keyHue(spec.key) * Math.PI / 180, minor = /m(in|inor)?\b/i.test(spec.key || "") && !/maj/i.test(spec.key || "");
const x = new Array(NIN).fill(0);
x[0] = (bpm - 60) / 60 - 1; x[1] = en * 2 - 1; x[2] = Math.cos(h); x[3] = Math.sin(h); x[4] = minor ? 1 : -1;
x[5] = (Math.min(300, Math.max(30, +spec.seconds || 120)) - 30) / 135 - 1; // length: 30 s → -1, 300 s → +1
const add = (words, w) => { for (const t of new Set(words)) { const hh = hash32("w:" + t); x[NUM + hh % WORDS] += ((hh >>> 16) & 1 ? 1 : -1) * w; } };
add(tokens(spec.tags), 1); add(tokens(spec.title), 0.5); add(tokens(spec.lyrics), 0.33);
let n = 0; for (let i = NUM; i < NIN; i++) n += x[i] * x[i]; n = Math.sqrt(n) || 1;
@@ -169,8 +170,8 @@ const cssv = (n) => getComputedStyle(document.documentElement).getPropertyValue(
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 = 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;
const cols = [W * 0.16, W * 0.5, W * 0.86], ins = ["tempo", "energy", "key·x", "key·y", "minor", "length", "words"];
const yI = (i) => H * (0.1 + 0.8 * i / NUM), yH = (i) => H * (0.07 + 0.86 * i / (NH - 1)), yO = H / 2;
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