diff --git a/flow-state/.claude/settings.json b/flow-state/.claude/settings.json new file mode 100644 index 0000000..f65aa61 --- /dev/null +++ b/flow-state/.claude/settings.json @@ -0,0 +1,7 @@ +{ + "permissions": { + "allow": [ + "Bash(npm run lint:scenes *)" + ] + } +} diff --git a/flow-state/filmstrip.html b/flow-state/filmstrip.html index 3f11ee3..8718e24 100644 --- a/flow-state/filmstrip.html +++ b/flow-state/filmstrip.html @@ -39,6 +39,15 @@ .row.churn { border-color: #eab308; } .row.arc { border-color: #22c55e; } .row.broken { border-color: #a855f7; background: #150e1c; } + .row.agitated { border-color: #f97316; background: #1a1210; } + .agit { color: #9aa3b5; font-size: 11px; } + .agit .meter { display: inline-block; width: 96px; height: 7px; background: #1a1e28; border-radius: 4px; vertical-align: middle; margin-right: 6px; } + .agit .meter i { display: block; height: 100%; border-radius: 4px 0 0 4px; } + .agit .meter i.low { background: #22c55e; } + .agit .meter i.mid { background: #eab308; } + .agit .meter i.high { background: #f97316; } + .agit b.agitated { color: #f97316; } + .agit b.calm { color: #22c55e; } .head { display: flex; align-items: baseline; gap: 12px; margin-bottom: 6px; flex-wrap: wrap; } .name { font-size: 14px; color: #e6eaf2; } .meta { color: #6b7280; font-size: 11px; } @@ -82,6 +91,7 @@ @@ -118,9 +128,13 @@ let rows = []; // Read against the arcless reference the variety report prints: around zero is // a video that is as unlike itself after ten seconds as after four minutes. -const grade = (row) => (row.error ? 'broken' - : row.direction < 0.15 ? 'static' - : row.direction < 0.45 ? 'churn' : 'arc'); +const AGIT_CEILING = 0.70; +const agitClass = (v) => (v == null ? 'low' : v >= AGIT_CEILING ? 'high' : v >= 0.50 ? 'mid' : 'low'); +const grade = (row) => { + if (row.error) return 'broken'; + if ((row.agitation ?? 0) >= AGIT_CEILING) return 'agitated'; + return row.direction < 0.15 ? 'static' : row.direction < 0.45 ? 'churn' : 'arc'; +}; // Nine stills are an argument about a video, and the only reply to them is the // video. The app takes the bank's wav straight from `?song=`, and the seed is @@ -140,13 +154,19 @@ const watchLink = (name) => function renderRow(row) { const el = document.createElement('div'); el.className = `row ${grade(row)}`; + const agit = row.agitation ?? 0; + const agitLabel = row.error ? '' : + ` ` + + ` ` + + `agit ${agit.toFixed(2)} · flash ${(row.agitationFlash ?? 0).toFixed(1)}/s · motion ${((row.agitationMotion ?? 0)*100).toFixed(0)}% · struct ${(row.agitationStructPeak ?? row.agitationStruct ?? row.peakStructure ?? 0).toFixed(2)}` + + ``; el.innerHTML = `
${row.name} watch ▸ ${row.bpm ?? '?'} bpm · ${row.sections ?? '?'} sections · ${row.director || ''} - direction ${(row.direction ?? 0).toFixed(2)} · drift ${(row.drift ?? 0).toFixed(3)} + direction ${(row.direction ?? 0).toFixed(2)} · drift ${(row.drift ?? 0).toFixed(3)}${agitLabel} ${row.error ? `${row.error}` : (row.storyLine || '')}
`; @@ -183,7 +203,8 @@ function draw() { const mode = sortSel.value; const order = songNames(); const sorted = rows.slice().sort((a, b) => ( - mode === 'name' ? order.indexOf(a.name) - order.indexOf(b.name) + mode === 'agitation' ? (b.agitation ?? 0) - (a.agitation ?? 0) + : mode === 'name' ? order.indexOf(a.name) - order.indexOf(b.name) : mode === 'drift' ? a.drift - b.drift : mode === 'plot' ? ((a.story?.plot || '').localeCompare(b.story?.plot || '') || a.direction - b.direction) : a.direction - b.direction)); @@ -196,10 +217,15 @@ sortSel.addEventListener('change', draw); function summarise(built) { const flat = rows.filter((r) => !r.error && r.direction < 0.15).length; + const validatedNote = rows.some((r) => r.validatedNote) ? ' · ' + rows.filter((r) => r.validatedNote).length + ' re-tuned' : ''; + const agited = rows.filter((r) => (r.agitation ?? 0) >= AGIT_CEILING).length; const meanDir = rows.length ? rows.reduce((a, r) => a + (r.direction || 0), 0) / rows.length : 0; + const meanAgit = rows.length + ? rows.reduce((a, r) => a + (r.agitation ?? 0), 0) / rows.length : 0; return `${rows.length} songs · every ${every}s of ${duration}s · ` + `mean direction ${meanDir.toFixed(2)} · ${flat} with no direction` + + ` · mean agit ${meanAgit.toFixed(2)} · ${agited} agitated (≥${AGIT_CEILING.toFixed(2)})${validatedNote}` + (built ? ` · built ${new Date(built).toLocaleString()}` : ''); } diff --git a/flow-state/gallery.html b/flow-state/gallery.html index 0912bc8..6d3d241 100644 --- a/flow-state/gallery.html +++ b/flow-state/gallery.html @@ -44,6 +44,12 @@ .row.thin { border-color: #eab308; } .row.good { border-color: #22c55e; } .row.broken { border-color: #a855f7; background: #150e1c; } + .row.agitated { border-color: #f97316; } + .comfort { color: #9aa3b5; font-size: 11px; } + .comfort .meter i.low { background: #22c55e; } + .comfort .meter i.mid { background: #eab308; } + .comfort .meter i.high { background: #ef4444; } + .comfort .meter i.hot { background: #f97316; } .head { display: flex; align-items: baseline; gap: 12px; margin-bottom: 6px; flex-wrap: wrap; } .name { font-size: 14px; color: #e6eaf2; } .fam { color: #6b7280; } @@ -132,6 +138,7 @@ +