From 7cff31febee5ff3bbbf4632b09a1edad3a98d619 Mon Sep 17 00:00:00 2001 From: "prompt.ac/@jeffrey" Date: Mon, 22 Jun 2026 21:28:06 -0700 Subject: [PATCH] =?UTF-8?q?chat:=20active=20hover=20cursor=20=E2=80=94=20s?= =?UTF-8?q?wap=20the=20crosshair=20for=20a=20reticle=20over=20UI=20control?= =?UTF-8?q?s?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds cursors/active.svg (cyan ring reticle, same 24x24 / hotspot 12,12 as precise.svg so it doesn't jump). chat.paint detects when the pen is over an interactive control (handle / + / message field / font + attach menus) and swaps document.body.style.cursor to active.svg via api.cursor(), restoring precise.svg otherwise. Only fires on state change; resets on leave. --- .../aesthetic.computer/cursors/active.svg | 8 +++++ .../public/aesthetic.computer/disks/chat.mjs | 31 +++++++++++++++++++ 2 files changed, 39 insertions(+) create mode 100644 system/public/aesthetic.computer/cursors/active.svg diff --git a/system/public/aesthetic.computer/cursors/active.svg b/system/public/aesthetic.computer/cursors/active.svg new file mode 100644 index 0000000000..329d9e8ac6 --- /dev/null +++ b/system/public/aesthetic.computer/cursors/active.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/system/public/aesthetic.computer/disks/chat.mjs b/system/public/aesthetic.computer/disks/chat.mjs index bc2fa7aa42..794ca165ef 100644 --- a/system/public/aesthetic.computer/disks/chat.mjs +++ b/system/public/aesthetic.computer/disks/chat.mjs @@ -219,6 +219,13 @@ let attachMenuPanelBounds = null; // open-menu panel hit box let attachMenuItemBounds = []; // per-item hit boxes let attachUploading = false; // guard against overlapping uploads +// 🖱️ Hover cursor — swap the crosshair (precise.svg) for an "active" reticle +// (active.svg) while the pen is over any interactive control. Tracks the +// current state so we only call cursor() on a change, not every frame. +let hoverCursorOn = false; +const CURSOR_ACTIVE = "url('/aesthetic.computer/cursors/active.svg') 12 12, pointer"; +const CURSOR_PRECISE = "url('/aesthetic.computer/cursors/precise.svg') 12 12, auto"; + // 📺 YouTube preview system let youtubePreviewCache = new Map(); // Store loaded YouTube thumbnails let youtubeLoadQueue = new Set(); // Track which videos are being loaded @@ -2549,6 +2556,30 @@ function paint( { x: dropdownX, y: dropdownY } ); } + + // 🖱️ Swap to the "active" cursor when the pen is over any interactive + // control (handle / + / message field / font + attach menus). Desktop + // nicety via the CSS SVG cursor; only fires on a state change. + { + const inBox = (b) => { + if (!b || !pen) return false; + const w = b.w ?? b.width, h = b.h ?? b.height; + return pen.x >= b.x && pen.x < b.x + w && pen.y >= b.y && pen.y < b.y + h; + }; + const boxes = [ + handleBtn?.btn?.box, + attachBtnBounds, + inputBtn?.box, + fontPickerBtnBounds, + ...attachMenuItemBounds, + ...fontPickerItemBounds, + ]; + const overUI = !leaving() && !!pen && boxes.some(inBox); + if (overUI !== hoverCursorOn) { + hoverCursorOn = overUI; + api.cursor?.(overUI ? CURSOR_ACTIVE : CURSOR_PRECISE); + } + } } function act( -- 2.51.2