music video renderer web app deftoku.digi.rip
audio visualizer webapp
1

Configure Feed

Select the types of activity you want to include in your feed.

visualizers: now grouped by category, persist last-selected and fall back to default or first option

- also organized visualizers folder to reflect grouping

digi.rip (Jun 21, 2026, 11:25 AM EDT) 8df464a0 bc20eefe

+64 -10
+1 -5
index.html
··· 68 68 </div> 69 69 70 70 <div class="menu-group" id="vis-group"> 71 - <select name="visualizer" id="vis-select"> 72 - <option value="cdtop">cd-top</option> 73 - <option value="cdbottom">cd-bottom</option> 74 - <option value="bars">bars</option> 75 - </select> 71 + <select name="visualizer" id="vis-select"></select> 76 72 <div id="vis-params"></div> 77 73 </div> 78 74 </div>
+57 -5
src/controller.ts
··· 11 11 12 12 // visualizers 13 13 import { 14 + category as barsCategory, 14 15 draw as bars, 15 16 params as barsParams, 16 17 preview as barsPreview, 17 - } from "./visualizers/bars.ts"; 18 + } from "./visualizers/classic/bars.ts"; 18 19 import { 20 + category as cdbottomCategory, 19 21 draw as cdbottom, 20 22 params as cdbottomParams, 21 23 preview as cdbottomPreview, 22 - } from "./visualizers/cd-bottom.ts"; 24 + } from "./visualizers/media/cd-bottom.ts"; 23 25 import { 26 + category as cdtopCategory, 24 27 draw as cdtop, 25 28 params as cdtopParams, 26 29 preview as cdtopPreview, 27 - } from "./visualizers/cd-top.ts"; 30 + } from "./visualizers/media/cd-top.ts"; 28 31 type VisualizerName = keyof typeof visualizers; 29 32 30 33 // visualizer opts registry, bundles draw & params ··· 51 54 step?: number; 52 55 label: string; 53 56 }>; 57 + category: string; 58 + default?: boolean; 54 59 }; 55 60 56 61 const visualizers: Record<string, VisualizerDef> = { 57 - bars: { draw: bars, params: barsParams, preview: barsPreview }, 62 + bars: { 63 + draw: bars, 64 + params: barsParams, 65 + preview: barsPreview, 66 + category: barsCategory, 67 + }, 58 68 cdbottom: { 59 69 draw: cdbottom, 60 70 params: cdbottomParams, 61 71 preview: cdbottomPreview, 72 + category: cdbottomCategory, 62 73 }, 63 - cdtop: { draw: cdtop, params: cdtopParams, preview: cdtopPreview }, 74 + cdtop: { 75 + draw: cdtop, 76 + params: cdtopParams, 77 + preview: cdtopPreview, 78 + category: cdtopCategory, 79 + default: true, 80 + }, 64 81 }; 65 82 66 83 const qualityMap: Record<string, Quality> = { ··· 96 113 fitCanvas(canvas); 97 114 98 115 const select = document.querySelector<HTMLSelectElement>("#vis-select")!; 116 + 117 + function buildVisSelect() { 118 + select.innerHTML = ""; 119 + const byCategory = new Map<string, Array<[string, VisualizerDef]>>(); 120 + for (const [name, def] of Object.entries(visualizers)) { 121 + const cat = def.category ?? "Other"; 122 + if (!byCategory.has(cat)) byCategory.set(cat, []); 123 + byCategory.get(cat)!.push([name, def]); 124 + } 125 + for (const [cat, entries] of byCategory) { 126 + const group = document.createElement("optgroup"); 127 + group.label = cat; 128 + for (const [name] of entries) { 129 + const opt = document.createElement("option"); 130 + opt.value = name; 131 + opt.textContent = name; 132 + group.appendChild(opt); 133 + } 134 + select.appendChild(group); 135 + } 136 + // restore last-used, then fall back to default, then first option 137 + const saved = localStorage.getItem("vis"); 138 + if (saved && visualizers[saved]) { 139 + select.value = saved; 140 + } else { 141 + const def = Object.entries(visualizers).find(([, v]) => v.default); 142 + select.value = def ? def[0] : select.querySelector("option")!.value; 143 + } 144 + } 145 + buildVisSelect(); 146 + 147 + // persist selection 148 + select.addEventListener("change", () => { 149 + localStorage.setItem("vis", select.value); 150 + }); 99 151 100 152 let stopPreview: (() => void) | null = null; 101 153
+2
src/visualizers/bars.ts src/visualizers/classic/bars.ts
··· 1 + export const category = "classic"; 2 + 1 3 export const params = [ 2 4 { 3 5 key: "barCount",
+2
src/visualizers/cd-bottom.ts src/visualizers/media/cd-bottom.ts
··· 6 6 const STREAK_SIZE_RATIO = 1.5; 7 7 const OUTER_EDGE_THICKNESS_RATIO = 0.012; 8 8 9 + export const category = "media"; 10 + 9 11 export const params = [ 10 12 { 11 13 key: "speed",
+2
src/visualizers/cd-top.ts src/visualizers/media/cd-top.ts
··· 6 6 const STREAK_SIZE_RATIO = 1.5; 7 7 const OUTER_EDGE_THICKNESS_RATIO = 0.012; 8 8 9 + export const category = "media"; 10 + 9 11 export const params = [ 10 12 { 11 13 key: "speed",