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
settings-layout: never fabricate a screenshot, and choice cards for mutually exclusive visual options
John (2026-08-23) on both halves of the same problem.
NEVER FABRICATE THE IMAGE. This is the rule an AI breaks, because drawing a plausible picture
is easy and driving the app into the state is work. Forbidden without exception: CSS/SVG
mockups that represent the feature, generated or illustrated images, a screenshot of a
different state relabelled, borrowed images from another product, a diagram standing in for a
screenshot. Each puts a picture next to a control saying this is what you get, and if it is
invented the user chooses based on a thing that does not exist. Added the capture recipe that
gets skipped: put the app in the real state including whatever transient condition the feature
responds to, capture the running app with a real screenshot verb, crop tight at 1:1, then LOOK
at the crop and re-capture if the options are not distinguishable. If the state cannot be
produced, ship no image and say so; prose without a picture is honest.
ALTERNATIVES. Two or three mutually exclusive options whose whole difference is visual (pup's
taskbar activity: determinate progress bar, orange flash, or off) get a choice card each with
its own real screenshot, not a dropdown, because a dropdown hides exactly the information
needed to choose. Identical crop, zoom and surroundings across the set so the option is the
only variable, the off state included as a card, a real radiogroup so keyboard and screen
readers work, a teal ring for selection, and one line naming the tradeoff rather than the
mechanism.
2 files changed
+136−1
package.json+1−1@@ -1,6 +1,6 @@ { "slug": "adom-ui-design",- "version": "1.7.0",+ "version": "1.7.1", "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": {},
skills/settings-layout/SKILL.md+135@@ -618,6 +618,42 @@ so the reading order is name, explanation, picture, then the thing you flip. } ``` +### NEVER fabricate the image. Capture the real thing.++**This is the rule this section exists to enforce, and it is the one an AI breaks.** Drawing a+plausible picture is easy; driving the app into the state and capturing it is work. Do the work.++Forbidden, without exception:++- A mockup drawn in HTML/CSS/SVG that "represents" the feature.+- A generated or illustrated image of what the option looks like.+- A screenshot of a DIFFERENT state relabelled as this one.+- A stock or borrowed image of a similar feature from another product.+- A diagram standing in for a screenshot, when the setting changes something you can see.++Every one of those puts a picture next to a control and tells the user "this is what you get".+If the picture is invented, the user makes a choice based on a thing that does not exist, and it+is worse than prose because a picture is believed. The earlier rule stands and hardens here: a+fabricated screenshot is a lie with a picture attached.++**How to actually capture it**, which is the part that gets skipped:++1. Put the app in the real state. Set the option, restart if the option needs it, generate the+ condition the feature responds to. If the feature only appears while something is happening+ (a progress bar during a long operation, a badge on an unread item), trigger that too.+2. Capture the running app with a real screenshot verb. On the desktop that is+ `desktop_screenshot_window` (works on a background window, so it never steals focus) or a+ `pup_screenshot` for a browser surface. Never a synthetic render.+3. Crop tight to the feature, at 1:1 pixels. Do not scale a full-window capture down into the+ card, and do not upscale a small crop; both make the difference unreadable, which defeats the+ whole point.+4. Look at the crop. If you cannot tell the options apart from the images alone, your crop is+ wrong or the images are of the wrong moment. Re-capture.++**If you cannot produce the state, ship no image.** Prose with no picture is honest and+useful; a picture you invented is neither. Say so plainly in the card ("screenshot pending")+rather than filling the hole.+ Rules that keep these from rotting: - **Crop tight to the feature.** A full-window screenshot shrunk into a card shows nothing.@@ -640,6 +676,103 @@ Rules that keep these from rotting: - **Never put text in the image that the card already says.** The picture shows, the prose tells. +## Alternatives: one option or the other, each shown by its own real screenshot++A very common shape: two or three options that are mutually exclusive, and the difference+between them is entirely visual. The user cannot choose without seeing what each one does.++The worked example is pup's taskbar activity setting, which is exactly this: while pup is+working on a window it can paint a **determinate progress bar** on that window's taskbar+button, or **flash the button orange**, or do **nothing**. Three alternatives, one behaviour+each, and the whole decision lives in what they look like.++**Use a choice card per option, not a dropdown.** A dropdown hides every option but the one+already chosen, which is the exact information the user needs. Put the options side by side,+each with its own tight screenshot of the real result:++```html+<fieldset class="choice-set" role="radiogroup" aria-labelledby="taskbar-activity-label">+ <legend id="taskbar-activity-label" class="row-label">Taskbar activity</legend>+ <p class="subsection-description">What a window's taskbar button does while pup is working+ on it.</p>++ <label class="choice" data-selected={mode === 'progress'}>+ <input type="radio" name="taskbarActivity" value="progress" checked={mode === 'progress'}>+ <img src="/assets/shots/taskbar-progress.png" width="240" height="72"+ alt="A taskbar button filled about two thirds with a teal progress bar">+ <span class="choice-name">Progress bar</span>+ <span class="choice-desc">Fills over the operation's usual duration, so you can see how+ far along it is.</span>+ </label>++ <label class="choice" data-selected={mode === 'flash'}>+ <input type="radio" name="taskbarActivity" value="flash" checked={mode === 'flash'}>+ <img src="/assets/shots/taskbar-flash.png" width="240" height="72"+ alt="The same taskbar button highlighted solid orange">+ <span class="choice-name">Orange flash</span>+ <span class="choice-desc">Highlights the button until you look at it. Tells you something+ happened, not how long is left.</span>+ </label>++ <label class="choice" data-selected={mode === 'off'}>+ <input type="radio" name="taskbarActivity" value="off" checked={mode === 'off'}>+ <img src="/assets/shots/taskbar-off.png" width="240" height="72"+ alt="The same taskbar button with no highlight of any kind">+ <span class="choice-name">Off</span>+ <span class="choice-desc">The taskbar button never changes.</span>+ </label>+</fieldset>+```++```css+.choice-set { border: none; margin: 0; padding: 0;+ display: flex; flex-wrap: wrap; gap: 0.75rem; }+.choice {+ flex: 1 1 240px;+ display: flex; flex-direction: column; gap: 0.35rem;+ padding: 0.6rem; cursor: pointer;+ background: var(--surface); border: 1px solid var(--border); border-radius: 8px;+ transition: border-color .15s ease, background .15s ease, transform .06s ease;+}+.choice input { position: absolute; opacity: 0; pointer-events: none; }+.choice img { display: block; width: 100%; height: auto; border-radius: 4px;+ background: var(--bg); }+.choice-name { font-family: var(--brand-heading); font-size: 0.875rem; font-weight: 600; }+.choice-desc { font-family: var(--brand-body); font-size: 0.75rem; color: var(--text-2);+ line-height: 1.5; }+.choice:hover { border-color: var(--accent); background: var(--elevated); }+.choice:active{ transform: translateY(1px) scale(.995); }+.choice[data-selected='true'] {+ border-color: var(--accent);+ box-shadow: inset 0 0 0 1px var(--accent); /* the ring IS the selection */+}+.choice:focus-within { outline: 2px solid var(--accent); outline-offset: 2px; }+```++The rules:++- **Every option gets its own screenshot, captured from the real feature.** All of the+ never-fabricate rules above apply with full force here: the user is choosing BETWEEN+ pictures, so an invented one directly causes a wrong choice.+- **Identical crop, zoom, and surroundings across the set.** Capture the same window, the same+ button, the same size, at the same moment in the operation. The only thing that may differ+ between the images is the option itself. A set shot at different zooms is unreadable as a+ comparison.+- **Include the "off" or "none" option as a card with a screenshot too**, showing the plain+ state. Users need to see what nothing looks like.+- **The set is a `radiogroup`** with real radio inputs, so keyboard and screen readers work.+ Hide the input visually, never with `display: none` (that removes it from the tab order).+- **Selection is a teal ring**, not just a tint: an unringed "selected" card is invisible on a+ dense surface.+- **Name the tradeoff in one line each**, not just the mechanism. "Tells you something happened,+ not how long is left" is what actually decides it.+- **Two to four options, side by side.** Past four, this becomes a list and you should reconsider+ whether they are really alternatives.++If the alternatives are NOT visual (a polling interval, a log level), skip the cards: a plain+enum control with a Default hint is right, and inventing screenshots for it is exactly the+failure mode this section forbids.+ ## Saving: local-first, optimistic, bounded Every rule here came from a real bug, and every one of them is invisible until it bites:@@ -673,6 +806,8 @@ Every rule here came from a real bug, and every one of them is invisible until i - [ ] Row names are breadcrumbs with a teal last part, full key in `title` - [ ] Every row shows its default, using the option LABEL for enums - [ ] Settings that change something visual carry a tight, current screenshot of it+- [ ] Every screenshot is a REAL capture of the running app, never drawn, generated, or borrowed+- [ ] Mutually exclusive visual options are choice cards with one real screenshot each, same crop and zoom, including the off state - [ ] Dependent settings are indented under their parent with a spine, dimmed and disabled (never hidden) when the parent is off, and say why - [ ] Booleans are toggles (`role="switch"`), never a native checkbox - [ ] Long actions stream a live console; no silent multi-minute buttons