From 4f18eefa69fe5fcfb14ebc2979c315d37cdc334f Mon Sep 17 00:00:00 2001 From: digital-garbage <133010426+digital-garbage@users.noreply.github.com> Date: Wed, 16 Sep 2026 06:25:12 +0300 Subject: [PATCH] feat: picker wheel -- customizable radial menu, replaces v4's pinned buttons MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [[project_v5_ui_requirements]]: "any action in the UI can be assigned to a slot... full wheel or half wheel... half wheel positioned left or right... both draggable... default: middle mouse button, anywhere." app/legacy/actions.js: ported the composer tree's tiny action registry (app/shell/actions.js, an ES module, unreferenced from boot) as a classic global window.FunPackActions -- offerAction({id,label,icon,run}), offered(), run(id). Whatever announces itself is what the wheel (or anything later -- a command palette, a keymap) can show. app/legacy/wheel.js: middle-mouse (anywhere) opens a radial menu of whatever's currently on it. Full wheel spaces items evenly around 360°; half wheel spaces them over a 180° arc on the chosen side, with drag locked to the vertical axis only (full wheel drags both axes) per the spec's "half wheel moves up/down, full wheel up/down and left/right" line. Dragging repositions the CURRENTLY OPEN wheel only, not persisted -- read "draggable" as "don't get stuck somewhere awkward this time" rather than a remembered dock position, since the spec doesn't say which and this is the simpler reading. Customize dialog (reuses pinned_buttons.js's existing .pin-modal/.pin-slot CSS) toggles shape, side, and which offered actions are on the wheel. pinned_buttons.js is NOT removed -- the spec says this supersedes it, but retiring a working control felt like a separate decision from adding a new one; both coexist for now, confirmed to not conflict (separate storage keys, no shared DOM, never both open at once). app/legacy/wheel_actions_seed.js: seeds 9 starter actions (Generate, Generate selected, Render, Auto Montage, Undo, Redo, Models & Pipeline, Engine settings, Sampler quick-access) so the wheel isn't empty on first use. Two rounds of extensive_testing, plus a bug I found myself in live testing before either round: the half wheel's fixed radius, sized for a full wheel's 360° spread, packed the same item count into half the angular room and produced heavily overlapping items -- fixed by growing the radius only as far as needed to keep adjacent items from touching, confirmed visually before/after. Round 1: no functional break found in outside-click-vs-item-click ordering, listener leaks on repeated opens, or coexistence with pinned_buttons.js. Round 2: found the real defect -- enabledIds()'s first-call snapshot ("default to everything offered so far") could run in the gap between wheel.js executing and wheel_actions_seed.js finishing (classic +