diff --git a/frontend/src/components/DetailPanel.tsx b/frontend/src/components/DetailPanel.tsx index 8bc047f..cdef05a 100644 --- a/frontend/src/components/DetailPanel.tsx +++ b/frontend/src/components/DetailPanel.tsx @@ -1,4 +1,5 @@ import { useRef, useState, useEffect } from 'react' +import { getKeyColor, getBPMColor } from '../utils/musicColors' interface Clip { id: string @@ -260,18 +261,34 @@ export default function DetailPanel({ clip, onClose, onRename, onDelete, onUploa
{(clip.file_size_bytes / 1024).toFixed(0)} KB
)} - {clip.bpm && ( -{Math.round(clip.bpm)}
-{clip.key}
-{formatDate(clip.created_at)}
diff --git a/frontend/src/components/Gallery.tsx b/frontend/src/components/Gallery.tsx index 3171d5e..02dae7a 100644 --- a/frontend/src/components/Gallery.tsx +++ b/frontend/src/components/Gallery.tsx @@ -1,4 +1,5 @@ import { useState, useMemo, useRef } from 'react' +import { getKeyColor, getBPMColor } from '../utils/musicColors' const PAGE_SIZE = 10 @@ -246,16 +247,28 @@ export default function Gallery({ clips, onPlay, onDelete, onRename, onSelect, o {clip.duration_seconds}s {modelName(clip.model)} {formatDate(clip.created_at)} - {clip.bpm && ( - - {Math.round(clip.bpm)} BPM - - )} - {clip.key && ( - - {clip.key} - - )} + {clip.bpm && (() => { + const c = getBPMColor(clip.bpm) + return c ? ( + + {Math.round(clip.bpm)} BPM + + ) : null + })()} + {clip.key && (() => { + const c = getKeyColor(clip.key) + return c ? ( + + {clip.key} + + ) : null + })()}
@@ -386,16 +399,28 @@ export default function Gallery({ clips, onPlay, onDelete, onRename, onSelect, o
{clip.duration_seconds}s
{modelName(clip.model)}
- {clip.bpm && (
-
- {Math.round(clip.bpm)} BPM
-
- )}
- {clip.key && (
-
- {clip.key}
-
- )}
+ {clip.bpm && (() => {
+ const c = getBPMColor(clip.bpm)
+ return c ? (
+
+ {Math.round(clip.bpm)} BPM
+
+ ) : null
+ })()}
+ {clip.key && (() => {
+ const c = getKeyColor(clip.key)
+ return c ? (
+
+ {clip.key}
+
+ ) : null
+ })()}
{/* Error */}
diff --git a/frontend/src/utils/musicColors.ts b/frontend/src/utils/musicColors.ts
new file mode 100644
index 0000000..221d6aa
--- /dev/null
+++ b/frontend/src/utils/musicColors.ts
@@ -0,0 +1,128 @@
+/**
+ * Music color utilities — Camelot wheel key colors + BPM gradient.
+ *
+ * Key colors: Each key maps to a hue based on its Camelot wheel position.
+ * 12 positions × 30° = full color wheel. Major = bright, minor = slightly darker.
+ *
+ * BPM gradient: Two root tempos define the hue range.
+ * Default: 60 BPM (blue, calm) → 180 BPM (red, intense).
+ * Anything outside the range clamps to the nearest edge.
+ */
+
+// ─── Camelot Wheel Mapping ───────────────────────────────────────
+
+// Standard Camelot wheel: position → key name (as returned by librosa)
+const CAMELOT_MAJOR: Record