← Commit history

dash-demo skill + say-strip gains Send to AI (new threads via panel API) - 1.9.0

John Lauer ·f5ec27b009 ·1mo ago ·parent c44042c
5 files changed +154−22
SKILL.md+2−1
@@ -424,7 +424,8 @@ This whole system ships as **one installable skill**. `adom-wiki pkg install ado | [**settings-layout**](https://wiki.adom.inc/adom/adom-ui-design/files/skills/settings-layout/SKILL.md) | The settings surface every Adom app shares: a cog in the header opening a dismissible MODAL, backdrop dimmed 20-30% and NEVER blurred (settings often change what is behind them), teal-accent cards that explain themselves, toggles not checkboxes, defaults shown on every row, two-click Restore defaults, and a category sidebar with jump-to and scroll-spy once settings outgrow a screen | | [**dock-dashboard**](https://wiki.adom.inc/adom/adom-ui-design/files/skills/dock-dashboard/SKILL.md) | THE parent contract for every Dock Bar launch dashboard: one anatomy (house header, say strip, status pill row, then the app's own content), the two legitimate species (bridge launch page vs full app whose main UI is the dock target), and the shared token stub - ends the seven-dashboards-seven-designs era | | [**dash-header**](https://wiki.adom.inc/adom/adom-ui-design/files/skills/dash-header/SKILL.md) | One header grammar for dashboards: human name never a slug echo, version NEVER inline in the bar (popover only), the standard target box chip, and the ? that recalls the newbie scaffolding |-| [**say-strip**](https://wiki.adom.inc/adom/adom-ui-design/files/skills/say-strip/SKILL.md) | The ONE say strip: "Say it" heading, quoted phrases with the noun in teal, exactly one Try-it treatment (ghost pill, copy to clipboard, the fleet toast "Copied to clipboard. Paste it into any AI thread."), with the unfocused-window clipboard recipe |+| [**say-strip**](https://wiki.adom.inc/adom/adom-ui-design/files/skills/say-strip/SKILL.md) | The ONE say strip: "Say it" heading, quoted phrases with the noun in teal, two buttons on every phrase: Copy (clipboard + the fleet toast) and Send to AI (a NEW AI thread via the panel API, submitted), with the unfocused-window clipboard recipe |+| [**dash-demo**](https://wiki.adom.inc/adom/adom-ui-design/files/skills/dash-demo/SKILL.md) | The demo contract: one guided demo per dashboard driven by a step list, play/pause/prev/next/exit toolbar, pre-created adom-tts mp3s (audio on by default, mute button), and ab captions perfectly synced at the bridge default size so every app's demo feels identical | | [**status-leds**](https://wiki.adom.inc/adom/adom-ui-design/files/skills/status-leds/SKILL.md) | One status language: a compact LED pill row (the chip-fetcher pattern canonized), prose on tap never by default, red LEDs always carry their next step, staleness escalates, and the row never disagrees with the dock card's LED | | [**newbie-graduation**](https://wiki.adom.inc/adom/adom-ui-design/files/skills/newbie-graduation/SKILL.md) | The scaffolding-fade contract: Fresh, Graduated, Recallable states per app; triggers are dismissal, 3 green launches, or the first AI-driven action the bridge sees; the say strip folds last because handing the user to the AI is the point | | [**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 |
package.json+3−2
@@ -1,6 +1,6 @@ {   "slug": "adom-ui-design",-  "version": "1.8.0",+  "version": "1.9.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, clickable-paths, dark-default, input-feedback, settings-layout). One install drops the whole set of skill files onto your container, plus shared icon assets (the settings cog) so every Adom app draws the same glyph.",   "dependencies": {},@@ -29,7 +29,8 @@     "skills/dock-dashboard/SKILL.md",     "skills/newbie-graduation/SKILL.md",     "skills/say-strip/SKILL.md",-    "skills/status-leds/SKILL.md"+    "skills/status-leds/SKILL.md",+    "skills/dash-demo/SKILL.md"   ],   "scripts": {     "install": "./install.sh",
skills/dash-demo/SKILL.mdadded+95
@@ -0,0 +1,95 @@+---+name: dash-demo+user-invocable: true+description: >-+  The demo contract for every dock bar dashboard: one guided demo alongside the sample AI+  prompts, driven by a step list where each step carries an action, a caption, and a+  pre-created adom-tts mp3. The player shows a play / pause / prev / next / exit toolbar+  while running; audio plays by DEFAULT with a mute/unmute button; captions are ab captions+  (Adom Bridge captions) perfectly synced to what is happening on screen, always at the+  bridge's default size and position so every app's demo feels identical. Read BEFORE+  building or restyling any dashboard demo, tour, or walkthrough. Trigger words: dashboard+  demo, guided demo, demo toolbar, demo player, tour player, ab captions, caption size,+  demo audio, tts narration demo, mute demo, demo steps, play pause demo.+---++Parent skill: **adom-ui-design**++# The dashboard demo - one player, every app++John's ruling (2026-08-24): every dock dashboard ships a demo alongside its sample AI+prompts, and every demo feels like the same product: same toolbar, same captions, same+audio behavior. An app's demo differs in WHAT it shows, never in how it plays.++## The step list is the demo++A demo is a JSON list of steps. Everything else (player, audio, captions) is generic:++```json+[+  { "id": "open-symbol",+    "action": "kicad_open_symbol {\"name\":\"AdomDemo_SOIC8\"}",+    "caption": "Opening the demo symbol in the Symbol Editor.",+    "audio": "demo/audio/open-symbol.mp3",+    "min_ms": 4000 }+]+```++- `action`: what the step DOES - a bridge verb, a UI drive, an in-page navigation.+- `caption`: one sentence, present tense, saying what the user is watching RIGHT NOW.+- `audio`: the pre-created narration mp3 for exactly this step.+- `min_ms`: floor so a fast action does not cut the narration; the step advances at+  max(action done, audio done, min_ms).++## Audio: pre-created adom-tts mp3s++- Narration is synthesized AT BUILD/PUBLISH TIME with `adom-tts say` (pronunciation+  overrides + source-hash cache make re-renders free), one mp3 per step, shipped in the+  package `files[]` and served by the dashboard. NEVER synthesize at demo time.+- **Audio plays by default.** A mute/unmute button sits in the player toolbar; muted state+  persists in localStorage, but a fresh user hears the demo.+- The mp3 for a step starts the moment the step starts. That is the sync contract: caption,+  audio, and screen action all key off the same step boundary.++## Captions: ab captions, one size fleet-wide++- Captions render as **ab captions** (the Adom Bridge caption overlay), not homemade+  in-page banners, so they sit over whatever the demo is driving - the dashboard, KiCad,+  Fusion, a pup window.+- **Always the bridge's default caption size and position. Never pass a custom size.** This+  is the whole consistency ruling: seven apps, one caption look. If the default is wrong,+  fix the bridge default for everyone, not your app.+- One caption per step, shown for the life of the step, cleared on exit. A caption that+  outlives its step (the "showing forever" bug) is a broken demo: always clear on step+  advance, on exit, and in every error path.++## The player toolbar++Visible whenever the demo is running, hidden otherwise:++```+[ ⏮ prev ] [ ⏯ play/pause ] [ ⏭ next ] | [ 🔊 mute ] | step 3/8 | [ ✕ exit ]+```++- **play/pause**: pause freezes the action where safe, pauses audio mid-word, keeps the+  caption up. Resume continues the same step.+- **prev/next**: jump step boundaries. Audio for the old step stops instantly; the new+  step's caption and mp3 start together. next during the last step = exit.+- **exit**: stop everything, clear the ab caption, stop audio, restore whatever the demo+  moved (windows, tabs, state), return the dashboard to rest. Exit must be safe at ANY+  step - ralph-test it from the middle of the most destructive step.+- Toolbar style: house tokens, fixed bottom-center of the dashboard, small; it is a+  remote control, not a feature. Buttons follow the input-feedback skill.++## Where the demo lives on the page++In the newbie area, next to the say strip, as ONE primary button: "Play the demo"+(optionally with duration: "Play the 2-minute demo"). It folds with the rest of the+scaffolding per **newbie-graduation**, and the ? brings it back.++## Ralph-test++Run the demo end to end in pup and WATCH: captions change exactly when the screen does;+audio starts within ~200ms of each step; mute silences without breaking sync; pause/resume+mid-step works; prev/next from every position; exit from the middle clears the caption and+restores state. Then run it muted and check the captions alone tell the story.
skills/dock-dashboard/SKILL.md+6−3
@@ -8,7 +8,8 @@ description: >-   dock target), and the shared token stub every dashboard copies. Born from the 2026-08-24   audit where seven dashboards shipped seven say-strips, five status dialects, and five   version placements. Read BEFORE building or restyling any dock bar dashboard, and route to-  the sub-skills dash-header, say-strip, status-leds, newbie-graduation for each region.+  the sub-skills dash-header, say-strip, dash-demo, status-leds, newbie-graduation for+  each region.   Trigger words: dock dashboard, launch dashboard, dock bar ui, dockbar dashboard, bridge   launch page, dashboard anatomy, dashboard contract, dock bar consistency, dashboard tokens,   brother from another mother.@@ -29,8 +30,10 @@ Every launch dashboard renders these regions in this order:  1. **House header** (44px, three zones) - see **dash-header**. Human app name, target box    chip, gear. Version NEVER in the bar.-2. **Say strip** - see **say-strip**. The one component that teaches the user to talk to-   their AI. One heading, one chip style, one Try-it.+2. **Say strip + demo** - see **say-strip** and **dash-demo**. The strip teaches the user+   to talk to their AI (Copy and Send to AI on every phrase); beside it, ONE "Play the+   demo" button starts the guided demo (player toolbar, pre-built adom-tts narration,+   synced ab captions at the fleet-standard size). 3. **Status pill row** - see **status-leds**. The whole app's health in one compact line,    prose on demand, never by default. 4. **The app's own content** - actions, demos, consoles, whatever the app is. This region
skills/say-strip/SKILL.md+48−16
@@ -25,12 +25,17 @@ the last scaffolding to fade (see **newbie-graduation**) because it IS the gradu  - **Heading:** the literal string **"Say it"**. Not "Say it to your AI", not all-caps. - **Explainer:** ONE sentence, naming the noun: `You never need this page's buttons: just-  tell your AI what you want, using the word <b>kicad</b>. Click a phrase to copy it.`+  tell your AI what you want, using the word <b>kicad</b>. Copy a phrase, or send it straight to a new AI thread.` - **Phrases:** 3 to 6, straight from the app's dockbar.json `say` array, ALWAYS in curly   quotes, the noun highlighted teal: `"open the symbol in <em>kicad</em>"`. Body face,   never monospace.-- **Try it:** ONE style - a small ghost pill after the phrase chip. Clicking the phrase or-  the pill does the same thing: copy, then toast.+- **Two buttons per chip, always the same two:**+  - **Copy** - ghost pill. Copies the phrase, then the fleet toast. Clicking the phrase+    itself also copies (largest hit target does the safest thing).+  - **Send to AI** - teal-outline pill. Opens a NEW AI thread named for the app, tagged+    with the app slug, and submits the phrase (John's ruling 2026-08-24: the AI-threads+    API is trusted for new threads now). Toast: "Sent to a new AI thread." On any failure:+    error toast AND fall back to copying the phrase so the user is never stranded. - **Dismiss:** an X on the strip's corner. Dismissal is a graduation trigger; the ? in the   header brings it back. Never gone forever. @@ -40,11 +45,12 @@ the last scaffolding to fade (see **newbie-graduation**) because it IS the gradu <section class="say" id="say">   <div class="say-head"><h2>Say it</h2>     <p>You never need this page's buttons: just tell your AI what you want,-       using the word <b class="noun">kicad</b>. Click a phrase to copy it.</p>+       using the word <b class="noun">kicad</b>. Copy a phrase, or send it straight to a new AI thread.</p>     <button class="say-x" aria-label="Collapse">&times;</button></div>   <div class="say-chips">     <span class="say-chip" data-say="open the symbol in kicad">-      &ldquo;open the symbol in <em>kicad</em>&rdquo;<button class="try">Try it</button>+      &ldquo;open the symbol in <em>kicad</em>&rdquo;+      <button class="copy">Copy</button><button class="send">Send to AI</button>     </span>     <!-- ...one per phrase -->   </div>@@ -57,8 +63,11 @@ the last scaffolding to fade (see **newbie-graduation**) because it IS the gradu .say-head p { color: var(--muted); font-size: 13.5px; margin: 4px 0 0; } .say-chip { display: inline-flex; align-items: center; gap: 8px; background: var(--surface2); border: 1px solid var(--line); border-radius: 999px; padding: 5px 6px 5px 12px; font-size: 13.5px; margin: 4px 6px 0 0; cursor: pointer; } .say-chip em { color: var(--teal); font-style: normal; }-.say-chip .try { font: 500 11px var(--body); color: var(--muted); background: none; border: 1px solid var(--line); border-radius: 999px; padding: 2px 9px; cursor: pointer; }-.say-chip:hover .try { color: var(--teal); border-color: var(--teal); }+.say-chip .copy, .say-chip .send { font: 500 11px var(--body); background: none; border: 1px solid var(--line); border-radius: 999px; padding: 2px 9px; cursor: pointer; }+.say-chip .copy { color: var(--muted); }+.say-chip .send { color: var(--teal); border-color: rgba(0,184,177,.45); }+.say-chip:hover .copy { color: var(--teal); border-color: var(--teal); }+.say-chip .send:hover { background: rgba(0,184,177,.12); } ```  ```js@@ -76,23 +85,46 @@ function legacyCopy(text) {   ta.style.cssText = 'position:fixed;opacity:0'; document.body.append(ta);   ta.select(); const ok = document.execCommand('copy'); ta.remove(); return ok; }-document.querySelectorAll('.say-chip').forEach(c =>-  c.addEventListener('click', () => copyPhrase(c.dataset.say)));+document.querySelectorAll('.say-chip').forEach(c => {+  c.addEventListener('click', () => copyPhrase(c.dataset.say));+  c.querySelector('.send').addEventListener('click', async (e) => {+    e.stopPropagation();+    const r = await fetch('/api/say-send', { method: 'POST',+      headers: { 'Content-Type': 'application/json' },+      body: JSON.stringify({ phrase: c.dataset.say }) }).then(x => x.json()).catch(() => null);+    if (r && r.ok) toast('success', 'Sent to a new AI thread.');+    else { copyPhrase(c.dataset.say); toast('error', (r && r.why) || 'Could not reach the AI panel; copied instead.'); }+  });+}); ```  The toast is the standard toasts-skill toast: success green, bottom center, ~4s. The copy string is EXACTLY `Copied to clipboard. Paste it into any AI thread.` - fleet-wide, so the behavior reads as one product. -## Live-thread staging (currently parked)+## Send to AI: the server side -When AI-thread staging is certified and un-parked, Try it MAY stage the phrase into the-app's AI thread instead of copying - behind the app's staging flag AND the dock's aiThreads-setting, and the copy+toast path remains the fallback forever. Until the un-park broadcast:-copy+toast only, and POST /api/say-try answers `{parked:true, why}` per the dockbar guide.+The page never talks to the panel directly; its backend does, via the workspace control+API (the URL in `~/.adom/hydrogen-control-url`):++1. `POST /ai-threads/new` with a staged `name` ("KiCad - say it") and `tags`+   (`["dock:kicad"]`, the app slug) - returns the new thread's `sid`. The staged name/tags+   have a 4h TTL, which a real send consumes immediately.+2. `POST /ai-threads/run-prompt` with `{ sid, prompt, submit: true }`.++The backend endpoint is `POST /api/say-send { phrase }` answering `{ ok, sid }` or+`{ ok: false, why }` (CORS `*` like every /api/* route, per the dockbar guide). This+replaces the parked `/api/say-try` contract.++**New threads ONLY.** Resuming or typing into EXISTING threads stays parked pending the+platform certification; a dashboard never calls resume or targets a tid it found in the+census. Tagging the new thread with the app slug is what lets the census find it later.  ## Ralph-test  Click a chip with the window UNFOCUSED (drive it via the bridge, not your own mouse):-toast appears, clipboard holds the exact phrase. Then check the strip at phone width: chips-wrap, nothing overflows the page body.+toast appears, clipboard holds the exact phrase. Click Send to AI: a NEW thread opens in+the panel with the phrase submitted, the success toast shows, and the thread carries the+app tag (check the census). Kill the control API and click Send again: error toast AND the+phrase lands on the clipboard. Then check the strip at phone width: chips wrap, nothing+overflows the page body.