Monorepo for Aesthetic.Computer aesthetic.computer
4
fork

Configure Feed

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

notepat-remote: square pads + notepat.mjs shake/shadow labels

Pad cells now sized at min(colW, rowH) so the buttons stay square no
matter the device width; grid centers horizontally, extra vertical
space falls below (reserved for future readouts).

Labels get the notepat.mjs treatment: per-pad jitter while held (+brief
decay on release) plus a 1px drop shadow (auto-inverted for dark vs
light label colors) so the typography pulses with each strike.

+28 -10
+28 -10
system/public/aesthetic.computer/disks/notepat-remote.mjs
··· 472 472 y += 10; 473 473 474 474 // ── Button grid area: two 4×3 octave blocks side-by-side ───────────── 475 - // Pixel-perfect: spans full width (0..W), fills from gridTop down to H. 476 - // Pads butt up against each other — rainbow palette gives enough natural 477 - // contrast that explicit separators add noise. 475 + // Pads are always square — cell size is the min of width/cols and 476 + // height/rows, so the grid stays piano-shaped no matter how narrow or 477 + // tall the device is. Grid centers horizontally; extra vertical space 478 + // falls below (kept for future readouts). 478 479 const gridTop = y + 1; 479 - // Pre-compute row and column extents so every pixel is accounted for and 480 - // adjacent pads share the same boundary line (no 1px gaps or overlaps). 481 480 const cols = 8; // 4 pads × 2 octave blocks 482 481 const rows = 3; 482 + const cellSize = max(1, min(floor(W / cols), floor((H - gridTop) / rows))); 483 + const gridW = cellSize * cols; 484 + const gridLeft = floor((W - gridW) / 2); 483 485 const colEdges = []; 484 - for (let c = 0; c <= cols; c += 1) colEdges.push(floor((c * W) / cols)); 486 + for (let c = 0; c <= cols; c += 1) colEdges.push(gridLeft + c * cellSize); 485 487 const rowEdges = []; 486 - for (let r = 0; r <= rows; r += 1) rowEdges.push(gridTop + floor((r * (H - gridTop)) / rows)); 488 + for (let r = 0; r <= rows; r += 1) rowEdges.push(gridTop + r * cellSize); 487 489 488 490 buttons = []; 489 491 for (let octIdx = 0; octIdx < OCTAVE_GRIDS.length; octIdx += 1) { ··· 561 563 ]; 562 564 ink(...borderColor).box(px, py, pw, ph, "outline"); 563 565 564 - // Main label = note name (C, C#, D…), small hint = keyboard key. 565 - // Measured against AC's default 6×10 glyph grid. 566 + // Main label = note name (C, C#, D…). Matches notepat.mjs web 567 + // piece: jittery shake while held + 1px drop shadow so the 568 + // typography pulses with each strike. 566 569 const charW = 6; 567 570 const charH = 10; 568 571 const label = nameShort; 569 572 const labelW = label.length * charW; 570 573 const labelX = px + floor((pw - labelW) / 2); 571 574 const labelY = py + floor((ph - charH) / 2); 575 + // Shake: 2px jitter while held, 1px briefly after release. 576 + const shakeAmount = held && focused 577 + ? 2 578 + : recentFlash && focused && sinceNote < 6 579 + ? 1 580 + : 0; 581 + const shakeX = shakeAmount > 0 582 + ? floor((Math.random() - 0.5) * shakeAmount * 2) 583 + : 0; 584 + const shakeY = shakeAmount > 0 585 + ? floor((Math.random() - 0.5) * shakeAmount * 2) 586 + : 0; 572 587 // Black keys stay dark when held (fill ≈ graphite), so dark label 573 588 // text disappears. Keep the light label for black keys even in 574 589 // the held state; only white keys (bright rainbow fill) flip to ··· 576 591 const labelColor = 577 592 held && focused && !black ? [10, 10, 14] : 578 593 black ? [220, 225, 235] : [20, 22, 28]; 579 - ink(...labelColor).write(label, { x: labelX, y: labelY }); 594 + // Drop shadow — opposite luminance of the label, slight offset. 595 + const shadowColor = labelColor[0] < 128 ? [240, 240, 240, 140] : [0, 0, 0, 180]; 596 + ink(...shadowColor).write(label, { x: labelX + shakeX + 1, y: labelY + shakeY + 1 }); 597 + ink(...labelColor).write(label, { x: labelX + shakeX, y: labelY + shakeY }); 580 598 } 581 599 } 582 600 }
system/public/m4l/notepat.com.amxd

This is a binary file and will not be displayed.