Monorepo for Aesthetic.Computer aesthetic.computer
4
fork

Configure Feed

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

fix notepat.com boot and os link

+152 -78
+1 -1
lith/Caddyfile
··· 343 343 @mainspa host aesthetic.computer www.aesthetic.computer kidlisp.com www.kidlisp.com notepat.com www.notepat.com p5.aesthetic.computer sitemap.aesthetic.computer 344 344 handle @mainspa { 345 345 # Preload critical assets (browser starts fetching before parsing HTML) 346 - header Link "</aesthetic.computer/boot.mjs>; rel=preload; as=script; crossorigin, </aesthetic.computer/style.css>; rel=preload; as=style" 346 + header Link "</aesthetic.computer/boot.mjs>; rel=preload; as=script, </aesthetic.computer/style.css>; rel=preload; as=style" 347 347 348 348 # Assets → DO Spaces CDN 349 349 handle /assets/* {
+9 -11
system/netlify/functions/index.mjs
··· 1134 1134 } 1135 1135 }); 1136 1136 </script> 1137 - <script 1138 - crossorigin="anonymous" 1139 - src="/aesthetic.computer/boot.mjs" 1140 - type="module" 1141 - defer 1142 - ></script> 1137 + <script 1138 + src="/aesthetic.computer/boot.mjs" 1139 + type="module" 1140 + defer 1141 + ></script> 1143 1142 ${dev ? `<!-- Modulepreload for module-loader (needed for fast WebSocket connection) --> 1144 1143 <link rel="modulepreload" href="/aesthetic.computer/module-loader.mjs" />` : `<!-- Modulepreload hints for critical path modules (parallel fetch) --> 1145 1144 <link rel="modulepreload" href="/aesthetic.computer/module-loader.mjs" /> ··· 1196 1195 </script> 1197 1196 <!-- Preload the YWFT Processing font for instant boot animation --> 1198 1197 <link rel="preload" href="/type/webfonts/ywft-processing-bold.woff2" as="font" type="font/woff2" crossorigin="anonymous" /> 1199 - <link 1200 - rel="stylesheet" 1201 - crossorigin="anonymous" 1202 - href="/aesthetic.computer/style.css" 1203 - /> 1198 + <link 1199 + rel="stylesheet" 1200 + href="/aesthetic.computer/style.css" 1201 + /> 1204 1202 <link rel="stylesheet" href="/type/webfonts/ywft-processing-bold.css" /> 1205 1203 <script type="application/ld+json"> 1206 1204 ${JSON.stringify({
+88 -28
system/public/aesthetic.computer/disks/notepat.mjs
··· 1082 1082 1083 1083 // let qrcells; 1084 1084 1085 - let waveBtn, octBtn; 1085 + let waveBtn, octBtn, osBtn; 1086 1086 let slideBtn, roomBtn, glitchBtn, quickBtn; // Toggle buttons for slide/room/glitch/quick modes 1087 1087 let metroBtn, bpmMinusBtn, bpmPlusBtn; // Metronome controls 1088 1088 let melodyAliasBtn; ··· 1503 1503 } 1504 1504 } 1505 1505 1506 - buildWaveButton(api); 1507 - buildOctButton(api); 1508 - buildToggleButtons(api); 1509 - buildMetronomeButtons(api); 1506 + buildWaveButton(api); 1507 + buildOctButton(api); 1508 + buildOsButton(api); 1509 + buildToggleButtons(api); 1510 + buildMetronomeButtons(api); 1510 1511 1511 1512 const newOctave = 1512 1513 parseInt(colon[0]) || parseInt(colon[1]) || parseInt(colon[2]); ··· 4416 4417 ink("yellow"); 4417 4418 write("tap", { right: 6, top: 6 }); 4418 4419 } else if (!paintPictureOverlay) { 4419 - waveBtn?.paint((btn) => { 4420 + osBtn?.paint((btn) => { 4421 + ink(btn.down ? [20, 70, 70] : [10, 45, 45]).box( 4422 + btn.box.x, 4423 + btn.box.y + 3, 4424 + btn.box.w, 4425 + btn.box.h - 3, 4426 + ); 4427 + if (btn.over && !btn.down) { 4428 + ink(255, 255, 255, 24).box( 4429 + btn.box.x, 4430 + btn.box.y + 3, 4431 + btn.box.w, 4432 + btn.box.h - 3, 4433 + ); 4434 + ink(100, 255, 255, 140).box( 4435 + btn.box.x, 4436 + btn.box.y + 3, 4437 + btn.box.w, 4438 + btn.box.h - 3, 4439 + "outline", 4440 + ); 4441 + } 4442 + ink(70, 160, 160).line( 4443 + btn.box.x + btn.box.w, 4444 + btn.box.y + 3, 4445 + btn.box.x + btn.box.w, 4446 + btn.box.y + btn.box.h - 1, 4447 + ); 4448 + ink(btn.down ? [220, 255, 255] : [120, 255, 255]).write( 4449 + "os", 4450 + { x: btn.box.x + 3, y: btn.box.y + 5 }, 4451 + undefined, undefined, false, "MatrixChunky8" 4452 + ); 4453 + }); 4454 + 4455 + waveBtn?.paint((btn) => { 4420 4456 ink(btn.down ? [40, 40, 100] : "darkblue").box( 4421 4457 btn.box.x, 4422 4458 btn.box.y + 3, ··· 5607 5643 } 5608 5644 } 5609 5645 if (e.is("reframed")) { 5610 - setupButtons(api); 5611 - buildWaveButton(api); 5612 - buildOctButton(api); 5613 - buildToggleButtons(api); 5614 - buildMetronomeButtons(api); 5646 + setupButtons(api); 5647 + buildWaveButton(api); 5648 + buildOctButton(api); 5649 + buildOsButton(api); 5650 + buildToggleButtons(api); 5651 + buildMetronomeButtons(api); 5615 5652 // Resize picture to quarter resolution (half width, half height) 5616 5653 const resizedPictureWidth = Math.max(1, Math.floor(screen.width / 2)); 5617 5654 const resizedPictureHeight = Math.max(1, Math.floor(screen.height / 2)); ··· 5710 5747 const topPianoWidth = Math.min(140, Math.floor((screen.width - topBarBase) * 0.5)); 5711 5748 const topPianoEndX = topBarBase + topPianoWidth; 5712 5749 const vizLeft = topPianoEndX; // Start after piano 5713 - const vizRight = waveBtn?.box?.x || screen.width; 5714 - if (e.x >= vizLeft && e.x <= vizRight) { 5715 - recitalMode = true; 5716 - recitalBlinkPhase = 0; 5750 + const vizRight = (osBtn?.box?.x ?? waveBtn?.box?.x ?? screen.width) - 1; 5751 + if (e.x >= vizLeft && e.x <= vizRight) { 5752 + recitalMode = true; 5753 + recitalBlinkPhase = 0; 5717 5754 } 5718 5755 } 5719 5756 ··· 6616 6653 }, 6617 6654 }); 6618 6655 6619 - waveBtn?.act(e, { 6620 - down: () => api.beep(400), 6621 - push: (btn) => { 6622 - api.beep(); 6623 - waveIndex = (waveIndex + 1) % wavetypes.length; 6624 - wave = wavetypes[waveIndex]; 6625 - buildWaveButton(api); 6626 - }, 6627 - }); 6656 + waveBtn?.act(e, { 6657 + down: () => api.beep(400), 6658 + push: (btn) => { 6659 + api.beep(); 6660 + waveIndex = (waveIndex + 1) % wavetypes.length; 6661 + wave = wavetypes[waveIndex]; 6662 + buildWaveButton(api); 6663 + }, 6664 + }); 6665 + 6666 + osBtn?.act(e, { 6667 + down: () => api.beep(400), 6668 + push: () => { 6669 + api.beep(); 6670 + jump("os"); 6671 + }, 6672 + }); 6628 6673 6629 6674 // 🎛️ Toggle button interactions 6630 6675 slideBtn?.act(e, { ··· 7742 7787 waveBtn.displayWave = displayWave; 7743 7788 } 7744 7789 7745 - function buildOctButton({ screen, ui, typeface }) { 7790 + function buildOctButton({ screen, ui, typeface }) { 7746 7791 const isNarrow = screen.width < 200; 7747 7792 const glyphWidth = typeface?.glyphs?.["0"]?.resolution?.[0] ?? matrixFont?.glyphs?.["0"]?.resolution?.[0] ?? 6; 7748 7793 const octWidth = octave.length * glyphWidth; ··· 7753 7798 octWidth + margin * 2 + 7, 7754 7799 10 + margin * 2 - 1 + 2, 7755 7800 ); 7756 - octBtn.id = "oct-button"; 7757 - octBtn.isNarrow = isNarrow; 7758 - } 7801 + octBtn.id = "oct-button"; 7802 + octBtn.isNarrow = isNarrow; 7803 + } 7804 + 7805 + function buildOsButton({ ui }) { 7806 + const margin = 4; 7807 + const labelWidth = 2 * 6; 7808 + const buttonWidth = labelWidth + margin * 2; 7809 + const buttonHeight = 10 + margin * 2 - 1 + 2; 7810 + const waveX = waveBtn?.box?.x ?? 9999; 7811 + osBtn = new ui.Button( 7812 + waveX - buttonWidth - 3, 7813 + 0, 7814 + buttonWidth, 7815 + buttonHeight, 7816 + ); 7817 + osBtn.id = "os-button"; 7818 + } 7759 7819 7760 7820 // Build metronome controls and toggle buttons with responsive layout 7761 7821 // Calculates available space and shortens labels as needed to prevent overlap
+54 -38
system/public/aesthetic.computer/lib/disk.mjs
··· 193 193 } 194 194 195 195 // Helper function to get safe protocol and hostname for URL construction 196 - function getSafeUrlParts() { 196 + function getSafeUrlParts() { 197 197 try { 198 198 const sandboxed = isSandboxed(); 199 199 ··· 232 232 protocol: "https:", 233 233 hostname: "aesthetic.computer" 234 234 }; 235 - } 236 - } 235 + } 236 + } 237 + 238 + const SAME_ORIGIN_BUILT_IN_PIECE_HOSTS = new Set([ 239 + "aesthetic.computer", 240 + "www.aesthetic.computer", 241 + "kidlisp.com", 242 + "www.kidlisp.com", 243 + "notepat.com", 244 + "www.notepat.com", 245 + "p5.aesthetic.computer", 246 + "sitemap.aesthetic.computer", 247 + ]); 248 + 249 + function isLocalDevelopmentHost(hostname) { 250 + return ( 251 + hostname === "localhost" || 252 + hostname === "127.0.0.1" || 253 + /^192\.168\./.test(hostname) || 254 + /^10\./.test(hostname) || 255 + /^172\.(1[6-9]|2[0-9]|3[01])\./.test(hostname) 256 + ); 257 + } 258 + 259 + function getBuiltInPieceBaseUrl() { 260 + const { protocol, hostname } = getSafeUrlParts(); 261 + 262 + if (typeof window !== "undefined" && window.acSPIDER) { 263 + return "https://aesthetic.computer"; 264 + } 265 + 266 + if ( 267 + isLocalDevelopmentHost(hostname) && 268 + typeof location !== "undefined" && 269 + location.port 270 + ) { 271 + return `${protocol}//${hostname}:${location.port}`; 272 + } 273 + 274 + if (SAME_ORIGIN_BUILT_IN_PIECE_HOSTS.has(hostname)) { 275 + return `${protocol}//${hostname}`; 276 + } 277 + 278 + return "https://aesthetic.computer"; 279 + } 237 280 238 281 let tf; // Active typeface global. 239 282 ··· 2862 2905 }, 2863 2906 2864 2907 // 🎄 Preload piece modules for merry pipelines (prevents network latency during fast cycling) 2865 - preloadPieces: async function preloadPieces(pieceNames) { 2908 + preloadPieces: async function preloadPieces(pieceNames) { 2866 2909 if (!pieceNames || pieceNames.length === 0) return; 2867 2910 2868 - const { protocol, hostname } = getSafeUrlParts(); 2869 - const isDevelopment = hostname === 'localhost' && typeof location !== 'undefined' && location.port; 2870 - let baseUrl; 2871 - if (isDevelopment) { 2872 - baseUrl = `${protocol}//${hostname}:${location.port}`; 2873 - } else { 2874 - baseUrl = `https://aesthetic.computer`; 2875 - } 2911 + const baseUrl = getBuiltInPieceBaseUrl(); 2876 2912 2877 2913 const fetchPromises = pieceNames.map(async (piece) => { 2878 2914 // Skip if already cached ··· 2883 2919 2884 2920 try { 2885 2921 // Try .mjs first, then .lua, then .lisp 2886 - const mjsUrl = `${baseUrl}/aesthetic.computer/disks/${piece}.mjs?v=${Date.now()}`; 2922 + const mjsUrl = `${baseUrl}/aesthetic.computer/disks/${piece}.mjs?v=${Date.now()}`; 2887 2923 let response = await fetch(mjsUrl, { cache: 'no-store' }); 2888 2924 2889 2925 if (response.ok) { ··· 2894 2930 } 2895 2931 2896 2932 // Try .lua 2897 - const luaUrl = `${baseUrl}/aesthetic.computer/disks/${piece}.lua?v=${Date.now()}`; 2933 + const luaUrl = `${baseUrl}/aesthetic.computer/disks/${piece}.lua?v=${Date.now()}`; 2898 2934 response = await fetch(luaUrl, { cache: 'no-store' }); 2899 2935 2900 2936 if (response.ok) { ··· 2905 2941 } 2906 2942 2907 2943 // Try .lisp 2908 - const lispUrl = `${baseUrl}/aesthetic.computer/disks/${piece}.lisp?v=${Date.now()}`; 2944 + const lispUrl = `${baseUrl}/aesthetic.computer/disks/${piece}.lisp?v=${Date.now()}`; 2909 2945 response = await fetch(lispUrl, { cache: 'no-store' }); 2910 2946 2911 2947 if (response.ok) { ··· 7404 7440 baseUrl = "."; 7405 7441 } else { 7406 7442 // Check if we're in a development environment (localhost with port) 7407 - const isDevelopment = hostname === 'localhost' && typeof location !== 'undefined' && location.port; 7408 - if (isDevelopment) { 7409 - // Use the local development server 7410 - baseUrl = `${protocol}//${hostname}:${location.port}`; 7411 - } else if (hostname === 'aesthetic.computer') { 7412 - // If we're on the main aesthetic.computer domain (not subdomain), use same origin 7413 - baseUrl = `${protocol}//${hostname}`; 7414 - } else { 7415 - // Use the production server for sandboxed iframes, spider mode, or any subdomain 7416 - baseUrl = `https://aesthetic.computer`; 7417 - } 7418 - } 7443 + baseUrl = getBuiltInPieceBaseUrl(); 7444 + } 7419 7445 } else { 7420 7446 baseUrl = `${protocol}//${hostname}`; 7421 7447 } ··· 8650 8676 let baseUrl; 8651 8677 if (path.startsWith('aesthetic.computer/')) { 8652 8678 // Check if we're in a development environment (localhost with port) 8653 - const isDevelopment = hostname === 'localhost' && typeof location !== 'undefined' && location.port; 8654 - if (isDevelopment) { 8655 - // Use the local development server 8656 - baseUrl = `${protocol}//${hostname}:${location.port}`; 8657 - } else if (hostname.includes('aesthetic.computer')) { 8658 - // If we're on any aesthetic.computer subdomain, use the same origin to avoid CORS 8659 - baseUrl = `${protocol}//${hostname}`; 8660 - } else { 8661 - // Use the production server for sandboxed iframes or production 8662 - baseUrl = `https://aesthetic.computer`; 8663 - } 8679 + baseUrl = getBuiltInPieceBaseUrl(); 8664 8680 8665 8681 // Only strip "aesthetic.computer/" if we're using the main production domain 8666 8682 if (baseUrl === 'https://aesthetic.computer') {