Monorepo for Aesthetic.Computer aesthetic.computer
4
fork

Configure Feed

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

Fix spreadnob UI bridge and compact rack layout

+130 -33
+5 -5
ac-m4l/AC-KnobMap.amxd.json
··· 965 965 230.0, 966 966 22.0 967 967 ], 968 - "text": "script if(window.acSpreadnobSetRange)window.acSpreadnobSetRange($1,$2)" 968 + "text": "executejavascript if(window.acSpreadnobSetRange)window.acSpreadnobSetRange($1,$2)" 969 969 } 970 970 }, 971 971 { ··· 983 983 205.0, 984 984 22.0 985 985 ], 986 - "text": "script if(window.acSpreadnobNote)window.acSpreadnobNote($1)" 986 + "text": "executejavascript if(window.acSpreadnobNote){window.acSpreadnobNote($1)}else{console.log(\"[SPREADNOB-UI/MISS NOTE]\",$1)}" 987 987 } 988 988 }, 989 989 { ··· 1001 1001 215.0, 1002 1002 22.0 1003 1003 ], 1004 - "text": "script if(window.acSpreadnobSetValue)window.acSpreadnobSetValue($1)" 1004 + "text": "executejavascript if(window.acSpreadnobSetValue)window.acSpreadnobSetValue($1)" 1005 1005 } 1006 1006 }, 1007 1007 { ··· 1019 1019 220.0, 1020 1020 22.0 1021 1021 ], 1022 - "text": "script if(window.acSpreadnobSetActive)window.acSpreadnobSetActive($1)" 1022 + "text": "executejavascript if(window.acSpreadnobSetActive){window.acSpreadnobSetActive($1)}else{console.log(\"[SPREADNOB-UI/MISS ACTIVE]\",$1)}" 1023 1023 } 1024 1024 }, 1025 1025 { ··· 1055 1055 255.0, 1056 1056 22.0 1057 1057 ], 1058 - "text": "script if(window.acSpreadnobSetTarget)window.acSpreadnobSetTarget(\"$1\")" 1058 + "text": "executejavascript if(window.acSpreadnobSetTarget)window.acSpreadnobSetTarget(\"$1\")" 1059 1059 } 1060 1060 }, 1061 1061 {
+125 -28
system/public/aesthetic.computer/disks/spreadnob.mjs
··· 61 61 return clamp(high - low + 1, 1, KEY_LABELS.length); 62 62 } 63 63 64 + function noteRangeState(note = currentNote) { 65 + if (!Number.isFinite(note)) return "none"; 66 + if (note < low) return "below"; 67 + if (note > high) return "above"; 68 + return "inside"; 69 + } 70 + 71 + function getLayout(screen) { 72 + const compact = screen.height <= 194; 73 + return compact 74 + ? { 75 + compact, 76 + inset: 4, 77 + headerH: 22, 78 + titleX: 9, 79 + titleY: 8, 80 + pillW: 40, 81 + pillH: 12, 82 + targetY: 31, 83 + subY: 45, 84 + statY: 54, 85 + statH: 15, 86 + modeY: 73, 87 + keyboardY: 83, 88 + keyboardH: 34, 89 + statusBaseY: 124, 90 + warningY: 124, 91 + footerLabelY: screen.height - 28, 92 + footerY: screen.height - 16, 93 + btnY: screen.height - 14, 94 + btnW: 14, 95 + btnH: 11, 96 + resetW: 50, 97 + } 98 + : { 99 + compact, 100 + inset: 6, 101 + headerH: 28, 102 + titleX: 13, 103 + titleY: 10, 104 + pillW: 50, 105 + pillH: 14, 106 + targetY: 42, 107 + subY: 58, 108 + statY: 67, 109 + statH: 17, 110 + modeY: 92, 111 + keyboardY: 97, 112 + keyboardH: 46, 113 + statusBaseY: 152, 114 + warningY: 152, 115 + footerLabelY: screen.height - 28, 116 + footerY: screen.height - 18, 117 + btnY: screen.height - 16, 118 + btnW: 16, 119 + btnH: 13, 120 + resetW: 56, 121 + }; 122 + } 123 + 64 124 function setRange(nextLow, nextHigh, { emit = false } = {}) { 65 125 let resolvedLow = clamp(Math.round(nextLow), 0, 127); 66 126 let resolvedHigh = clamp(Math.round(nextHigh), 0, 127); ··· 90 150 function updateFromMessage(data = {}) { 91 151 if (data.type === "spreadnob:active") { 92 152 active = !!Number(data.active); 153 + console.log("[SPREADNOB-UI/ACTIVE]", active ? 1 : 0); 93 154 requestPaint(); 94 155 return; 95 156 } 96 157 97 158 if (data.type === "spreadnob:target") { 98 159 target = String(data.name || "").trim(); 160 + console.log("[SPREADNOB-UI/TARGET]", target || "(none)"); 99 161 requestPaint(); 100 162 return; 101 163 } ··· 117 179 currentNote = Number.isFinite(num) ? num : null; 118 180 noteHits++; 119 181 flash = active ? 1 : 0.45; 182 + console.log("[SPREADNOB-UI/NOTE]", currentNote, "range", `${low}..${high}`); 120 183 requestPaint(); 121 184 } 122 185 } ··· 128 191 if (layoutKey === key) return; 129 192 layoutKey = key; 130 193 131 - const footerY = screen.height - 18; 132 - const btnY = footerY + 2; 194 + const layout = getLayout(screen); 195 + const footerY = layout.footerY; 196 + const btnY = layout.btnY; 133 197 const sideX = 8; 134 - const btnW = 16; 135 - const btnH = 13; 198 + const btnW = layout.btnW; 199 + const btnH = layout.btnH; 136 200 const chipW = 48; 137 201 const rightX = screen.width - sideX - btnW; 138 - const resetW = 56; 202 + const resetW = layout.resetW; 139 203 const resetX = Math.round((screen.width - resetW) / 2); 140 204 141 205 lowDownBtn = new uiKit.Button(sideX, btnY, btnW, btnH); ··· 192 256 193 257 const w = screen.width; 194 258 const h = screen.height; 259 + const layout = getLayout(screen); 195 260 const targetName = target || "CLICK ABLETON KNOB"; 196 261 const activeFill = active ? [110, 255, 120] : [255, 90, 95]; 197 262 const shell = active ? [19, 33, 20] : [36, 17, 24]; 198 263 const border = active ? [60, 180, 90] : [170, 50, 85]; 199 264 const flashAlpha = Math.round(110 * flash); 200 - const keyboardY = 97; 265 + const keyboardY = layout.keyboardY; 201 266 const keyboardX = 10; 202 267 const keyboardW = w - 20; 203 - const keyboardH = 46; 268 + const keyboardH = layout.keyboardH; 204 269 const count = rangeCount(); 270 + const noteState = noteRangeState(); 205 271 const gap = 2; 206 272 const keyW = Math.max(8, Math.floor((keyboardW - gap * (KEY_LABELS.length - 1)) / KEY_LABELS.length)); 207 273 const totalKeyW = keyW * KEY_LABELS.length + gap * (KEY_LABELS.length - 1); ··· 209 275 210 276 wipe(8, 10, 12); 211 277 ink(...shell).box(0, 0, w, h); 212 - ink(255, 80, 150, 28).box(0, 0, w, 28); 213 - ink(40, 120, 80, active ? 44 : 18).box(0, 24, w, h - 24); 278 + ink(255, 80, 150, 28).box(0, 0, w, layout.headerH); 279 + ink(40, 120, 80, active ? 44 : 18).box(0, layout.headerH - 4, w, h - (layout.headerH - 4)); 214 280 215 281 if (flashAlpha > 0) { 216 282 ink(active ? 110 : 255, active ? 255 : 105, active ? 150 : 145, flashAlpha).box(0, 0, w, h); 217 283 } 218 284 219 - ink(...border).box(6, 6, w - 12, h - 12); 220 - ink(255, 115, 180, 120).line(10, 34, w - 10, 34); 221 - ink(255, 115, 180, 60).line(10, 88, w - 10, 88); 222 - ink(255, 115, 180, 60).line(10, 149, w - 10, 149); 285 + ink(...border).box(layout.inset, layout.inset, w - layout.inset * 2, h - layout.inset * 2); 286 + ink(255, 115, 180, 120).line(8, layout.headerH + 6, w - 8, layout.headerH + 6); 287 + ink(255, 115, 180, 60).line(8, layout.modeY + 8, w - 8, layout.modeY + 8); 288 + ink(255, 115, 180, 60).line(8, layout.statusBaseY - 3, w - 8, layout.statusBaseY - 3); 223 289 224 - ink(255, 120, 185).write("spreadnob", { x: 13, y: 10 }, undefined, undefined, false, FONT); 290 + ink(255, 120, 185).write("spreadnob", { x: layout.titleX, y: layout.titleY }, undefined, undefined, false, FONT); 225 291 226 - ink(...activeFill).box(w - 64, 10, 50, 14); 227 - ink(10, 18, 12).write(active ? "ON" : "OFF", { x: w - 49, y: 11 }, undefined, undefined, false, FONT); 292 + ink(...activeFill).box(w - layout.pillW - 10, layout.titleY, layout.pillW, layout.pillH); 293 + ink(10, 18, 12).write( 294 + active ? "ON" : "OFF", 295 + { x: w - layout.pillW + 2 - 10, y: layout.titleY + 1 }, 296 + undefined, 297 + undefined, 298 + false, 299 + FONT, 300 + ); 228 301 229 - ink(255, 190, 220).write(targetName, { x: 13, y: 42 }, undefined, w - 26, true, FONT); 302 + ink(255, 190, 220).write(targetName, { x: 10, y: layout.targetY }, undefined, w - 20, true, FONT); 230 303 ink(170, 145, 170).write( 231 304 active ? "follows selected knob" : "device bypassed by ableton", 232 - { x: 13, y: 58 }, 305 + { x: 10, y: layout.subY }, 233 306 undefined, 234 307 undefined, 235 308 false, 236 309 MINI_FONT, 237 310 ); 238 311 239 - const statY = 67; 312 + const statY = layout.statY; 240 313 const statW = Math.floor((w - 34) / 3); 241 314 const statXs = [13, 13 + statW + 4, 13 + (statW + 4) * 2]; 242 315 const valueText = value === null ? "--" : value.toFixed(3); ··· 244 317 const rangeText = `${low}..${high}`; 245 318 246 319 for (const x of statXs) { 247 - ink(24, 18, 28).box(x, statY, statW, 17); 320 + ink(24, 18, 28).box(x, statY, statW, layout.statH); 248 321 ink(255, 255, 255, 24).box(x, statY, statW, 1); 249 322 } 250 323 ··· 259 332 260 333 ink(255, 135, 200).write( 261 334 isDefaultRange() ? "ableton qwerty spread" : "custom key spread", 262 - { x: 13, y: 92 }, 335 + { x: 10, y: layout.modeY }, 263 336 undefined, 264 337 undefined, 265 338 false, ··· 273 346 const inRange = i < count; 274 347 const midi = low + i; 275 348 const current = currentNote === midi; 349 + const edgeCurrent = 350 + (noteState === "below" && i === 0) || 351 + (noteState === "above" && i === count - 1); 276 352 const black = inRange && isBlack(midi); 277 353 const baseY = keyboardY + (black ? 4 : 0); 278 354 const keyH = black ? keyboardH - 14 : keyboardH; 279 355 const rgb = inRange ? noteColor(midi) : [42, 42, 46]; 280 - const fill = current 356 + const fill = current || edgeCurrent 281 357 ? [255, 105, 182] 282 358 : black 283 359 ? [rgb[0] * 0.45, rgb[1] * 0.45, rgb[2] * 0.45] 284 360 : [rgb[0] * 0.7, rgb[1] * 0.7, rgb[2] * 0.7]; 285 361 286 362 ink(...fill).box(x, baseY, keyW, keyH); 287 - ink(current ? 255 : 255, current ? 240 : 255, current ? 245 : 255, current ? 150 : 24).box(x, baseY, keyW, 1); 363 + ink( 364 + 255, 365 + current || edgeCurrent ? 240 : 255, 366 + current || edgeCurrent ? 245 : 255, 367 + current || edgeCurrent ? 150 : 24, 368 + ).box(x, baseY, keyW, 1); 288 369 289 370 if (inRange) { 290 371 ink(250, 248, 252).write(KEY_LABELS[i], { x: x + 2, y: keyboardY + keyboardH - 11 }, undefined, undefined, false, MINI_FONT); 291 372 ink(black ? 255 : 25, black ? 190 : 34, black ? 220 : 42).write(String(midi), { x: x + 1, y: baseY + 1 }, undefined, undefined, false, MINI_FONT); 292 - if (current) { 373 + if (current || edgeCurrent) { 293 374 ink(255, 245, 250).line(x, baseY + keyH, x + keyW, baseY + keyH); 294 375 } 295 376 } 296 377 } 297 378 379 + const statusY = noteState !== "inside" && currentNote !== null 380 + ? layout.statusBaseY + 14 381 + : layout.statusBaseY; 382 + 383 + if (noteState !== "inside" && currentNote !== null) { 384 + const warning = noteState === "below" 385 + ? `${currentNote} below visible range` 386 + : `${currentNote} above visible range`; 387 + ink(255, 105, 182).box(12, layout.warningY, w - 24, 12); 388 + ink(20, 10, 18).write(warning, { x: 15, y: layout.warningY + 2 }, undefined, w - 30, true, MINI_FONT); 389 + } 390 + 298 391 ink(160, 145, 165).write( 299 - currentNote === null ? "press a note to see the map move" : `${noteLabel(currentNote)} hit ${noteHits}`, 300 - { x: 12, y: 152 }, 392 + currentNote === null 393 + ? "press a note to see the map move" 394 + : noteState === "inside" 395 + ? `${noteLabel(currentNote)} hit ${noteHits}` 396 + : `${noteLabel(currentNote)} hit ${noteHits} · shift range if needed`, 397 + { x: 12, y: statusY }, 301 398 undefined, 302 399 w - 24, 303 400 true, 304 401 MINI_FONT, 305 402 ); 306 403 307 - ink(110, 230, 170).write(`${low} ${noteLabel(low)}`, { x: 8, y: h - 28 }, undefined, undefined, false, MINI_FONT); 308 - ink(110, 230, 170).write(`${high} ${noteLabel(high)}`, { right: 8, y: h - 28 }, undefined, undefined, false, MINI_FONT); 404 + ink(110, 230, 170).write(`${low} ${noteLabel(low)}`, { x: 8, y: layout.footerLabelY }, undefined, undefined, false, MINI_FONT); 405 + ink(110, 230, 170).write(`${high} ${noteLabel(high)}`, { right: 8, y: layout.footerLabelY }, undefined, undefined, false, MINI_FONT); 309 406 310 407 paintButton({ button: lowDownBtn, label: "-", ink }); 311 408 paintButton({ button: lowUpBtn, label: "+", ink });