chore: snapshot main sync

This commit is contained in:
2026-06-17 20:08:31 +00:00
parent b18de2a331
commit 8bd32537cf
354 changed files with 10208 additions and 9230 deletions

View File

@@ -0,0 +1,89 @@
---
name: boo-building-ui
description: >
Builds new frontend UI (pages, screens, components, flows) to high-end design
standards: deliberate color strategy, typography, layout, motion, full
interaction-state coverage, accessibility, and an AI-slop self-check before
handoff. Use for "build a landing page," "add a settings screen," "create
this component," "make the frontend for X." Do NOT use to critique or grade
existing UI; use boo-critiquing-frontend. Do NOT use for OpenSpec
change-folder work; use boo-implementing-changes.
metadata:
version: "1.0"
---
# Building UI
## Size
Classify small/medium/large from surface count: small = one component or section, medium = a full screen or 2-4 related components, large = a multi-screen flow or a new design-system surface. Default: small. Announce with one-line justification. Accept `$size` override.
## Process
1. Read `references/design-guidance.md` for the canonical design rules (color, typography, layout, motion, interaction, absolute bans, AI slop test). Every build decision defers to it.
2. Recon the existing surface: run `ls frontend/src/components/ui/` (or the project's equivalent primitives path) and read the token/theme source (tailwind config, CSS custom properties, theme file). Only import primitives that exist; if the primitives directory is missing, stop and report.
3. Extending an existing surface? Extract its conventions first (spacing scale, type ramp, radius, motion idiom) and match them. New surface with no prior design? Write the one-sentence physical scene (who uses this, where, under what ambient light, in what mood) and pick a color strategy (restrained / committed / full palette / drenched) before writing any markup.
4. Build incrementally: structure and hierarchy first, then spacing and type, then color, then motion last. One component or section per pass.
5. Cover every interactive state: hover, focus-visible, active, disabled, loading, empty, error. A component without designed states is not done.
6. Accessibility pass: keyboard reachability and focus order, contrast >=4.5:1 body / >=3:1 large text, labels on inputs, `prefers-reduced-motion` alternative for every animation.
7. Self-check against the absolute bans and the two-altitude AI slop test in references/design-guidance.md. Anything matching a ban gets rebuilt with different structure, not tweaked in place.
8. Verify rendering when tooling exists (dev server plus browser tool or screenshot). If verification is not possible, say so explicitly in the report.
9. At medium+, dispatch `user-experience-designer` for a post-build audit and fix what it finds before handoff.
## What NOT to do
- Do not critique or grade existing UI; that is boo-critiquing-frontend's job.
- Do not implement OpenSpec change folders here; use boo-implementing-changes.
- Do not invent primitives or import components that do not exist in the project.
- Do not hardcode colors, spacing, or z-index values where tokens or scales exist.
- Do not ship a build that fails the AI slop test on a promise of polishing later.
## Gotchas
- **BooLab primitive rule**: run `ls frontend/src/components/ui/` and only import primitives that exist. If missing, stop and report.
- **States are scope, not polish**: empty, loading, and error states are part of the build, never follow-up work.
- **Slop test runs at two altitudes**: check first-order (theme guessable from category alone) and second-order (aesthetic guessable from category plus anti-references) per references/design-guidance.md.
<!-- standing-rules:pi:start -->
- **Subagent visibility**: when the Paseo MCP tools (`mcp__paseo__*`) are available, spawn each agent persona as an attached Paseo subagent with `create_agent` (`detached: false`, `notifyOnFinish: true`; for an opencode provider also pass `settings.modeId: "build"` and `settings.features.auto_accept: true`) so every persona appears in the operator's Paseo agent track. Resolve each persona's provider/model from the active preset's `agents` map in `~/.paseo/orchestration-preferences.json`; supervise on the finish notification (never poll) and read each result with `get_agent_activity`.
- **Subagent fallback**: when the Paseo MCP tools are not available, use the platform's native subagent dispatch. On a platform with no subagent dispatch at all (for example Pi), read each `agents/<name>.md` persona and apply its lens in sequential passes.
- **Subagent concurrency**: honor the active preset's `concurrency` value in `~/.paseo/orchestration-preferences.json`. When it is `1` (local heavy-weight presets, around 27b/35b or larger on a single llama-swap server), dispatch subagents STRICTLY ONE AT A TIME: launch one, wait for its finish notification and read its result, then launch the next. This overrides any parallel fan-out. Absent or higher `concurrency` means parallel fan-out is fine.
<!-- standing-rules:pi:end -->
<!-- standing-rules:core:start -->
- **No commit**: never commit, push, or stage changes; never `git add -A`. Prove any edits with `git diff --stat`.
- **No em dashes**: never use em dashes (U+2014) in output or files you write.
<!-- standing-rules:core:end -->
## Output format
```
# UI Build: <target>
## What was built
<components/screens with file paths>
## Design decisions
- Scene sentence: <one sentence> (new surfaces only)
- Color strategy: <restrained | committed | full palette | drenched>
- <other load-bearing choices, one line each>
## State coverage
| Component | hover | focus | disabled | loading | empty | error |
|-----------|-------|-------|----------|---------|-------|-------|
## Verification
<how rendering was verified, or why it could not be>
## Slop self-check
<bans checked and result; both slop-test altitudes>
## Claims I did not verify
- <anything assumed or not checked>
```
## Failure modes
- **No frontend toolchain**: the repo has no frontend source or build setup. Report and stop; never scaffold a framework unasked.
- **Primitives directory missing**: report the actual path checked and stop.
- **Design guidance cannot be loaded**: references/design-guidance.md is missing. Report and stop.
- **Rendering cannot be verified**: no dev server or browser tooling available. Deliver the build and flag verification as not done.

View File

@@ -0,0 +1,77 @@
# Design Guidance
Ported from forks/impeccable/skill/SKILL.src.md. Substantive design rules preserved verbatim; provider-specific tags and placeholder syntax removed.
## General rules
### Color
- **Verify contrast.** Body text must hit >=4.5:1 against its background; large text (>=18px or bold >=14px) needs >=3:1. Placeholder text needs the same 4.5:1, not the muted-gray default. The most common failure: muted gray body text on a tinted near-white. If the contrast is even close, bump the body color toward the ink end of the ramp; light gray "for elegance" is the single biggest reason AI designs feel hard to read.
- Gray text on a colored background looks washed out. Use a darker shade of the background's own hue, or a transparency of the text color.
### Typography
- Cap body line length at 65-75ch.
- Don't pair fonts that are similar but not identical (two geometric sans-serifs, two humanist sans-serifs). Pair on a contrast axis (serif + sans, geometric + humanist) or use one family in multiple weights.
- Hero / display heading ceiling: clamp() max <= 6rem (~96px). Above that the page is shouting, not designing.
- Display heading letter-spacing floor: >= -0.04em. Anything tighter and letters touch; cramped, not "designed".
- Use `text-wrap: balance` on h1-h3 for even line lengths; `text-wrap: pretty` on long prose to reduce orphans.
### Layout
- Vary spacing for rhythm.
- Cards are the lazy answer. Use them only when they're truly the best affordance. Nested cards are always wrong.
- Flexbox for 1D, Grid for 2D. Don't default to Grid when `flex-wrap` would be simpler.
- For responsive grids without breakpoints: `repeat(auto-fit, minmax(280px, 1fr))`.
- Build a semantic z-index scale (dropdown, sticky, modal-backdrop, modal, toast, tooltip). Never arbitrary values like 999 or 9999.
### Motion
- Motion should be intentional, and not be an afterthought. Consider it as part of the build.
- Don't animate CSS layout properties unless truly needed.
- Ease out with exponential curves (ease-out-quart / quint / expo). No bounce, no elastic.
- Use libraries for more advanced motion needs (e.g. motion, GSAP, anime.js, Lenis etc).
- Reduced motion is not optional. Every animation needs a `@media (prefers-reduced-motion: reduce)` alternative: typically a crossfade or instant transition.
- Staggering the items within one list is legitimate. The tell is the uniform reflex (one identical entrance applied to every section), not motion itself; each reveal should fit what it reveals. Suppressing the reflex is never a reason to ship a page with no motion at all.
- Reveal animations must enhance an already-visible default. Don't gate content visibility on a class-triggered transition; transitions pause on hidden tabs and headless renderers, so the reveal never fires and the section ships blank.
- Premium motion materials are not just transform/opacity. Blur, backdrop-filter, clip-path, mask, and shadow/glow are part of the palette when they materially improve the effect and stay smooth.
### Interaction
- Dropdowns rendered with `position: absolute` inside an `overflow: hidden` or `overflow: auto` container will be clipped. Use the native `<dialog>` / popover API, `position: fixed`, or a portal to escape the stacking context.
## New projects only (when no prior work exists)
### Color & Theme
- Use OKLCH.
- **The cream / sand / beige body bg is the saturated AI default of 2026.** The whole warm-neutral band (OKLCH L 0.84-0.97, C < 0.06, hue 40-100) reads as cream/sand/paper/parchment regardless of what you call it. Token names like `--paper`, `--cream`, `--sand`, `--bone`, `--flour`, `--linen`, `--parchment`, `--wheat`, `--biscuit`, `--ivory` are tells in themselves. If the brief is "warm, traditional, family-coastal-Italian" or "magazine-warm" or "editorial-restraint", DO NOT translate that into a near-white warm-tinted bg; that's the AI move. Pick: (a) a saturated brand color as the body (terracotta, oxblood, deep ochre, near-black), (b) a true off-white at chroma 0 (or chroma toward the brand's own hue, not toward warmth-by-default), or (c) a darker mid-tone tinted neutral that's clearly the brand's own. "Warmth" in the brand is carried by accent + typography + imagery, not by body bg.
- Tinted neutrals: add 0.005-0.015 chroma toward the brand's hue. Don't default-tint toward warm or cool "because the brand feels that way"; that's the cross-project monoculture move.
- When picking a theme: Dark vs. light is never a default. Not dark "because tools look cool dark." Not light "to be safe." Before choosing, write one sentence of physical scene: who uses this, where, under what ambient light, in what mood. If the sentence doesn't force the answer, it's not concrete enough. Add detail until it does.
- Pick a **color strategy** before picking colors. Four steps on the commitment axis:
- **Restrained**: tinted neutrals + one accent <=10%. Product default; brand minimalism.
- **Committed**: one saturated color carries 30-60% of the surface. Brand default for identity-driven pages.
- **Full palette**: 3-4 named roles, each used deliberately. Brand campaigns; product data viz.
- **Drenched**: the surface IS the color. Brand heroes, campaign pages.
## Absolute bans
Match-and-refuse. If you're about to write any of these, rewrite the element with different structure.
- **Side-stripe borders.** `border-left` or `border-right` greater than 1px as a colored accent on cards, list items, callouts, or alerts. Never intentional. Rewrite with full borders, background tints, leading numbers/icons, or nothing.
- **Gradient text.** `background-clip: text` combined with a gradient background. Decorative, never meaningful. Use a single solid color. Emphasis via weight or size.
- **Glassmorphism as default.** Blurs and glass cards used decoratively. Rare and purposeful, or nothing.
- **The hero-metric template.** Big number, small label, supporting stats, gradient accent. SaaS cliche.
- **Identical card grids.** Same-sized cards with icon + heading + text, repeated endlessly.
- **Tiny uppercase tracked eyebrow above every section.** The 2023-era kicker (small all-caps text with wide tracking, "ABOUT" "PROCESS" "PRICING" above each heading) is now the saturated AI scaffold. One named kicker as a deliberate brand system is voice; an eyebrow on every section is AI grammar. Choose a different cadence.
- **Numbered section markers as default scaffolding (01 / 02 / 03).** Numbers earn their place when the section actually IS a sequence (a real 3-step process, an ordered flow, a typed timeline) and the order carries information the reader needs. One deliberate numbered sequence on one page is voice; numbered eyebrows on every section across the site is AI grammar.
- **Text that overflows its container.** Long heading words plus large clamp scales plus narrow grids cause headline overflow on tablet/mobile. Test the heading copy at every breakpoint; if it overflows, reduce the clamp max or rewrite the copy.
## The AI slop test
If someone could look at this interface and say "AI made that" without doubt, it's failed. Cross-register failures are the absolute bans above. Register-specific failures live in each reference.
**Category-reflex check.** Run at two altitudes; the second one catches what the first one misses.
- **First-order:** if someone could guess the theme + palette from the category alone, it's the first training-data reflex. Rework the scene sentence and color strategy until the answer isn't obvious from the domain.
- **Second-order:** if someone could guess the aesthetic family from category-plus-anti-references ("AI workflow tool that's not SaaS-cream, editorial-typographic", "fintech that's not navy-and-gold, terminal-native dark mode"), it's the trap one tier deeper. The first reflex was avoided; the second wasn't. Rework until both answers are not obvious.