skill
Adom UI Design System
Public Made by Adomby adom
How the AI builds and tests interfaces people love to use in Adom. Ships as one installable skill that bundles focused skills (tooltips, floating-windows, toasts, responsive-ui, app-shell, ai-driven-apps, clickable-paths).
← Commit history
Merge human-ui-patterns into the pack: new clickable-paths skill, walkthroughs, master toggles, dbl-click wiring, preview isPickable + toggle sync; fix HUD resize-clamp contradiction and 6 wrong-owner skill-map URLs
12 files changed
+274−41
README.md+20−12@@ -43,7 +43,7 @@ The AI picks the surface by what it needs to test, and it can use more than one | Surface | What it is | Use it for | |---|---|---|-| **Native browser** | The user's own Chrome or Edge, driven through Adom Desktop | The real, signed-in experience. The browser is already the user's, so the app opens **logged in with zero friction**. Huge for demoing and testing anything behind a login. |+| **Native browser** (**nb**) | The user's own Chrome or Edge, driven through Adom Desktop | The real, signed-in experience. The browser is already the user's, so the app opens **logged in with zero friction**. Huge for demoing and testing anything behind a login. | | **pup** | A clean, scriptable Chrome the AI fully owns, via `adom-desktop` | The **fresh, logged-out, first-time-user** experience, and automated screenshot loops that should not fight the user's own tabs. | | **Hydrogen webview** | An in-workspace browser tab | Showing a result inside the workbench, next to the code and the chat. | @@ -107,13 +107,17 @@ Toasts are the standard transient-feedback element, and in Adom they do double d - **Body-appended `position:fixed` elements at `z-index:99999`.** Never a CSS `::after` pseudo-element, which gets clipped by panel `overflow:hidden`, `backdrop-filter`, or `transform` stacking contexts. - Reveal after a **600ms** hover delay so a fast cursor fly-by stays quiet. Motion is a short fade plus translate, `0.18s ease`.-- Anchor near the cursor, offset about 14px into a quadrant that does not cover the cursor or the hovered element. Flip on-screen near an edge. Reset `text-transform:none`.+- Anchor near the cursor, offset about 14px into a quadrant that does not cover the cursor or the hovered element. Reset `text-transform:none`.+- **MUST clamp to the viewport on BOTH axes so it can NEVER run off any edge. This is the #1 tooltip bug the AI ships and users are sick of reporting.** After computing the ideal position, force it inside `[M, clientWidth - elW - M] x [M, clientHeight - elH - M]` (M~=8px), and **flip** above/left instead of clipping when it would overflow the bottom/right. Measure `offsetWidth/offsetHeight` only AFTER the content is set and the element is laid out (0 size gives a meaningless clamp). Keep the caret pointing at the trigger after clamping (`caretX = clamp(anchorX - clampedLeft, 10, elW-10)`). Inside an iframe, clamp to the iframe's own viewport. This applies to EVERY floating element you position by JS: tooltips, popovers, dropdowns, context menus, autocomplete lists, hover cards, toasts.+- **RALPH-TEST it before shipping, at the corners, not the middle.** Show the WIDEST tooltip on the MOST extreme triggers (leftmost, rightmost, topmost, bottommost) and assert the rendered rect is inside the viewport: `const r=tt.getBoundingClientRect(); console.assert(r.left>=0 && r.right<=innerWidth && r.top>=0 && r.bottom<=innerHeight)`. Drive it live (or compute the clamp for the extreme case and show the numbers). A single centered-control hover is NOT a ralph-test; the bug hides at the edges. Never say a tooltip is done without this check. ### Buttons, toggles, and previews -- A toggle must **look** like its state. Flat styling for both on and off is a lie.+- A toggle must **look** like its state. Flat styling for both on and off is a lie. Carry `aria-pressed="true|false"` and an `.is-on` class, and make the on state differ in at least **two** ways (background, border, inset shadow, accent text). A five percent tint shift is too subtle to read.+- **Sync a toggle both ways.** Every other path that flips the underlying state (the HUD's own close X, a keyboard shortcut, a programmatic `setX(false)`) must update the button too. A button that drifts out of sync is worse than no button, because now it lies confidently. - Primary actions use teal `#00b8b0`. Green means success, red means destructive, reserved for those meanings. - **Any irreversible-feeling action gets a live preview** before it commits: a snap point, a deletion glow, a highlighted target.+- **The preview must not be pickable.** Set `isPickable = false` (or the equivalent) on the preview mesh or element. Otherwise it becomes the hit target for the very next hover and the tool stalls, picking its own ghost. Dispose the preview the instant intent changes: filter switched, tool closed, selection limit reached. Stale ghost markers are their own bug report. ### Floating tool windows and HUDs @@ -193,6 +197,10 @@ Adom has many 3D viewports: CAD, PCB, mechanical, component preview. They share Match Fusion 360 and SolidWorks: **live hover preview, not click-only**; smart-pick edge then face then vertex; the committed marker matches the preview; dimension line distinct from markers (markers teal `#00B8B1`, line blue `#64ABFF`); millimeters primary with mils secondary, never inches; Esc is multi-stage (pop last pick, then the previous, then close). +Expose secondary units and precision as **dropdowns**, never hardcoded. A user who wants `0.1 mm` and a user who wants `0.1234 mm` are both right, and a reader who does not want a second unit at all should be able to switch it off rather than have it clutter every readout. The same applies to any cross-cultural unit pair elsewhere in the app: dB with a numeric ratio, °C with °F.++More generally, when the user's workflow involves a tool they already know well (Fusion 360, KiCad, Photoshop, Figma), **copy that tool's UX for the comparable feature before inventing your own**. Users arrive with muscle memory. Reinventing a mode picker or a selection filter spends their attention for zero benefit. If you are about to do something different, first answer why re-learning is worth it.+ --- ## 8. Foundations: color@@ -304,18 +312,18 @@ Fix every FAIL (the hint tells you exactly what to do), address relevant WARNs, ## 13. The skill map -This whole system ships as **one installable skill**. `adompkg install adom-ui-design` drops the design-system skill **plus all seven skills below** onto your container as separate skill files, so the AI loads each by its own trigger words. The first seven live as files in **this** repo; click to read them. The rest are existing platform skills.+This whole system ships as **one installable skill**. `adom-wiki pkg install adom/adom-ui-design` drops the design-system skill **plus all seven skills below** onto your container as separate skill files, so the AI loads each by its own trigger words. The first seven live as files in **this** repo; click to read them. The rest are existing platform skills. | Skill | Governs | |---|---|-| [**tooltips**](https://wiki.adom.inc/john/adom-ui-design/files/skills/tooltips/SKILL.md) | Great desktop tooltips: 600ms reveal, the fixed-div renderer, placement that never covers what you hover, edge-aware flipping, the z-index ladder |-| [**floating-windows**](https://wiki.adom.inc/john/adom-ui-design/files/skills/floating-windows/SKILL.md) | Draggable floaty tool windows and HUDs that never get in the way |-| [**toasts**](https://wiki.adom.inc/john/adom-ui-design/files/skills/toasts/SKILL.md) | Non-blocking confirmations, and the AI's live narration channel to the user |-| [**responsive-ui**](https://wiki.adom.inc/john/adom-ui-design/files/skills/responsive-ui/SKILL.md) | Phone-to-desktop layouts, touch targets, and tooltips on touch where hover does not exist |-| [**app-shell**](https://wiki.adom.inc/john/adom-ui-design/files/skills/app-shell/SKILL.md) | The full-height single-page app shell, the footer / status bar, and the sizing traps |-| [**ai-driven-apps**](https://wiki.adom.inc/john/adom-ui-design/files/skills/ai-driven-apps/SKILL.md) | The build-show-drive-ralph loop, the live SSE/WebSocket channel, the three display surfaces |-| [**skill-authoring**](https://wiki.adom.inc/john/adom-ui-design/files/skills/skill-authoring/SKILL.md) | How to author a new Adom skill set as a bundle: many skill files in one repo, never a repo per skill |-| [human-ui-patterns](https://wiki.adom.inc/adom/human-ui-patterns) | The broader user-first interaction primitives these were extracted from |+| [**tooltips**](https://wiki.adom.inc/adom/adom-ui-design/files/skills/tooltips/SKILL.md) | Great desktop tooltips: 600ms reveal, the fixed-div renderer, placement that never covers what you hover, edge-aware flipping, the z-index ladder |+| [**floating-windows**](https://wiki.adom.inc/adom/adom-ui-design/files/skills/floating-windows/SKILL.md) | Draggable floaty tool windows and HUDs that never get in the way |+| [**toasts**](https://wiki.adom.inc/adom/adom-ui-design/files/skills/toasts/SKILL.md) | Non-blocking confirmations, and the AI's live narration channel to the user |+| [**responsive-ui**](https://wiki.adom.inc/adom/adom-ui-design/files/skills/responsive-ui/SKILL.md) | Phone-to-desktop layouts, touch targets, and tooltips on touch where hover does not exist |+| [**app-shell**](https://wiki.adom.inc/adom/adom-ui-design/files/skills/app-shell/SKILL.md) | The full-height single-page app shell, the footer / status bar, and the sizing traps |+| [**ai-driven-apps**](https://wiki.adom.inc/adom/adom-ui-design/files/skills/ai-driven-apps/SKILL.md) | The build-show-drive-ralph loop, the live SSE/WebSocket channel, the three display surfaces, guided walkthroughs |+| [**clickable-paths**](https://wiki.adom.inc/adom/adom-ui-design/files/skills/clickable-paths/SKILL.md) | Every path in the UI reveals in the VS Code Explorer, plus the workspace-boundary and dead-server traps |+| [adom-wiki-skillpack](https://wiki.adom.inc/john/adom-wiki-skillpack) | How to author a new Adom skill set as a bundle: many skill files in one repo, never a repo per skill | | [app-creator](https://wiki.adom.inc/adom/app-creator) | Scaffolding a webview app: two-way comms, proxy URL, favicon, publish flow | | `adom-app-header` | The 44px three-zone header and the app-info popover | | [adom-screenshot](https://wiki.adom.inc/adom/adom-screenshot) | Ralph loops and the visual feedback loop for debugging UI |
SKILL.md+16−10@@ -136,9 +136,11 @@ Toasts are the standard transient-feedback element, and in Adom they do double d ### Buttons, toggles, and previews -- A toggle must **look** like its state. Flat styling for both on and off is a lie.+- A toggle must **look** like its state. Flat styling for both on and off is a lie. Carry `aria-pressed="true|false"` and an `.is-on` class, and make the on state differ in at least **two** ways (background, border, inset shadow, accent text). A five percent tint shift is too subtle to read.+- **Sync a toggle both ways.** Every other path that flips the underlying state (the HUD's own close X, a keyboard shortcut, a programmatic `setX(false)`) must update the button too. A button that drifts out of sync is worse than no button, because now it lies confidently. - Primary actions use teal `#00b8b0`. Green means success, red means destructive, reserved for those meanings. - **Any irreversible-feeling action gets a live preview** before it commits: a snap point, a deletion glow, a highlighted target.+- **The preview must not be pickable.** Set `isPickable = false` (or the equivalent) on the preview mesh or element. Otherwise it becomes the hit target for the very next hover and the tool stalls, picking its own ghost. Dispose the preview the instant intent changes: filter switched, tool closed, selection limit reached. Stale ghost markers are their own bug report. ### Floating tool windows and HUDs @@ -218,6 +220,10 @@ Adom has many 3D viewports: CAD, PCB, mechanical, component preview. They share Match Fusion 360 and SolidWorks: **live hover preview, not click-only**; smart-pick edge then face then vertex; the committed marker matches the preview; dimension line distinct from markers (markers teal `#00B8B1`, line blue `#64ABFF`); millimeters primary with mils secondary, never inches; Esc is multi-stage (pop last pick, then the previous, then close). +Expose secondary units and precision as **dropdowns**, never hardcoded. A user who wants `0.1 mm` and a user who wants `0.1234 mm` are both right, and a reader who does not want a second unit at all should be able to switch it off rather than have it clutter every readout. The same applies to any cross-cultural unit pair elsewhere in the app: dB with a numeric ratio, °C with °F.++More generally, when the user's workflow involves a tool they already know well (Fusion 360, KiCad, Photoshop, Figma), **copy that tool's UX for the comparable feature before inventing your own**. Users arrive with muscle memory. Reinventing a mode picker or a selection filter spends their attention for zero benefit. If you are about to do something different, first answer why re-learning is worth it.+ --- ## 8. Foundations: color@@ -329,18 +335,18 @@ Fix every FAIL (the hint tells you exactly what to do), address relevant WARNs, ## 13. The skill map -This whole system ships as **one installable skill**. `adompkg install adom-ui-design` drops the design-system skill **plus all seven skills below** onto your container as separate skill files, so the AI loads each by its own trigger words. The first seven live as files in **this** repo; click to read them. The rest are existing platform skills.+This whole system ships as **one installable skill**. `adom-wiki pkg install adom/adom-ui-design` drops the design-system skill **plus all seven skills below** onto your container as separate skill files, so the AI loads each by its own trigger words. The first seven live as files in **this** repo; click to read them. The rest are existing platform skills. | Skill | Governs | |---|---|-| [**tooltips**](https://wiki.adom.inc/john/adom-ui-design/files/skills/tooltips/SKILL.md) | Great desktop tooltips: 600ms reveal, the fixed-div renderer, placement that never covers what you hover, edge-aware flipping, the z-index ladder |-| [**floating-windows**](https://wiki.adom.inc/john/adom-ui-design/files/skills/floating-windows/SKILL.md) | Draggable floaty tool windows and HUDs that never get in the way |-| [**toasts**](https://wiki.adom.inc/john/adom-ui-design/files/skills/toasts/SKILL.md) | Non-blocking confirmations, and the AI's live narration channel to the user |-| [**responsive-ui**](https://wiki.adom.inc/john/adom-ui-design/files/skills/responsive-ui/SKILL.md) | Phone-to-desktop layouts, touch targets, and tooltips on touch where hover does not exist |-| [**app-shell**](https://wiki.adom.inc/john/adom-ui-design/files/skills/app-shell/SKILL.md) | The full-height single-page app shell, the footer / status bar, and the sizing traps |-| [**ai-driven-apps**](https://wiki.adom.inc/john/adom-ui-design/files/skills/ai-driven-apps/SKILL.md) | The build-show-drive-ralph loop, the live SSE/WebSocket channel, the three display surfaces |-| [**wiki-skillpack (in adom-wiki-skillpack)**](https://wiki.adom.inc/john/adom-ui-design/files/skills/wiki-skillpack (in adom-wiki-skillpack)/SKILL.md) | How to author a new Adom skill set as a bundle: many skill files in one repo, never a repo per skill |-| [human-ui-patterns](https://wiki.adom.inc/adom/human-ui-patterns) | The broader user-first interaction primitives these were extracted from |+| [**tooltips**](https://wiki.adom.inc/adom/adom-ui-design/files/skills/tooltips/SKILL.md) | Great desktop tooltips: 600ms reveal, the fixed-div renderer, placement that never covers what you hover, edge-aware flipping, the z-index ladder |+| [**floating-windows**](https://wiki.adom.inc/adom/adom-ui-design/files/skills/floating-windows/SKILL.md) | Draggable floaty tool windows and HUDs that never get in the way |+| [**toasts**](https://wiki.adom.inc/adom/adom-ui-design/files/skills/toasts/SKILL.md) | Non-blocking confirmations, and the AI's live narration channel to the user |+| [**responsive-ui**](https://wiki.adom.inc/adom/adom-ui-design/files/skills/responsive-ui/SKILL.md) | Phone-to-desktop layouts, touch targets, and tooltips on touch where hover does not exist |+| [**app-shell**](https://wiki.adom.inc/adom/adom-ui-design/files/skills/app-shell/SKILL.md) | The full-height single-page app shell, the footer / status bar, and the sizing traps |+| [**ai-driven-apps**](https://wiki.adom.inc/adom/adom-ui-design/files/skills/ai-driven-apps/SKILL.md) | The build-show-drive-ralph loop, the live SSE/WebSocket channel, the three display surfaces, guided walkthroughs |+| [**clickable-paths**](https://wiki.adom.inc/adom/adom-ui-design/files/skills/clickable-paths/SKILL.md) | Every path in the UI reveals in the VS Code Explorer, plus the workspace-boundary and dead-server traps |+| [adom-wiki-skillpack](https://wiki.adom.inc/john/adom-wiki-skillpack) | How to author a new Adom skill set as a bundle: many skill files in one repo, never a repo per skill | | [app-creator](https://wiki.adom.inc/adom/app-creator) | Scaffolding a webview app: two-way comms, proxy URL, favicon, publish flow | | `adom-app-header` | The 44px three-zone header and the app-info popover | | [adom-screenshot](https://wiki.adom.inc/adom/adom-screenshot) | Ralph loops and the visual feedback loop for debugging UI |
install.sh+2−1@@ -14,6 +14,7 @@ install_skill toasts skills/toasts/SKILL.md install_skill responsive-ui skills/responsive-ui/SKILL.md install_skill app-shell skills/app-shell/SKILL.md install_skill ai-driven-apps skills/ai-driven-apps/SKILL.md+install_skill clickable-paths skills/clickable-paths/SKILL.md -echo "OK: Installed the Adom UI Design System plus 6 bundled skills to $DEST/."+echo "OK: Installed the Adom UI Design System plus 7 bundled skills to $DEST/." echo "Hint: Ask Claude 'what are the Adom color tokens', 'great tooltips', or 'make my app a joy to use'."
package.json+4−4@@ -1,8 +1,8 @@ { "slug": "adom-ui-design",- "version": "1.3.11",+ "version": "1.4.0", "type": "skill",- "description": "The Adom UI Design System plus a bundle of focused UI skills (tooltips, floating-windows, toasts, responsive-ui, app-shell, ai-driven-apps). One adompkg install drops the whole set of skill files onto your container.",+ "description": "The Adom UI Design System plus a bundle of focused UI skills (tooltips, floating-windows, toasts, responsive-ui, app-shell, ai-driven-apps, clickable-paths). One install drops the whole set of skill files onto your container.", "dependencies": {}, "files": [ "SKILL.md",@@ -18,7 +18,7 @@ "skills/responsive-ui/SKILL.md", "skills/app-shell/SKILL.md", "skills/ai-driven-apps/SKILL.md",- "skills/skill-authoring/SKILL.md"+ "skills/clickable-paths/SKILL.md" ], "scripts": { "install": "./install.sh",@@ -32,4 +32,4 @@ "guidelines", "tokens" ]-}+}
page.json+12−6@@ -1,8 +1,8 @@ { "slug": "adom-ui-design",- "version": "1.3.11",+ "version": "1.4.0", "type": "skill",- "description": "The Adom UI Design System plus a bundle of focused UI skills (tooltips, floating-windows, toasts, responsive-ui, app-shell, ai-driven-apps). One adompkg install drops the whole set of skill files onto your container.",+ "description": "The Adom UI Design System plus a bundle of focused UI skills (tooltips, floating-windows, toasts, responsive-ui, app-shell, ai-driven-apps, clickable-paths). One install drops the whole set of skill files onto your container.", "dependencies": {}, "files": [ "SKILL.md",@@ -18,7 +18,7 @@ "skills/responsive-ui/SKILL.md", "skills/app-shell/SKILL.md", "skills/ai-driven-apps/SKILL.md",- "skills/skill-authoring/SKILL.md"+ "skills/clickable-paths/SKILL.md" ], "scripts": { "install": "./install.sh",@@ -37,7 +37,7 @@ "email": "[email protected]" }, "title": "Adom UI Design System",- "brief": "How the AI builds and tests interfaces people love to use in Adom. Ships as one installable skill that bundles focused skills (tooltips, floating-windows, toasts, responsive-ui, app-shell, ai-driven-apps).",+ "brief": "How the AI builds and tests interfaces people love to use in Adom. Ships as one installable skill that bundles focused skills (tooltips, floating-windows, toasts, responsive-ui, app-shell, ai-driven-apps, clickable-paths).", "hero": { "type": "image", "path": "screenshots/hero.png"@@ -58,7 +58,13 @@ "viewport clamp", "dropdown", "popover",- "design system"+ "design system",+ "clickable path",+ "reveal in vscode",+ "path link",+ "walkthrough",+ "toggle button",+ "master toggle" ], "discovery_pitch": "The Adom UI design system: how to build app UIs that are beautiful, self-explaining, responsive, and a joy for an AI to drive - headers, tooltips (viewport-clamped, ralph-tested), toasts, floating HUDs, touch.", "sample_prompts": [@@ -85,4 +91,4 @@ ], "visibility": "public", "org": "adom"-}+}
skills/ai-driven-apps/SKILL.md+22@@ -111,6 +111,28 @@ genuinely drivable. - **Inside a webview, always use relative URLs.** A leading slash bypasses the proxy and hits the wrong origin. Every `fetch`, `href`, `src`, and CSS `url()` must be relative. +## Guided walkthroughs++For any tour of a board, scene, or document (a "Walk me through this" feature), the user stays in+control at every moment. Four rules, none optional:++1. **Interruptible camera.** The fly-to-next-step animation yields the moment the user orbits, pans,+ or zooms. Hook `pointerdown` on the canvas, stop the running animation, auto-pause the step+ timer. Never make somebody sit through an animation to get their view back.+2. **Explicit pause with a visible indicator.** A pause button *and* the Space key. While paused,+ badge the narration HUD ("Paused") and recolor the progress bar so the stop is obvious. Resume+ re-flies the camera, since the user has moved the view, and resumes the step with its+ **remaining** duration rather than restarting it.+3. **Reading-speed auto-advance.** `duration = max(minMs, chars * 45 + 2500 + sentences * 300)`.+ About 45 ms per character is a comfortable 220 wpm, and the 2.5 s floor keeps a slower reader+ from being rushed off a step before the camera has even landed. Never a flat "5 seconds per+ step".+4. **Drivable like everything else in this skill.** Every action (start, pause, resume, next, prev,+ close) is reachable over CLI and HTTP, and `GET /api/walkthrough` returns+ `{active, step, total, paused, currentStepId, title}` so a ralph loop knows which step it is on+ when it captions each screenshot. Without that status endpoint you cannot regression-test the+ tour after the underlying board or document changes, which is exactly when tours break.+ ## Boundary with app-creator (do not blur it) `adom/app-creator` owns CREATING the app: scaffolding, project layout, server + webview skeleton,
skills/clickable-paths/SKILL.mdadded+163@@ -0,0 +1,163 @@+---+name: clickable-paths+description: >-+ Every file or folder path an Adom app shows in its UI is a link that reveals that file in the+ user's VS Code Explorer, never dead text they have to copy into a terminal. Covers the wiring+ (a button, not an anchor; POST to the app's own server; the server shells to `adom-vscode+ reveal`), the required tooltip and result toast, the visual treatment, reveal versus open, and+ the two traps that make this silently fail: the workspace-boundary footgun where `adom-vscode+ reveal` returns OK exit 0 for a path outside VS Code's open folders and the Explorer just does+ nothing (classic for anything downloaded to /tmp), and the dead-server case where the proxy+ returns a plain-text ECONNREFUSED body that blows up JSON.parse. Trigger words: clickable path,+ path link, clickable file path, reveal in vscode, reveal in explorer, open in explorer, show file+ in sidebar, adom-vscode reveal, path in the UI, file path label, reveal failed, nothing happens+ when I click the path, outside workspace, /tmp not revealable.+---++# Clickable paths++Whenever an Adom app shows a file or folder path in any UI surface (a HUD label, a toast, a tooltip,+a list cell, an info bar, an error message, a breadcrumb), that path is a **link that opens the+user's VS Code Explorer focused on it**. Always. No exceptions.++The mental model is simply "I see a path, I want to look at the file." Every static path label+forces this instead:++1. Select it with the mouse, often clobbering other selection state.+2. Copy.+3. Switch to a terminal.+4. Type `code <paste>` or `ls <paste>`.+5. Realize they wanted the Explorer, not the editor.+6. Navigate to it by hand in the sidebar.++Six steps for what should be one click, in a platform that already ships every piece needed to do it+for them.++## Wiring++The container ships `adom-vscode reveal <path>`, which reveals a path in the VS Code Explorer and+expands the tree to it. A webview cannot shell out, so route it through the app's own server.++```html+<!-- a button, NOT an anchor: there is nothing to navigate to -->+<button class="path-link" data-tooltip="Reveal this file in the VS Code Explorer">+ /home/adom/project/r0402.glb+</button>+```++```js+async function reveal(path) {+ const r = await fetch("api/reveal", { method: "POST", body: JSON.stringify({ path }) });+ // read as text FIRST, then try JSON (see "When the server is dead")+ const text = await r.text();+ let j = null;+ try { j = JSON.parse(text); } catch (_) {}++ if (j && j.ok) showToast("Revealed " + path, "ok");+ else if (j && j.outside_workspace)+ showToast("Outside the VS Code workspace: " + j.path ++ ". Move or copy it into " + j.workspace_roots + " to reveal it.", "error");+ else if (j && j.error) showToast("Reveal failed: " + j.error, "error");+ else showToast("Server unreachable, restart " + APP_NAME, "error");+}+```++```rust+(Method::Post, "/api/reveal") => {+ if !is_in_vscode_workspace(&path) { return outside_workspace_response(&path); }+ let out = std::process::Command::new("adom-vscode").args(["reveal"]).arg(&path).output();+ // ... return {ok, path} or {ok: false, error}+}+```++## Required behavior++- **Tooltip every path link** with `data-tooltip="Reveal this <thing> in the VS Code Explorer"`. See+ the `tooltips` skill.+- **Toast the result**, success or failure, per the `toasts` skill. A click that reveals nothing and+ says nothing is indistinguishable from a broken app.+- **Visual treatment**: accent-colored underline on hover plus a focus ring for keyboard users. Keep+ it light. A path should read as text first and a link second, so resist full button styling.+- **Reveal, do not open.** "Click a path" means *reveal in the Explorer*, because users want to see+ the surrounding folder and then decide. Opening it in the editor is a different verb+ (`adom-vscode open`). If your tool genuinely wants edit-on-click, add a second explicit button+ next to the reveal one. Never silently pick for them.+- **Do not fake a link you cannot honor.** If the path lives on another container or is not on this+ filesystem, render it as plain dimmed text with a tooltip saying why, rather than a click that+ quietly fails.++## Trap 1: the workspace-boundary footgun++**`adom-vscode reveal <path>` prints `OK:` and exits 0 even when the path is outside VS Code's open+workspace folders.** The Explorer is a *workspace tree*: it can only render files beneath the+folders the user actually has open, typically `$HOME/project/`. A path in `/tmp/`, `/var/`, or any+other prefix produces a silent visual no-op. The CLI reports success, the sidebar does not move, and+the user concludes your app is broken.++This bites the very common "download it to /tmp and reveal it" shape: URL-source quicklooks,+conversion intermediates, generated exports.++Pre-check server-side before you ever invoke the CLI:++```rust+// On Adom containers the workspace root is $HOME/project/. Users can add more roots via+// "Add Folder to Workspace"; until adom-vscode exposes a /workspace endpoint, $HOME/project+// is the safe baseline.+fn vscode_workspace_roots() -> Vec<PathBuf> {+ let mut out = Vec::new();+ if let Ok(home) = std::env::var("HOME") {+ let p = PathBuf::from(home).join("project");+ if p.exists() {+ if let Ok(c) = std::fs::canonicalize(&p) { out.push(c); }+ }+ }+ out+}+fn is_in_vscode_workspace(p: &Path) -> bool {+ let roots = vscode_workspace_roots();+ if roots.is_empty() { return true; } // no info, trust adom-vscode+ roots.iter().any(|r| p.starts_with(r))+}+```++Respond with something the UI can act on, rather than a fake success:++```json+{+ "ok": false,+ "outside_workspace": true,+ "path": "/tmp/r0402.glb",+ "workspace_roots": "/home/adom/project",+ "error": "File is outside the VS Code workspace (workspace: /home/adom/project). Move or copy it into the workspace to make it revealable."+}+```++**Better still, avoid the situation.** If your app writes files it will later show the user, write+them to `$HOME/project/.adom-cache/<app>/` instead of `/tmp/`, so they stay revealable. That beats a+correct-but-sad "outside workspace" toast every single time.++## Trap 2: when the local server is dead++If the user `Ctrl-C`s the app's server while the Hydrogen tab is still open, clicks return whatever+the proxy serves on connection-refused, typically a plain-text body like+`connect ECONNREFUSED 127.0.0.1:<port>`. Calling `r.json()` on that throws+`SyntaxError: Unexpected token 'c'` and the user sees nothing at all.++**Always read the response as text first, then attempt `JSON.parse`**, exactly as the `reveal()`+snippet above does, so a non-JSON body still produces a useful toast.++## Acceptance check++- [ ] Every path rendered anywhere in the UI is a `.path-link` button, not static text?+- [ ] Each one carries a `data-tooltip` naming what will be revealed?+- [ ] Click produces a toast on success *and* on every failure branch?+- [ ] Server pre-checks the workspace boundary instead of trusting the CLI's exit code?+- [ ] The outside-workspace toast names the workspace root so the user knows where to move it?+- [ ] Generated files are written under `$HOME/project/` rather than `/tmp/` where practical?+- [ ] The fetch handler reads text before `JSON.parse` so a dead server toasts cleanly?++## Related skills++`tooltips` (the tooltip on every path link), `toasts` (the result toast and the failure branches),+`floating-windows` (HUDs are where most paths get rendered), `ai-driven-apps` (give reveal a CLI+subcommand too), and `adom-ui-design` (the hub).
skills/floating-windows/SKILL.md+31−4@@ -23,12 +23,25 @@ grows past the screen with no scroll. - **Draggable by a visible grip.** A clear header bar or a grip icon, not the whole panel (you still want to click controls inside). Cursor `grab` on the grip, `grabbing` while dragging.-- **Never clamp to a screen edge.** The user places it; do not snap it flush to a corner or pin it.- Keep it fully on-screen on resize (clamp into the viewport), but do not force it to an edge.+- **Never clamp, on drag or on resize.** The user places it; do not snap it flush to a corner, do not+ pull it back on-screen when they drag it past the edge, and do not re-snap it when the window+ resizes. Parking a HUD half off the canvas to get a wider look is a deliberate choice, and sliding+ it back "for their own good" is infuriating. The feedback that set this rule: *"huds should be+ allowed to drag off the edge of the webview. you are constraining them too much now."* Bounding the+ HUD's own content growth (next rule) is a separate concern and still applies. - **Bounded height with internal scroll.** `max-height: calc(100% - <margin>)`. The header and footer stay pinned, the body scrolls. A HUD must never grow taller than the viewport. - **Minimize, close, and double-click to collapse.** Every HUD offers all three. Collapsed shows- just the header bar so it stays out of the way without disappearing.+ just the header bar so it stays out of the way without disappearing. Bind the `dblclick` to the+ **grip/header element, not the whole HUD**, so double-clicking inside a scrolling body does+ nothing; ignore it on child icons that own their own action (`−`, `×`, dropdown carets); call+ `e.preventDefault()` so the second click does not select text. The minimize icon is a tiny target,+ and users who already know "drag this bar to move it" naturally try double-clicking it to get it+ out of the way (Fusion, Blender, Figma and every dockable IDE panel behave this way). Do not make+ them aim.+- **Closing leaves no orphan.** When the user hits `×`, do not strand a floating "show me again"+ button on the canvas. Re-expose the HUD from a toggle button on the main toolbar instead: close+ makes the HUD disappear, the toolbar stays. Orphan hamburgers are clutter. - **It floats above content but below tooltips and modals.** Use the `--z-hud: 50` slot from the z-index ladder. A menu opened from a HUD button uses `--z-floating-menu: 200` so it can escape the HUD's box. Tooltips (99999) always win. See the `tooltips` skill for the full ladder.@@ -60,6 +73,20 @@ grows past the screen with no scroll. .hud.collapsed .hud-body, .hud.collapsed .hud-foot { display: none; } ``` +## Grouping long lists++When a HUD holds many toggleable items that naturally cluster (by kind, layer, net, priority), give+each group a header carrying three things:++- A caret (`▾` / `▸`) that collapses just that group.+- A count (`<visible>/<total>`) so the group's state reads at a glance.+- A master toggle (`●` all visible, `○` all hidden, `◐` mixed) that flips the whole group at once.++Keep the per-item toggles inside each group; the master never replaces them. "Hide every testpoint+so I can see the traces" is miserable one row at a time, and "hide *this* chip" still needs the+per-item row. Default every group to **collapsed**, so a first-time user gets a compact overview and+expands only what they care about.+ ## AI-drivable Because the AI builds and tests the app (see `ai-driven-apps`), every HUD action has a command so@@ -69,5 +96,5 @@ inspector`. This is also how the AI screenshots a panel open and closed during a ## Related skills `tooltips` (the z-index ladder and tooltips that render above HUDs), `app-shell` (where HUDs mount-in the layout), `human-ui-patterns` (the broader interaction rules), `ai-driven-apps` (driving HUDs+in the layout), `clickable-paths` (paths shown inside a HUD are links), `ai-driven-apps` (driving HUDs for tests), and `adom-ui-design` (the hub).
skills/responsive-ui/SKILL.md+1−1@@ -70,5 +70,5 @@ it does the desktop one (see `ai-driven-apps`). ## Related skills -`tooltips` (desktop tooltips), `app-shell` (the fluid layout that reshapes), `human-ui-patterns`,+`tooltips` (desktop tooltips), `app-shell` (the fluid layout that reshapes), `ai-driven-apps` (testing the mobile layout), and `adom-ui-design` (the hub).
skills/toasts/SKILL.md+1−1@@ -68,5 +68,5 @@ everything else also lets it talk to the user. ## Related skills `tooltips` (the z-index ladder, the sibling transient element), `ai-driven-apps` (the AI raising-toasts while driving), `human-ui-patterns` (the broader feedback rules), and `adom-ui-design` (the+toasts while driving), `clickable-paths` (the reveal-result toast), and `adom-ui-design` (the hub).
skills/tooltips/SKILL.md+1−1@@ -252,7 +252,7 @@ after layout) and re-run. Never report tooltips complete without stating this te ## Related skills -`human-ui-patterns` (the broader interaction rules this was extracted from), `floating-windows`+`clickable-paths` (every path link needs a tooltip), `floating-windows` (HUDs that tooltips render above), `toasts` (the sibling transient-feedback element), `responsive-ui` (tooltips on touch), and `adom-ui-design` (the design-system hub that indexes all of these).
uninstall.sh+1−1@@ -1,7 +1,7 @@ #!/usr/bin/env bash set -e DEST="$HOME/.claude/skills"-for n in adom-ui-design tooltips floating-windows toasts responsive-ui app-shell ai-driven-apps skill-authoring; do+for n in adom-ui-design tooltips floating-windows toasts responsive-ui app-shell ai-driven-apps clickable-paths skill-authoring; do rm -rf "$DEST/$n" done echo "OK: Removed the Adom UI Design System and its 7 bundled skills."